From ed81a111d1999a6b62f2cfea21c241e557b800da Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Thu, 19 Jun 2025 15:56:32 +0000 Subject: wasm: rm static mut --- library/std/src/sys/alloc/wasm.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/library/std/src/sys/alloc/wasm.rs b/library/std/src/sys/alloc/wasm.rs index c8fab992a88..48e2fdd4ecc 100644 --- a/library/std/src/sys/alloc/wasm.rs +++ b/library/std/src/sys/alloc/wasm.rs @@ -16,12 +16,15 @@ //! The crate itself provides a global allocator which on wasm has no //! synchronization as there are no threads! -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#![allow(static_mut_refs)] +use core::cell::SyncUnsafeCell; use crate::alloc::{GlobalAlloc, Layout, System}; -static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new(); +struct SyncDlmalloc(dlmalloc::Dlmalloc); +unsafe impl Sync for SyncDlmalloc {} + +static DLMALLOC: SyncUnsafeCell = + SyncUnsafeCell::new(SyncDlmalloc(dlmalloc::Dlmalloc::new())); #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { @@ -30,7 +33,7 @@ unsafe impl GlobalAlloc for System { // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access. // Calling malloc() is safe because preconditions on this function match the trait method preconditions. let _lock = lock::lock(); - unsafe { DLMALLOC.malloc(layout.size(), layout.align()) } + unsafe { (*DLMALLOC.get()).0.malloc(layout.size(), layout.align()) } } #[inline] @@ -38,7 +41,7 @@ unsafe impl GlobalAlloc for System { // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access. // Calling calloc() is safe because preconditions on this function match the trait method preconditions. let _lock = lock::lock(); - unsafe { DLMALLOC.calloc(layout.size(), layout.align()) } + unsafe { (*DLMALLOC.get()).0.calloc(layout.size(), layout.align()) } } #[inline] @@ -46,7 +49,7 @@ unsafe impl GlobalAlloc for System { // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access. // Calling free() is safe because preconditions on this function match the trait method preconditions. let _lock = lock::lock(); - unsafe { DLMALLOC.free(ptr, layout.size(), layout.align()) } + unsafe { (*DLMALLOC.get()).0.free(ptr, layout.size(), layout.align()) } } #[inline] @@ -54,7 +57,7 @@ unsafe impl GlobalAlloc for System { // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access. // Calling realloc() is safe because preconditions on this function match the trait method preconditions. let _lock = lock::lock(); - unsafe { DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) } + unsafe { (*DLMALLOC.get()).0.realloc(ptr, layout.size(), layout.align(), new_size) } } } -- cgit 1.4.1-3-g733a5 From 3ddd2ef8c518efe10c811a229f056e96864d83c1 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 2 Jul 2025 13:15:07 -0700 Subject: Mention that casting to *const () is a way to roundtrip with from_raw_parts --- library/core/src/ptr/metadata.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 0deac3621e8..dc3ec3fd199 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -106,6 +106,9 @@ pub const fn metadata(ptr: *const T) -> ::Metadat /// For slices, see the documentation of [`slice::from_raw_parts`] for safety requirements. /// For trait objects, the metadata must come from a pointer to the same underlying erased type. /// +/// If you are attempting to deconstruct a DST in a generic context to be reconstructed later, +/// a thin pointer can always be obtained by casting `*const T` to `*const ()`. +/// /// [`slice::from_raw_parts`]: crate::slice::from_raw_parts #[unstable(feature = "ptr_metadata", issue = "81513")] #[inline] -- cgit 1.4.1-3-g733a5 From 905342525f88b757a4f7026b2b51a21621999fd1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 9 Jul 2025 21:27:27 -0400 Subject: Add a mailmap entry for gnzlbg The submodule->subtree changes add a lot of commits with the GitHub email. --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 90533e81b39..68abb9003a0 100644 --- a/.mailmap +++ b/.mailmap @@ -255,6 +255,7 @@ Guillaume Gomez Guillaume Gomez ggomez Guillaume Gomez Guillaume Gomez Guillaume Gomez Guillaume Gomez +gnzlbg hamidreza kalbasi Hanna Kruppe Heather -- cgit 1.4.1-3-g733a5 From 613080b5f1d58a2496d9f8dc8c314d5432fe3d6f Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Thu, 31 Jul 2025 23:46:04 -0400 Subject: add Option::reduce --- library/core/src/option.rs | 36 ++++++++++++++++++++++++++++++++++++ library/coretests/tests/lib.rs | 1 + 2 files changed, 37 insertions(+) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 0e481519f76..f3ddc05bc1a 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1961,6 +1961,42 @@ impl Option { _ => None, } } + + /// Reduces two options into one, using the provided function if both are `Some`. + /// + /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some(f(s, o))`. + /// Otherwise, if only one of `self` and `other` is `Some`, that one is returned. + /// If both `self` and `other` are `None`, `None` is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(option_reduce)] + /// + /// let s12 = Some(12); + /// let s17 = Some(17); + /// let n = None; + /// let f = |a, b| a + b; + /// + /// assert_eq!(s12.reduce(s17, f), Some(29)); + /// assert_eq!(s12.reduce(n, f), Some(12)); + /// assert_eq!(n.reduce(s17, f), Some(17)); + /// assert_eq!(n.reduce(n, f), None); + /// ``` + #[unstable(feature = "option_reduce", issue = "144273")] + pub fn reduce(self, other: Option, f: F) -> Option + where + T: Into, + U: Into, + F: FnOnce(T, U) -> R, + { + match (self, other) { + (Some(a), Some(b)) => Some(f(a, b)), + (Some(a), _) => Some(a.into()), + (_, Some(b)) => Some(b.into()), + _ => None, + } + } } impl Option<(T, U)> { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 4cfac9ecc2a..3f817ab128b 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -77,6 +77,7 @@ #![feature(never_type)] #![feature(next_index)] #![feature(numfmt)] +#![feature(option_reduce)] #![feature(pattern)] #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] -- cgit 1.4.1-3-g733a5 From decdb950bf016391145b582cd0756d3e67481ad6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 7 Aug 2025 01:05:01 -0500 Subject: symcheck: Store the section name in `SymInfo` if available Currently `SymInfo` stores a `Section`, which is just an index: SymInfo { section: Section( SectionIndex( 539, ), ), ... }, Look up and store the section name instead if possible, with a fallback to the `Section` debug printing. This makes output more clear and will allow us to filter by section name. --- .../crates/symbol-check/src/main.rs | 30 ++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/crates/symbol-check/src/main.rs b/library/compiler-builtins/crates/symbol-check/src/main.rs index 1312a717970..beb568a0f84 100644 --- a/library/compiler-builtins/crates/symbol-check/src/main.rs +++ b/library/compiler-builtins/crates/symbol-check/src/main.rs @@ -9,7 +9,7 @@ use std::process::{Command, Stdio}; use object::read::archive::{ArchiveFile, ArchiveMember}; use object::{ - File as ObjFile, Object, ObjectSymbol, Symbol, SymbolKind, SymbolScope, SymbolSection, + File as ObjFile, Object, ObjectSection, ObjectSymbol, Symbol, SymbolKind, SymbolScope, }; use serde_json::Value; @@ -154,7 +154,7 @@ struct SymInfo { name: String, kind: SymbolKind, scope: SymbolScope, - section: SymbolSection, + section: String, is_undefined: bool, is_global: bool, is_local: bool, @@ -165,12 +165,22 @@ struct SymInfo { } impl SymInfo { - fn new(sym: &Symbol, member: &ArchiveMember) -> Self { + fn new(sym: &Symbol, obj: &ObjFile, member: &ArchiveMember) -> Self { + // Include the section name if possible. Fall back to the `Section` debug impl if not. + let section = sym.section(); + let section_name = sym + .section() + .index() + .and_then(|idx| obj.section_by_index(idx).ok()) + .and_then(|sec| sec.name().ok()) + .map(ToString::to_string) + .unwrap_or_else(|| format!("{section:?}")); + Self { name: sym.name().expect("missing name").to_owned(), kind: sym.kind(), scope: sym.scope(), - section: sym.section(), + section: section_name, is_undefined: sym.is_undefined(), is_global: sym.is_global(), is_local: sym.is_local(), @@ -192,13 +202,13 @@ fn verify_no_duplicates(archive: &Archive) { let mut dups = Vec::new(); let mut found_any = false; - archive.for_each_symbol(|symbol, member| { + archive.for_each_symbol(|symbol, obj, member| { // Only check defined globals if !symbol.is_global() || symbol.is_undefined() { return; } - let sym = SymInfo::new(&symbol, member); + let sym = SymInfo::new(&symbol, obj, member); // x86-32 includes multiple copies of thunk symbols if sym.name.starts_with("__x86.get_pc_thunk") { @@ -244,7 +254,7 @@ fn verify_core_symbols(archive: &Archive) { let mut undefined = Vec::new(); let mut has_symbols = false; - archive.for_each_symbol(|symbol, member| { + archive.for_each_symbol(|symbol, obj, member| { has_symbols = true; // Find only symbols from `core` @@ -252,7 +262,7 @@ fn verify_core_symbols(archive: &Archive) { return; } - let sym = SymInfo::new(&symbol, member); + let sym = SymInfo::new(&symbol, obj, member); if sym.is_undefined { undefined.push(sym); } else { @@ -304,9 +314,9 @@ impl Archive { } /// For a given archive, do something with each symbol. - fn for_each_symbol(&self, mut f: impl FnMut(Symbol, &ArchiveMember)) { + fn for_each_symbol(&self, mut f: impl FnMut(Symbol, &ObjFile, &ArchiveMember)) { self.for_each_object(|obj, member| { - obj.symbols().for_each(|sym| f(sym, member)); + obj.symbols().for_each(|sym| f(sym, &obj, member)); }); } } -- cgit 1.4.1-3-g733a5 From ab0def2739744ae31d5738263acd0cc0e00e1a16 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 7 Aug 2025 03:27:16 -0500 Subject: symcheck: Ignore symbols in `.debug_gdb_scripts` Since [1], our object files may now contain a GDB script section. These symbols wind up with multiple instances in the archive but are weak, so we can safely ignore them in our duplicates check. This resolves the current CI failures. [1]: https://github.com/rust-lang/rust/pull/143679 --- library/compiler-builtins/crates/symbol-check/src/main.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/crates/symbol-check/src/main.rs b/library/compiler-builtins/crates/symbol-check/src/main.rs index beb568a0f84..129c959f23a 100644 --- a/library/compiler-builtins/crates/symbol-check/src/main.rs +++ b/library/compiler-builtins/crates/symbol-check/src/main.rs @@ -215,6 +215,11 @@ fn verify_no_duplicates(archive: &Archive) { return; } + // GDB pretty printing symbols may show up more than once but are weak. + if sym.section == ".debug_gdb_scripts" && sym.is_weak { + return; + } + // Windows has symbols for literal numeric constants, string literals, and MinGW pseudo- // relocations. These are allowed to have repeated definitions. let win_allowed_dup_pfx = ["__real@", "__xmm@", "??_C@_", ".refptr"]; -- cgit 1.4.1-3-g733a5 From 36ec648e0a951425a7dcee0c742a60df19a37939 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 7 Aug 2025 03:42:02 -0500 Subject: Remove instances of `allow(improper_ctypes)` i128/u128 haven't flagged `improper_ctypes` for a while, and this just made it to stable [1]. Remove the `allow`s as they are no longer needed. [1]: https://blog.rust-lang.org/2025/08/07/Rust-1.89.0/#i128-and-u128-in-extern-c-functions --- library/compiler-builtins/builtins-test/benches/float_conv.rs | 1 - library/compiler-builtins/compiler-builtins/src/lib.rs | 4 ---- 2 files changed, 5 deletions(-) diff --git a/library/compiler-builtins/builtins-test/benches/float_conv.rs b/library/compiler-builtins/builtins-test/benches/float_conv.rs index e0f488eb685..40c13d270ac 100644 --- a/library/compiler-builtins/builtins-test/benches/float_conv.rs +++ b/library/compiler-builtins/builtins-test/benches/float_conv.rs @@ -1,4 +1,3 @@ -#![allow(improper_ctypes)] #![cfg_attr(f128_enabled, feature(f128))] use builtins_test::float_bench; diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index ca75f44e02a..b111dc0bd18 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -18,10 +18,6 @@ #![no_std] #![allow(unused_features)] #![allow(internal_features)] -// We use `u128` in a whole bunch of places which we currently agree with the -// compiler on ABIs and such, so we should be "good enough" for now and changes -// to the `u128` ABI will be reflected here. -#![allow(improper_ctypes, improper_ctypes_definitions)] // `mem::swap` cannot be used because it may generate references to memcpy in unoptimized code. #![allow(clippy::manual_swap)] // Support compiling on both stage0 and stage1 which may differ in supported stable features. -- cgit 1.4.1-3-g733a5 From 9a81b2a6a0932547c8e949a34d61cf789dbee675 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 7 Aug 2025 15:45:52 -0500 Subject: Start runnning tests for aarch64-pc-windows-msvc This target is currently build-only. Switch to the windows-11-arm runner, which allows us to start running tests. --- library/compiler-builtins/.github/workflows/main.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index c54df2e90b7..3afadbfe894 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -51,8 +51,7 @@ jobs: - target: aarch64-unknown-linux-gnu os: ubuntu-24.04-arm - target: aarch64-pc-windows-msvc - os: windows-2025 - build_only: 1 + os: windows-11-arm - target: arm-unknown-linux-gnueabi os: ubuntu-24.04 - target: arm-unknown-linux-gnueabihf -- cgit 1.4.1-3-g733a5 From d47b5e4ab63df3774727e6dec542dade6ef22d9a Mon Sep 17 00:00:00 2001 From: minxuanz Date: Fri, 8 Aug 2025 11:19:04 +0800 Subject: Fix wrong cache line size of riscv64 --- library/std/src/sync/mpmc/utils.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/library/std/src/sync/mpmc/utils.rs b/library/std/src/sync/mpmc/utils.rs index 0cbc61160f7..e3bcb149f64 100644 --- a/library/std/src/sync/mpmc/utils.rs +++ b/library/std/src/sync/mpmc/utils.rs @@ -23,14 +23,13 @@ use crate::ops::{Deref, DerefMut}; any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64",), repr(align(128)) )] -// arm, mips, mips64, and riscv64 have 32-byte cache line size. +// arm, mips and mips64 have 32-byte cache line size. // // Sources: // - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_arm.go#L7 // - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mips.go#L7 // - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mipsle.go#L7 // - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mips64x.go#L9 -// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_riscv64.go#L7 #[cfg_attr( any( target_arch = "arm", @@ -38,7 +37,6 @@ use crate::ops::{Deref, DerefMut}; target_arch = "mips32r6", target_arch = "mips64", target_arch = "mips64r6", - target_arch = "riscv64", ), repr(align(32)) )] @@ -47,11 +45,12 @@ use crate::ops::{Deref, DerefMut}; // Sources: // - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_s390x.go#L7 #[cfg_attr(target_arch = "s390x", repr(align(256)))] -// x86 and wasm have 64-byte cache line size. +// x86, wasm and riscv have 64-byte cache line size. // // Sources: // - https://github.com/golang/go/blob/dda2991c2ea0c5914714469c4defc2562a907230/src/internal/cpu/cpu_x86.go#L9 // - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_wasm.go#L7 +// - https://github.com/golang/go/blob/5e31f78c8a4ed1b872ddc194f0cd1ae931b37d7e/src/internal/cpu/cpu_riscv64.go#L7 // // All others are assumed to have 64-byte cache line size. #[cfg_attr( @@ -64,7 +63,6 @@ use crate::ops::{Deref, DerefMut}; target_arch = "mips32r6", target_arch = "mips64", target_arch = "mips64r6", - target_arch = "riscv64", target_arch = "s390x", )), repr(align(64)) -- cgit 1.4.1-3-g733a5 From 3fb62b990c0bdb46412944862a28ad9b92a73b82 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Sat, 9 Aug 2025 01:53:44 +0000 Subject: Prepare for merging from rust-lang/rust This updates the rust-version file to ffb9d94dcf4ade0d534842be3672d5e9f47e1333. --- library/compiler-builtins/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version index a4db05a8796..3928504c857 100644 --- a/library/compiler-builtins/rust-version +++ b/library/compiler-builtins/rust-version @@ -1 +1 @@ -82310651b93a594a3fd69015e1562186a080d94c +ffb9d94dcf4ade0d534842be3672d5e9f47e1333 -- cgit 1.4.1-3-g733a5 From 531d5aa593592b16f379f9d6af5d9ae666a163b3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 9 Aug 2025 15:42:48 -0500 Subject: symcheck: Skip `__ymm@` symbols on Windows Like `__real@`, and `__xmm@`, Windows can emit duplicate `__ymm@` symbols for constants. --- library/compiler-builtins/crates/symbol-check/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/crates/symbol-check/src/main.rs b/library/compiler-builtins/crates/symbol-check/src/main.rs index 129c959f23a..4e94552331a 100644 --- a/library/compiler-builtins/crates/symbol-check/src/main.rs +++ b/library/compiler-builtins/crates/symbol-check/src/main.rs @@ -222,7 +222,7 @@ fn verify_no_duplicates(archive: &Archive) { // Windows has symbols for literal numeric constants, string literals, and MinGW pseudo- // relocations. These are allowed to have repeated definitions. - let win_allowed_dup_pfx = ["__real@", "__xmm@", "??_C@_", ".refptr"]; + let win_allowed_dup_pfx = ["__real@", "__xmm@", "__ymm@", "??_C@_", ".refptr"]; if win_allowed_dup_pfx .iter() .any(|pfx| sym.name.starts_with(pfx)) -- cgit 1.4.1-3-g733a5 From ba5def8a85bc983460f65f889510accbc7b743ae Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 9 Aug 2025 06:29:01 -0500 Subject: Add __addhf3, __subhf3, __mulhf3, __{eq,ge,gt,le,lt,ne,unord}hf2 LLVM does not currently emit these, but it is being discussed as an option on platforms where `f32` is not hardware supported. Glibc/libgcc also has the comparison functions [1] already. The generic implementations for addition, subtraction, and multiplication work for f16 without any complications, as do comparisons, so add them here. [1]: https://sourceware.org/git/?p=glibc.git;a=commit;h=6ec6c77867af4ddfec7323e0ac6ede89effca852 --- .../builtins-test/tests/addsub.rs | 24 ++++++++--------- .../compiler-builtins/builtins-test/tests/cmp.rs | 21 +++++++++++++++ .../compiler-builtins/builtins-test/tests/mul.rs | 8 +++++- .../compiler-builtins/src/float/add.rs | 5 ++++ .../compiler-builtins/src/float/cmp.rs | 31 ++++++++++++++++++++++ .../compiler-builtins/src/float/mul.rs | 5 ++++ .../compiler-builtins/src/float/sub.rs | 5 ++++ 7 files changed, 85 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/builtins-test/tests/addsub.rs b/library/compiler-builtins/builtins-test/tests/addsub.rs index abe7dde645e..f3334bd0e2d 100644 --- a/library/compiler-builtins/builtins-test/tests/addsub.rs +++ b/library/compiler-builtins/builtins-test/tests/addsub.rs @@ -1,4 +1,5 @@ #![allow(unused_macros)] +#![cfg_attr(f16_enabled, feature(f16))] #![cfg_attr(f128_enabled, feature(f128))] use builtins_test::*; @@ -115,28 +116,25 @@ macro_rules! float_sum { mod float_addsub { use super::*; + #[cfg(f16_enabled)] + float_sum! { + f16, __addhf3, __subhf3, Half, all(); + } + float_sum! { f32, __addsf3, __subsf3, Single, all(); f64, __adddf3, __subdf3, Double, all(); } -} - -#[cfg(f128_enabled)] -#[cfg(not(x86_no_sse))] -#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] -mod float_addsub_f128 { - use super::*; + #[cfg(f128_enabled)] + #[cfg(not(x86_no_sse))] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] float_sum! { f128, __addtf3, __subtf3, Quad, not(feature = "no-sys-f128"); } -} - -#[cfg(f128_enabled)] -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -mod float_addsub_f128_ppc { - use super::*; + #[cfg(f128_enabled)] + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] float_sum! { f128, __addkf3, __subkf3, Quad, not(feature = "no-sys-f128"); } diff --git a/library/compiler-builtins/builtins-test/tests/cmp.rs b/library/compiler-builtins/builtins-test/tests/cmp.rs index a904dc5f7de..4b01b6ca1c7 100644 --- a/library/compiler-builtins/builtins-test/tests/cmp.rs +++ b/library/compiler-builtins/builtins-test/tests/cmp.rs @@ -1,5 +1,6 @@ #![allow(unused_macros)] #![allow(unreachable_code)] +#![cfg_attr(f16_enabled, feature(f16))] #![cfg_attr(f128_enabled, feature(f128))] use builtins_test::*; @@ -51,6 +52,26 @@ mod float_comparisons { }; } + #[test] + #[cfg(f16_enabled)] + fn cmp_f16() { + use compiler_builtins::float::cmp::{ + __eqhf2, __gehf2, __gthf2, __lehf2, __lthf2, __nehf2, __unordhf2, + }; + + fuzz_float_2(N, |x: f16, y: f16| { + assert_eq!(__unordhf2(x, y) != 0, x.is_nan() || y.is_nan()); + cmp!(f16, x, y, Half, all(), + 1, __lthf2; + 1, __lehf2; + 1, __eqhf2; + -1, __gehf2; + -1, __gthf2; + 1, __nehf2; + ); + }); + } + #[test] fn cmp_f32() { use compiler_builtins::float::cmp::{ diff --git a/library/compiler-builtins/builtins-test/tests/mul.rs b/library/compiler-builtins/builtins-test/tests/mul.rs index 3072b45dca0..bbf1157db42 100644 --- a/library/compiler-builtins/builtins-test/tests/mul.rs +++ b/library/compiler-builtins/builtins-test/tests/mul.rs @@ -1,5 +1,6 @@ -#![allow(unused_macros)] +#![cfg_attr(f16_enabled, feature(f16))] #![cfg_attr(f128_enabled, feature(f128))] +#![allow(unused_macros)] use builtins_test::*; @@ -117,6 +118,11 @@ macro_rules! float_mul { mod float_mul { use super::*; + #[cfg(f16_enabled)] + float_mul! { + f16, __mulhf3, Half, all(); + } + // FIXME(#616): Stop ignoring arches that don't have native support once fix for builtins is in // nightly. float_mul! { diff --git a/library/compiler-builtins/compiler-builtins/src/float/add.rs b/library/compiler-builtins/compiler-builtins/src/float/add.rs index 0cc362f705b..8dbfb0e1020 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/add.rs @@ -191,6 +191,11 @@ where } intrinsics! { + #[cfg(f16_enabled)] + pub extern "C" fn __addhf3(a: f16, b: f16) -> f16 { + add(a, b) + } + #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_fadd] pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 { diff --git a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs index f1e54dc1c83..8ab39c2b591 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs @@ -115,6 +115,37 @@ fn unord(a: F, b: F) -> bool { a_abs > inf_rep || b_abs > inf_rep } +#[cfg(f16_enabled)] +intrinsics! { + pub extern "C" fn __lehf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { + cmp(a, b).to_le_abi() + } + + pub extern "C" fn __gehf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { + cmp(a, b).to_ge_abi() + } + + pub extern "C" fn __unordhf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { + unord(a, b) as crate::float::cmp::CmpResult + } + + pub extern "C" fn __eqhf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { + cmp(a, b).to_le_abi() + } + + pub extern "C" fn __lthf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { + cmp(a, b).to_le_abi() + } + + pub extern "C" fn __nehf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { + cmp(a, b).to_le_abi() + } + + pub extern "C" fn __gthf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { + cmp(a, b).to_ge_abi() + } +} + intrinsics! { pub extern "C" fn __lesf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() diff --git a/library/compiler-builtins/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/compiler-builtins/src/float/mul.rs index dbed3095cda..49a2414eb5c 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mul.rs @@ -180,6 +180,11 @@ where } intrinsics! { + #[cfg(f16_enabled)] + pub extern "C" fn __mulhf3(a: f16, b: f16) -> f16 { + mul(a, b) + } + #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_fmul] pub extern "C" fn __mulsf3(a: f32, b: f32) -> f32 { diff --git a/library/compiler-builtins/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/compiler-builtins/src/float/sub.rs index a0fd9dff97f..48ef33b0b82 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/sub.rs @@ -1,6 +1,11 @@ use crate::float::Float; intrinsics! { + #[cfg(f16_enabled)] + pub extern "C" fn __subhf3(a: f16, b: f16) -> f16 { + crate::float::add::__addhf3(a, f16::from_bits(b.to_bits() ^ f16::SIGN_MASK)) + } + #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { crate::float::add::__addsf3(a, f32::from_bits(b.to_bits() ^ f32::SIGN_MASK)) -- cgit 1.4.1-3-g733a5 From 12b57942d646d27e8d0a615ba4b8a0dea6cf3b9f Mon Sep 17 00:00:00 2001 From: Zachary S Date: Tue, 12 Aug 2025 17:42:43 -0500 Subject: Remove TmpLayout in layout_of_enum --- compiler/rustc_abi/src/layout.rs | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index c2405553756..5004d0c8022 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -594,23 +594,13 @@ impl LayoutCalculator { discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool), discriminants: impl Iterator, ) -> LayoutCalculatorResult { - // Until we've decided whether to use the tagged or - // niche filling LayoutData, we don't want to intern the - // variant layouts, so we can't store them in the - // overall LayoutData. Store the overall LayoutData - // and the variant LayoutDatas here until then. - struct TmpLayout { - layout: LayoutData, - variants: IndexVec>, - } - let dl = self.cx.data_layout(); // bail if the enum has an incoherent repr that cannot be computed if repr.packed() { return Err(LayoutCalculatorError::ReprConflict); } - let calculate_niche_filling_layout = || -> Option> { + let calculate_niche_filling_layout = || -> Option> { if repr.inhibit_enum_layout_opt() { return None; } @@ -746,7 +736,7 @@ impl LayoutCalculator { niche_start, }, tag_field: FieldIdx::new(0), - variants: IndexVec::new(), + variants: variant_layouts, }, fields: FieldsShape::Arbitrary { offsets: [niche_offset].into(), @@ -762,7 +752,7 @@ impl LayoutCalculator { randomization_seed: combined_seed, }; - Some(TmpLayout { layout, variants: variant_layouts }) + Some(layout) }; let niche_filling_layout = calculate_niche_filling_layout(); @@ -1093,7 +1083,7 @@ impl LayoutCalculator { tag, tag_encoding: TagEncoding::Direct, tag_field: FieldIdx::new(0), - variants: IndexVec::new(), + variants: layout_variants, }, fields: FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), @@ -1109,18 +1099,16 @@ impl LayoutCalculator { randomization_seed: combined_seed, }; - let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants }; - - let mut best_layout = match (tagged_layout, niche_filling_layout) { + let best_layout = match (tagged_layout, niche_filling_layout) { (tl, Some(nl)) => { // Pick the smaller layout; otherwise, // pick the layout with the larger niche; otherwise, // pick tagged as it has simpler codegen. use cmp::Ordering::*; - let niche_size = |tmp_l: &TmpLayout| { - tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl)) + let niche_size = |l: &LayoutData| { + l.largest_niche.map_or(0, |n| n.available(dl)) }; - match (tl.layout.size.cmp(&nl.layout.size), niche_size(&tl).cmp(&niche_size(&nl))) { + match (tl.size.cmp(&nl.size), niche_size(&tl).cmp(&niche_size(&nl))) { (Greater, _) => nl, (Equal, Less) => nl, _ => tl, @@ -1129,16 +1117,7 @@ impl LayoutCalculator { (tl, None) => tl, }; - // Now we can intern the variant layouts and store them in the enum layout. - best_layout.layout.variants = match best_layout.layout.variants { - Variants::Multiple { tag, tag_encoding, tag_field, .. } => { - Variants::Multiple { tag, tag_encoding, tag_field, variants: best_layout.variants } - } - Variants::Single { .. } | Variants::Empty => { - panic!("encountered a single-variant or empty enum during multi-variant layout") - } - }; - Ok(best_layout.layout) + Ok(best_layout) } fn univariant_biased< -- cgit 1.4.1-3-g733a5 From b951b5dca116803b89380aae55ce9053a4674f31 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Fri, 15 Aug 2025 16:56:11 +0000 Subject: stabilize strict provenance atomic ptr --- library/core/src/sync/atomic.rs | 21 +++++++-------------- library/coretests/tests/lib.rs | 1 - library/std/src/lib.rs | 1 - src/tools/miri/tests/pass/atomic.rs | 1 - tests/codegen-llvm/atomicptr.rs | 1 - 5 files changed, 7 insertions(+), 18 deletions(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 44a6895f90a..7bd68bcd0bc 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -2199,7 +2199,6 @@ impl AtomicPtr { /// # Examples /// /// ``` - /// #![feature(strict_provenance_atomic_ptr)] /// use core::sync::atomic::{AtomicPtr, Ordering}; /// /// let atom = AtomicPtr::::new(core::ptr::null_mut()); @@ -2209,7 +2208,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T { self.fetch_byte_add(val.wrapping_mul(size_of::()), order) @@ -2240,7 +2239,6 @@ impl AtomicPtr { /// # Examples /// /// ``` - /// #![feature(strict_provenance_atomic_ptr)] /// use core::sync::atomic::{AtomicPtr, Ordering}; /// /// let array = [1i32, 2i32]; @@ -2254,7 +2252,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T { self.fetch_byte_sub(val.wrapping_mul(size_of::()), order) @@ -2279,7 +2277,6 @@ impl AtomicPtr { /// # Examples /// /// ``` - /// #![feature(strict_provenance_atomic_ptr)] /// use core::sync::atomic::{AtomicPtr, Ordering}; /// /// let atom = AtomicPtr::::new(core::ptr::null_mut()); @@ -2289,7 +2286,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. @@ -2315,7 +2312,6 @@ impl AtomicPtr { /// # Examples /// /// ``` - /// #![feature(strict_provenance_atomic_ptr)] /// use core::sync::atomic::{AtomicPtr, Ordering}; /// /// let mut arr = [0i64, 1]; @@ -2325,7 +2321,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. @@ -2361,7 +2357,6 @@ impl AtomicPtr { /// # Examples /// /// ``` - /// #![feature(strict_provenance_atomic_ptr)] /// use core::sync::atomic::{AtomicPtr, Ordering}; /// /// let pointer = &mut 3i64 as *mut i64; @@ -2376,7 +2371,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. @@ -2412,7 +2407,6 @@ impl AtomicPtr { /// # Examples /// /// ``` - /// #![feature(strict_provenance_atomic_ptr)] /// use core::sync::atomic::{AtomicPtr, Ordering}; /// /// let pointer = &mut 3i64 as *mut i64; @@ -2426,7 +2420,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. @@ -2462,7 +2456,6 @@ impl AtomicPtr { /// # Examples /// /// ``` - /// #![feature(strict_provenance_atomic_ptr)] /// use core::sync::atomic::{AtomicPtr, Ordering}; /// /// let pointer = &mut 3i64 as *mut i64; @@ -2474,7 +2467,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 0c4d49f3c99..92774e12681 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -95,7 +95,6 @@ #![feature(std_internals)] #![feature(step_trait)] #![feature(str_internals)] -#![feature(strict_provenance_atomic_ptr)] #![feature(strict_provenance_lints)] #![feature(test)] #![feature(trusted_len)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f111fcb4a47..77c7878ce08 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -370,7 +370,6 @@ #![feature(slice_range)] #![feature(std_internals)] #![feature(str_internals)] -#![feature(strict_provenance_atomic_ptr)] #![feature(sync_unsafe_cell)] #![feature(temporary_niche_types)] #![feature(ub_checks)] diff --git a/src/tools/miri/tests/pass/atomic.rs b/src/tools/miri/tests/pass/atomic.rs index 3de34e570c7..d8ac5114f27 100644 --- a/src/tools/miri/tests/pass/atomic.rs +++ b/src/tools/miri/tests/pass/atomic.rs @@ -2,7 +2,6 @@ //@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance -#![feature(strict_provenance_atomic_ptr)] // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] diff --git a/tests/codegen-llvm/atomicptr.rs b/tests/codegen-llvm/atomicptr.rs index ce6c4aa0d2b..9d5e618fe76 100644 --- a/tests/codegen-llvm/atomicptr.rs +++ b/tests/codegen-llvm/atomicptr.rs @@ -6,7 +6,6 @@ //@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes #![crate_type = "lib"] -#![feature(strict_provenance_atomic_ptr)] use std::ptr::without_provenance_mut; use std::sync::atomic::AtomicPtr; -- cgit 1.4.1-3-g733a5 From 6a24ae96eaf175b048e70dfb46dfb860ee7147d9 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 18 Aug 2025 11:50:27 +0200 Subject: Simplify macro generating `ToString` implementations for `&…&str` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use deref coercion to let the compiler remove any amount of references. --- library/alloc/src/string.rs | 55 +++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 9eacbf00e42..b1f2cb598c8 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2949,52 +2949,39 @@ impl SpecToString for i8 { } } -// Generic/generated code can sometimes have multiple, nested references -// for strings, including `&&&str`s that would never be written -// by hand. This macro generates twelve layers of nested `&`-impl -// for primitive strings. -#[cfg(not(no_global_oom_handling))] -macro_rules! to_string_str_wrap_in_ref { - {x $($x:ident)*} => { - &to_string_str_wrap_in_ref! { $($x)* } - }; - {} => { str }; -} -#[cfg(not(no_global_oom_handling))] -macro_rules! to_string_expr_wrap_in_deref { - {$self:expr ; x $($x:ident)*} => { - *(to_string_expr_wrap_in_deref! { $self ; $($x)* }) - }; - {$self:expr ;} => { $self }; -} #[cfg(not(no_global_oom_handling))] macro_rules! to_string_str { - {$($($x:ident)*),+} => { + {$($type:ty,)*} => { $( - impl SpecToString for to_string_str_wrap_in_ref!($($x)*) { + impl SpecToString for $type { #[inline] fn spec_to_string(&self) -> String { - String::from(to_string_expr_wrap_in_deref!(self ; $($x)*)) + let s: &str = self; + String::from(s) } } - )+ + )* }; } #[cfg(not(no_global_oom_handling))] to_string_str! { - x x x x x x x x x x x x, - x x x x x x x x x x x, - x x x x x x x x x x, - x x x x x x x x x, - x x x x x x x x, - x x x x x x x, - x x x x x x, - x x x x x, - x x x x, - x x x, - x x, - x, + // Generic/generated code can sometimes have multiple, nested references + // for strings, including `&&&str`s that would never be written + // by hand. + &&&&&&&&&&&&str, + &&&&&&&&&&&str, + &&&&&&&&&&str, + &&&&&&&&&str, + &&&&&&&&str, + &&&&&&&str, + &&&&&&str, + &&&&&str, + &&&&str, + &&&str, + &&str, + &str, + str, } #[cfg(not(no_global_oom_handling))] -- cgit 1.4.1-3-g733a5 From cb5a4d138a298853225d7561c243ce6e23064775 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 18 Aug 2025 11:51:31 +0200 Subject: Use `ToString` specialization macro also for `Cow` and `String` --- library/alloc/src/string.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index b1f2cb598c8..ec4d934a5a3 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2966,6 +2966,8 @@ macro_rules! to_string_str { #[cfg(not(no_global_oom_handling))] to_string_str! { + Cow<'_, str>, + String, // Generic/generated code can sometimes have multiple, nested references // for strings, including `&&&str`s that would never be written // by hand. @@ -2984,22 +2986,6 @@ to_string_str! { str, } -#[cfg(not(no_global_oom_handling))] -impl SpecToString for Cow<'_, str> { - #[inline] - fn spec_to_string(&self) -> String { - self[..].to_owned() - } -} - -#[cfg(not(no_global_oom_handling))] -impl SpecToString for String { - #[inline] - fn spec_to_string(&self) -> String { - self.to_owned() - } -} - #[cfg(not(no_global_oom_handling))] impl SpecToString for fmt::Arguments<'_> { #[inline] -- cgit 1.4.1-3-g733a5 From ca7a0aff74668ec62f4eb84a6b7655a2dfb821e2 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Wed, 20 Aug 2025 01:03:18 +0200 Subject: Fix some typos --- library/compiler-builtins/compiler-builtins/src/float/add.rs | 2 +- library/compiler-builtins/compiler-builtins/src/probestack.rs | 2 +- library/compiler-builtins/etc/update-api-list.py | 2 +- library/compiler-builtins/libm/src/math/rem_pio2_large.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/float/add.rs b/library/compiler-builtins/compiler-builtins/src/float/add.rs index 8dbfb0e1020..acdcd2ebe31 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/add.rs @@ -130,7 +130,7 @@ where return F::from_bits(MinInt::ZERO); } - // If partial cancellation occured, we need to left-shift the result + // If partial cancellation occurred, we need to left-shift the result // and adjust the exponent: if a_significand < implicit_bit << 3 { let shift = a_significand.leading_zeros() as i32 diff --git a/library/compiler-builtins/compiler-builtins/src/probestack.rs b/library/compiler-builtins/compiler-builtins/src/probestack.rs index 9a18216da99..72975485a77 100644 --- a/library/compiler-builtins/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/compiler-builtins/src/probestack.rs @@ -73,7 +73,7 @@ pub unsafe extern "custom" fn __rust_probestack() { // page needed. // // Note that we're also testing against `8(%rsp)` to account for the 8 - // bytes pushed on the stack orginally with our return address. Using + // bytes pushed on the stack originally with our return address. Using // `8(%rsp)` simulates us testing the stack pointer in the caller's // context. diff --git a/library/compiler-builtins/etc/update-api-list.py b/library/compiler-builtins/etc/update-api-list.py index 28ff22f4cbb..76c75cbf4dc 100755 --- a/library/compiler-builtins/etc/update-api-list.py +++ b/library/compiler-builtins/etc/update-api-list.py @@ -34,7 +34,7 @@ def eprint(*args, **kwargs): @dataclass class Crate: - """Representation of public interfaces and function defintion locations in + """Representation of public interfaces and function definition locations in `libm`. """ diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index f1fdf3673a8..bb2c532916b 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -146,7 +146,7 @@ const PIO2: [f64; 8] = [ // x[i] = floor(z) // z = (z-x[i])*2**24 // -// y[] ouput result in an array of double precision numbers. +// y[] output result in an array of double precision numbers. // The dimension of y[] is: // 24-bit precision 1 // 53-bit precision 2 -- cgit 1.4.1-3-g733a5 From 5a2fceefd312ec027bdeaa89ebefbe4c33d94de1 Mon Sep 17 00:00:00 2001 From: ltdk Date: Wed, 13 Aug 2025 01:16:09 -0400 Subject: Copy WTF-8 code into core/alloc (for better diffs) --- library/alloc/src/wtf8/mod.rs | 1083 ++++++++++++++++++++++++++++++ library/alloc/src/wtf8/tests.rs | 751 +++++++++++++++++++++ library/core/src/wtf8.rs | 1083 ++++++++++++++++++++++++++++++ library/std/src/sys_common/wtf8.rs | 1083 ------------------------------ library/std/src/sys_common/wtf8/tests.rs | 751 --------------------- 5 files changed, 2917 insertions(+), 1834 deletions(-) create mode 100644 library/alloc/src/wtf8/mod.rs create mode 100644 library/alloc/src/wtf8/tests.rs create mode 100644 library/core/src/wtf8.rs delete mode 100644 library/std/src/sys_common/wtf8.rs delete mode 100644 library/std/src/sys_common/wtf8/tests.rs diff --git a/library/alloc/src/wtf8/mod.rs b/library/alloc/src/wtf8/mod.rs new file mode 100644 index 00000000000..50bde88b5a4 --- /dev/null +++ b/library/alloc/src/wtf8/mod.rs @@ -0,0 +1,1083 @@ +//! Implementation of [the WTF-8 encoding](https://simonsapin.github.io/wtf-8/). +//! +//! This library uses Rust’s type system to maintain +//! [well-formedness](https://simonsapin.github.io/wtf-8/#well-formed), +//! like the `String` and `&str` types do for UTF-8. +//! +//! Since [WTF-8 must not be used +//! for interchange](https://simonsapin.github.io/wtf-8/#intended-audience), +//! this library deliberately does not provide access to the underlying bytes +//! of WTF-8 strings, +//! nor can it decode WTF-8 from arbitrary bytes. +//! WTF-8 strings can be obtained from UTF-8, UTF-16, or code points. + +// this module is imported from @SimonSapin's repo and has tons of dead code on +// unix (it's mostly used on windows), so don't worry about dead code here. +#![allow(dead_code)] + +#[cfg(test)] +mod tests; + +use core::char::{MAX_LEN_UTF8, MAX_LEN_UTF16, encode_utf8_raw, encode_utf16_raw}; +use core::clone::CloneToUninit; +use core::str::next_code_point; + +use crate::borrow::Cow; +use crate::collections::TryReserveError; +use crate::hash::{Hash, Hasher}; +use crate::iter::FusedIterator; +use crate::rc::Rc; +use crate::sync::Arc; +use crate::sys_common::AsInner; +use crate::{fmt, mem, ops, slice, str}; + +const UTF8_REPLACEMENT_CHARACTER: &str = "\u{FFFD}"; + +/// A Unicode code point: from U+0000 to U+10FFFF. +/// +/// Compares with the `char` type, +/// which represents a Unicode scalar value: +/// a code point that is not a surrogate (U+D800 to U+DFFF). +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] +pub struct CodePoint { + value: u32, +} + +/// Format the code point as `U+` followed by four to six hexadecimal digits. +/// Example: `U+1F4A9` +impl fmt::Debug for CodePoint { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(formatter, "U+{:04X}", self.value) + } +} + +impl CodePoint { + /// Unsafely creates a new `CodePoint` without checking the value. + /// + /// Only use when `value` is known to be less than or equal to 0x10FFFF. + #[inline] + pub unsafe fn from_u32_unchecked(value: u32) -> CodePoint { + CodePoint { value } + } + + /// Creates a new `CodePoint` if the value is a valid code point. + /// + /// Returns `None` if `value` is above 0x10FFFF. + #[inline] + pub fn from_u32(value: u32) -> Option { + match value { + 0..=0x10FFFF => Some(CodePoint { value }), + _ => None, + } + } + + /// Creates a new `CodePoint` from a `char`. + /// + /// Since all Unicode scalar values are code points, this always succeeds. + #[inline] + pub fn from_char(value: char) -> CodePoint { + CodePoint { value: value as u32 } + } + + /// Returns the numeric value of the code point. + #[inline] + pub fn to_u32(&self) -> u32 { + self.value + } + + /// Returns the numeric value of the code point if it is a leading surrogate. + #[inline] + pub fn to_lead_surrogate(&self) -> Option { + match self.value { + lead @ 0xD800..=0xDBFF => Some(lead as u16), + _ => None, + } + } + + /// Returns the numeric value of the code point if it is a trailing surrogate. + #[inline] + pub fn to_trail_surrogate(&self) -> Option { + match self.value { + trail @ 0xDC00..=0xDFFF => Some(trail as u16), + _ => None, + } + } + + /// Optionally returns a Unicode scalar value for the code point. + /// + /// Returns `None` if the code point is a surrogate (from U+D800 to U+DFFF). + #[inline] + pub fn to_char(&self) -> Option { + match self.value { + 0xD800..=0xDFFF => None, + _ => Some(unsafe { char::from_u32_unchecked(self.value) }), + } + } + + /// Returns a Unicode scalar value for the code point. + /// + /// Returns `'\u{FFFD}'` (the replacement character “�”) + /// if the code point is a surrogate (from U+D800 to U+DFFF). + #[inline] + pub fn to_char_lossy(&self) -> char { + self.to_char().unwrap_or('\u{FFFD}') + } +} + +/// An owned, growable string of well-formed WTF-8 data. +/// +/// Similar to `String`, but can additionally contain surrogate code points +/// if they’re not in a surrogate pair. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone)] +pub struct Wtf8Buf { + bytes: Vec, + + /// Do we know that `bytes` holds a valid UTF-8 encoding? We can easily + /// know this if we're constructed from a `String` or `&str`. + /// + /// It is possible for `bytes` to have valid UTF-8 without this being + /// set, such as when we're concatenating `&Wtf8`'s and surrogates become + /// paired, as we don't bother to rescan the entire string. + is_known_utf8: bool, +} + +impl ops::Deref for Wtf8Buf { + type Target = Wtf8; + + fn deref(&self) -> &Wtf8 { + self.as_slice() + } +} + +impl ops::DerefMut for Wtf8Buf { + fn deref_mut(&mut self) -> &mut Wtf8 { + self.as_mut_slice() + } +} + +/// Formats the string in double quotes, with characters escaped according to +/// [`char::escape_debug`] and unpaired surrogates represented as `\u{xxxx}`, +/// where each `x` is a hexadecimal digit. +/// +/// For example, the code units [U+0061, U+D800, U+000A] are formatted as +/// `"a\u{D800}\n"`. +impl fmt::Debug for Wtf8Buf { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, formatter) + } +} + +/// Formats the string with unpaired surrogates substituted with the replacement +/// character, U+FFFD. +impl fmt::Display for Wtf8Buf { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(s) = self.as_known_utf8() { + fmt::Display::fmt(s, formatter) + } else { + fmt::Display::fmt(&**self, formatter) + } + } +} + +impl Wtf8Buf { + /// Creates a new, empty WTF-8 string. + #[inline] + pub fn new() -> Wtf8Buf { + Wtf8Buf { bytes: Vec::new(), is_known_utf8: true } + } + + /// Creates a new, empty WTF-8 string with pre-allocated capacity for `capacity` bytes. + #[inline] + pub fn with_capacity(capacity: usize) -> Wtf8Buf { + Wtf8Buf { bytes: Vec::with_capacity(capacity), is_known_utf8: true } + } + + /// Creates a WTF-8 string from a WTF-8 byte vec. + /// + /// Since the byte vec is not checked for valid WTF-8, this function is + /// marked unsafe. + #[inline] + pub unsafe fn from_bytes_unchecked(value: Vec) -> Wtf8Buf { + Wtf8Buf { bytes: value, is_known_utf8: false } + } + + /// Creates a WTF-8 string from a UTF-8 `String`. + /// + /// This takes ownership of the `String` and does not copy. + /// + /// Since WTF-8 is a superset of UTF-8, this always succeeds. + #[inline] + pub const fn from_string(string: String) -> Wtf8Buf { + Wtf8Buf { bytes: string.into_bytes(), is_known_utf8: true } + } + + /// Creates a WTF-8 string from a UTF-8 `&str` slice. + /// + /// This copies the content of the slice. + /// + /// Since WTF-8 is a superset of UTF-8, this always succeeds. + #[inline] + pub fn from_str(s: &str) -> Wtf8Buf { + Wtf8Buf { bytes: s.as_bytes().to_vec(), is_known_utf8: true } + } + + pub fn clear(&mut self) { + self.bytes.clear(); + self.is_known_utf8 = true; + } + + /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units. + /// + /// This is lossless: calling `.encode_wide()` on the resulting string + /// will always return the original code units. + pub fn from_wide(v: &[u16]) -> Wtf8Buf { + let mut string = Wtf8Buf::with_capacity(v.len()); + for item in char::decode_utf16(v.iter().cloned()) { + match item { + Ok(ch) => string.push_char(ch), + Err(surrogate) => { + let surrogate = surrogate.unpaired_surrogate(); + // Surrogates are known to be in the code point range. + let code_point = unsafe { CodePoint::from_u32_unchecked(surrogate as u32) }; + // The string will now contain an unpaired surrogate. + string.is_known_utf8 = false; + // Skip the WTF-8 concatenation check, + // surrogate pairs are already decoded by decode_utf16 + string.push_code_point_unchecked(code_point); + } + } + } + string + } + + /// Appends the given `char` to the end of this string. + /// This does **not** include the WTF-8 concatenation check or `is_known_utf8` check. + /// Copied from String::push. + fn push_code_point_unchecked(&mut self, code_point: CodePoint) { + let mut bytes = [0; MAX_LEN_UTF8]; + let bytes = encode_utf8_raw(code_point.value, &mut bytes); + self.bytes.extend_from_slice(bytes) + } + + #[inline] + pub fn as_slice(&self) -> &Wtf8 { + unsafe { Wtf8::from_bytes_unchecked(&self.bytes) } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut Wtf8 { + // Safety: `Wtf8` doesn't expose any way to mutate the bytes that would + // cause them to change from well-formed UTF-8 to ill-formed UTF-8, + // which would break the assumptions of the `is_known_utf8` field. + unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) } + } + + /// Converts the string to UTF-8 without validation, if it was created from + /// valid UTF-8. + #[inline] + fn as_known_utf8(&self) -> Option<&str> { + if self.is_known_utf8 { + // SAFETY: The buffer is known to be valid UTF-8. + Some(unsafe { str::from_utf8_unchecked(self.as_bytes()) }) + } else { + None + } + } + + /// Reserves capacity for at least `additional` more bytes to be inserted + /// in the given `Wtf8Buf`. + /// The collection may reserve more space to avoid frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.bytes.reserve(additional) + } + + /// Tries to reserve capacity for at least `additional` more bytes to be + /// inserted in the given `Wtf8Buf`. The `Wtf8Buf` may reserve more space to + /// avoid frequent reallocations. After calling `try_reserve`, capacity will + /// be greater than or equal to `self.len() + additional`. Does nothing if + /// capacity is already sufficient. This method preserves the contents even + /// if an error occurs. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + #[inline] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.bytes.try_reserve(additional) + } + + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.bytes.reserve_exact(additional) + } + + /// Tries to reserve the minimum capacity for exactly `additional` more + /// bytes to be inserted in the given `Wtf8Buf`. After calling + /// `try_reserve_exact`, capacity will be greater than or equal to + /// `self.len() + additional` if it returns `Ok(())`. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the `Wtf8Buf` more space than it + /// requests. Therefore, capacity can not be relied upon to be precisely + /// minimal. Prefer [`try_reserve`] if future insertions are expected. + /// + /// [`try_reserve`]: Wtf8Buf::try_reserve + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + #[inline] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.bytes.try_reserve_exact(additional) + } + + #[inline] + pub fn shrink_to_fit(&mut self) { + self.bytes.shrink_to_fit() + } + + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.bytes.shrink_to(min_capacity) + } + + #[inline] + pub fn leak<'a>(self) -> &'a mut Wtf8 { + unsafe { Wtf8::from_mut_bytes_unchecked(self.bytes.leak()) } + } + + /// Returns the number of bytes that this string buffer can hold without reallocating. + #[inline] + pub fn capacity(&self) -> usize { + self.bytes.capacity() + } + + /// Append a UTF-8 slice at the end of the string. + #[inline] + pub fn push_str(&mut self, other: &str) { + self.bytes.extend_from_slice(other.as_bytes()) + } + + /// Append a WTF-8 slice at the end of the string. + /// + /// This replaces newly paired surrogates at the boundary + /// with a supplementary code point, + /// like concatenating ill-formed UTF-16 strings effectively would. + #[inline] + pub fn push_wtf8(&mut self, other: &Wtf8) { + match ((&*self).final_lead_surrogate(), other.initial_trail_surrogate()) { + // Replace newly paired surrogates by a supplementary code point. + (Some(lead), Some(trail)) => { + let len_without_lead_surrogate = self.len() - 3; + self.bytes.truncate(len_without_lead_surrogate); + let other_without_trail_surrogate = &other.bytes[3..]; + // 4 bytes for the supplementary code point + self.bytes.reserve(4 + other_without_trail_surrogate.len()); + self.push_char(decode_surrogate_pair(lead, trail)); + self.bytes.extend_from_slice(other_without_trail_surrogate); + } + _ => { + // If we'll be pushing a string containing a surrogate, we may + // no longer have UTF-8. + if self.is_known_utf8 && other.next_surrogate(0).is_some() { + self.is_known_utf8 = false; + } + + self.bytes.extend_from_slice(&other.bytes); + } + } + } + + /// Append a Unicode scalar value at the end of the string. + #[inline] + pub fn push_char(&mut self, c: char) { + self.push_code_point_unchecked(CodePoint::from_char(c)) + } + + /// Append a code point at the end of the string. + /// + /// This replaces newly paired surrogates at the boundary + /// with a supplementary code point, + /// like concatenating ill-formed UTF-16 strings effectively would. + #[inline] + pub fn push(&mut self, code_point: CodePoint) { + if let Some(trail) = code_point.to_trail_surrogate() { + if let Some(lead) = (&*self).final_lead_surrogate() { + let len_without_lead_surrogate = self.len() - 3; + self.bytes.truncate(len_without_lead_surrogate); + self.push_char(decode_surrogate_pair(lead, trail)); + return; + } + + // We're pushing a trailing surrogate. + self.is_known_utf8 = false; + } else if code_point.to_lead_surrogate().is_some() { + // We're pushing a leading surrogate. + self.is_known_utf8 = false; + } + + // No newly paired surrogates at the boundary. + self.push_code_point_unchecked(code_point) + } + + /// Shortens a string to the specified length. + /// + /// # Panics + /// + /// Panics if `new_len` > current length, + /// or if `new_len` is not a code point boundary. + #[inline] + pub fn truncate(&mut self, new_len: usize) { + assert!(is_code_point_boundary(self, new_len)); + self.bytes.truncate(new_len) + } + + /// Consumes the WTF-8 string and tries to convert it to a vec of bytes. + #[inline] + pub fn into_bytes(self) -> Vec { + self.bytes + } + + /// Consumes the WTF-8 string and tries to convert it to UTF-8. + /// + /// This does not copy the data. + /// + /// If the contents are not well-formed UTF-8 + /// (that is, if the string contains surrogates), + /// the original WTF-8 string is returned instead. + pub fn into_string(self) -> Result { + if self.is_known_utf8 || self.next_surrogate(0).is_none() { + Ok(unsafe { String::from_utf8_unchecked(self.bytes) }) + } else { + Err(self) + } + } + + /// Consumes the WTF-8 string and converts it lossily to UTF-8. + /// + /// This does not copy the data (but may overwrite parts of it in place). + /// + /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”) + pub fn into_string_lossy(mut self) -> String { + if !self.is_known_utf8 { + let mut pos = 0; + while let Some((surrogate_pos, _)) = self.next_surrogate(pos) { + pos = surrogate_pos + 3; + // Surrogates and the replacement character are all 3 bytes, so + // they can substituted in-place. + self.bytes[surrogate_pos..pos] + .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); + } + } + unsafe { String::from_utf8_unchecked(self.bytes) } + } + + /// Converts this `Wtf8Buf` into a boxed `Wtf8`. + #[inline] + pub fn into_box(self) -> Box { + // SAFETY: relies on `Wtf8` being `repr(transparent)`. + unsafe { mem::transmute(self.bytes.into_boxed_slice()) } + } + + /// Converts a `Box` into a `Wtf8Buf`. + pub fn from_box(boxed: Box) -> Wtf8Buf { + let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) }; + Wtf8Buf { bytes: bytes.into_vec(), is_known_utf8: false } + } + + /// Provides plumbing to core `Vec::extend_from_slice`. + /// More well behaving alternative to allowing outer types + /// full mutable access to the core `Vec`. + #[inline] + pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { + self.bytes.extend_from_slice(other); + self.is_known_utf8 = false; + } +} + +/// Creates a new WTF-8 string from an iterator of code points. +/// +/// This replaces surrogate code point pairs with supplementary code points, +/// like concatenating ill-formed UTF-16 strings effectively would. +impl FromIterator for Wtf8Buf { + fn from_iter>(iter: T) -> Wtf8Buf { + let mut string = Wtf8Buf::new(); + string.extend(iter); + string + } +} + +/// Append code points from an iterator to the string. +/// +/// This replaces surrogate code point pairs with supplementary code points, +/// like concatenating ill-formed UTF-16 strings effectively would. +impl Extend for Wtf8Buf { + fn extend>(&mut self, iter: T) { + let iterator = iter.into_iter(); + let (low, _high) = iterator.size_hint(); + // Lower bound of one byte per code point (ASCII only) + self.bytes.reserve(low); + iterator.for_each(move |code_point| self.push(code_point)); + } + + #[inline] + fn extend_one(&mut self, code_point: CodePoint) { + self.push(code_point); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + // Lower bound of one byte per code point (ASCII only) + self.bytes.reserve(additional); + } +} + +/// A borrowed slice of well-formed WTF-8 data. +/// +/// Similar to `&str`, but can additionally contain surrogate code points +/// if they’re not in a surrogate pair. +#[derive(Eq, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct Wtf8 { + bytes: [u8], +} + +impl AsInner<[u8]> for Wtf8 { + #[inline] + fn as_inner(&self) -> &[u8] { + &self.bytes + } +} + +/// Formats the string in double quotes, with characters escaped according to +/// [`char::escape_debug`] and unpaired surrogates represented as `\u{xxxx}`, +/// where each `x` is a hexadecimal digit. +impl fmt::Debug for Wtf8 { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fn write_str_escaped(f: &mut fmt::Formatter<'_>, s: &str) -> fmt::Result { + use crate::fmt::Write; + for c in s.chars().flat_map(|c| c.escape_debug()) { + f.write_char(c)? + } + Ok(()) + } + + formatter.write_str("\"")?; + let mut pos = 0; + while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) { + write_str_escaped(formatter, unsafe { + str::from_utf8_unchecked(&self.bytes[pos..surrogate_pos]) + })?; + write!(formatter, "\\u{{{:x}}}", surrogate)?; + pos = surrogate_pos + 3; + } + write_str_escaped(formatter, unsafe { str::from_utf8_unchecked(&self.bytes[pos..]) })?; + formatter.write_str("\"") + } +} + +/// Formats the string with unpaired surrogates substituted with the replacement +/// character, U+FFFD. +impl fmt::Display for Wtf8 { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + let wtf8_bytes = &self.bytes; + let mut pos = 0; + loop { + match self.next_surrogate(pos) { + Some((surrogate_pos, _)) => { + formatter.write_str(unsafe { + str::from_utf8_unchecked(&wtf8_bytes[pos..surrogate_pos]) + })?; + formatter.write_str(UTF8_REPLACEMENT_CHARACTER)?; + pos = surrogate_pos + 3; + } + None => { + let s = unsafe { str::from_utf8_unchecked(&wtf8_bytes[pos..]) }; + if pos == 0 { return s.fmt(formatter) } else { return formatter.write_str(s) } + } + } + } + } +} + +impl Wtf8 { + /// Creates a WTF-8 slice from a UTF-8 `&str` slice. + /// + /// Since WTF-8 is a superset of UTF-8, this always succeeds. + #[inline] + pub fn from_str(value: &str) -> &Wtf8 { + unsafe { Wtf8::from_bytes_unchecked(value.as_bytes()) } + } + + /// Creates a WTF-8 slice from a WTF-8 byte slice. + /// + /// Since the byte slice is not checked for valid WTF-8, this functions is + /// marked unsafe. + #[inline] + pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { + // SAFETY: start with &[u8], end with fancy &[u8] + unsafe { &*(value as *const [u8] as *const Wtf8) } + } + + /// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice. + /// + /// Since the byte slice is not checked for valid WTF-8, this functions is + /// marked unsafe. + #[inline] + unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 { + // SAFETY: start with &mut [u8], end with fancy &mut [u8] + unsafe { &mut *(value as *mut [u8] as *mut Wtf8) } + } + + /// Returns the length, in WTF-8 bytes. + #[inline] + pub fn len(&self) -> usize { + self.bytes.len() + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.bytes.is_empty() + } + + /// Returns the code point at `position` if it is in the ASCII range, + /// or `b'\xFF'` otherwise. + /// + /// # Panics + /// + /// Panics if `position` is beyond the end of the string. + #[inline] + pub fn ascii_byte_at(&self, position: usize) -> u8 { + match self.bytes[position] { + ascii_byte @ 0x00..=0x7F => ascii_byte, + _ => 0xFF, + } + } + + /// Returns an iterator for the string’s code points. + #[inline] + pub fn code_points(&self) -> Wtf8CodePoints<'_> { + Wtf8CodePoints { bytes: self.bytes.iter() } + } + + /// Access raw bytes of WTF-8 data + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.bytes + } + + /// Tries to convert the string to UTF-8 and return a `&str` slice. + /// + /// Returns `None` if the string contains surrogates. + /// + /// This does not copy the data. + #[inline] + pub fn as_str(&self) -> Result<&str, str::Utf8Error> { + str::from_utf8(&self.bytes) + } + + /// Creates an owned `Wtf8Buf` from a borrowed `Wtf8`. + pub fn to_owned(&self) -> Wtf8Buf { + Wtf8Buf { bytes: self.bytes.to_vec(), is_known_utf8: false } + } + + /// Lossily converts the string to UTF-8. + /// Returns a UTF-8 `&str` slice if the contents are well-formed in UTF-8. + /// + /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”). + /// + /// This only copies the data if necessary (if it contains any surrogate). + pub fn to_string_lossy(&self) -> Cow<'_, str> { + let Some((surrogate_pos, _)) = self.next_surrogate(0) else { + return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }); + }; + let wtf8_bytes = &self.bytes; + let mut utf8_bytes = Vec::with_capacity(self.len()); + utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]); + utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); + let mut pos = surrogate_pos + 3; + loop { + match self.next_surrogate(pos) { + Some((surrogate_pos, _)) => { + utf8_bytes.extend_from_slice(&wtf8_bytes[pos..surrogate_pos]); + utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); + pos = surrogate_pos + 3; + } + None => { + utf8_bytes.extend_from_slice(&wtf8_bytes[pos..]); + return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) }); + } + } + } + } + + /// Converts the WTF-8 string to potentially ill-formed UTF-16 + /// and return an iterator of 16-bit code units. + /// + /// This is lossless: + /// calling `Wtf8Buf::from_ill_formed_utf16` on the resulting code units + /// would always return the original WTF-8 string. + #[inline] + pub fn encode_wide(&self) -> EncodeWide<'_> { + EncodeWide { code_points: self.code_points(), extra: 0 } + } + + #[inline] + fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> { + let mut iter = self.bytes[pos..].iter(); + loop { + let b = *iter.next()?; + if b < 0x80 { + pos += 1; + } else if b < 0xE0 { + iter.next(); + pos += 2; + } else if b == 0xED { + match (iter.next(), iter.next()) { + (Some(&b2), Some(&b3)) if b2 >= 0xA0 => { + return Some((pos, decode_surrogate(b2, b3))); + } + _ => pos += 3, + } + } else if b < 0xF0 { + iter.next(); + iter.next(); + pos += 3; + } else { + iter.next(); + iter.next(); + iter.next(); + pos += 4; + } + } + } + + #[inline] + fn final_lead_surrogate(&self) -> Option { + match self.bytes { + [.., 0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)), + _ => None, + } + } + + #[inline] + fn initial_trail_surrogate(&self) -> Option { + match self.bytes { + [0xED, b2 @ 0xB0..=0xBF, b3, ..] => Some(decode_surrogate(b2, b3)), + _ => None, + } + } + + pub fn clone_into(&self, buf: &mut Wtf8Buf) { + buf.is_known_utf8 = false; + self.bytes.clone_into(&mut buf.bytes); + } + + /// Boxes this `Wtf8`. + #[inline] + pub fn into_box(&self) -> Box { + let boxed: Box<[u8]> = self.bytes.into(); + unsafe { mem::transmute(boxed) } + } + + /// Creates a boxed, empty `Wtf8`. + pub fn empty_box() -> Box { + let boxed: Box<[u8]> = Default::default(); + unsafe { mem::transmute(boxed) } + } + + #[inline] + pub fn into_arc(&self) -> Arc { + let arc: Arc<[u8]> = Arc::from(&self.bytes); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Wtf8) } + } + + #[inline] + pub fn into_rc(&self) -> Rc { + let rc: Rc<[u8]> = Rc::from(&self.bytes); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Wtf8) } + } + + #[inline] + pub fn make_ascii_lowercase(&mut self) { + self.bytes.make_ascii_lowercase() + } + + #[inline] + pub fn make_ascii_uppercase(&mut self) { + self.bytes.make_ascii_uppercase() + } + + #[inline] + pub fn to_ascii_lowercase(&self) -> Wtf8Buf { + Wtf8Buf { bytes: self.bytes.to_ascii_lowercase(), is_known_utf8: false } + } + + #[inline] + pub fn to_ascii_uppercase(&self) -> Wtf8Buf { + Wtf8Buf { bytes: self.bytes.to_ascii_uppercase(), is_known_utf8: false } + } + + #[inline] + pub fn is_ascii(&self) -> bool { + self.bytes.is_ascii() + } + + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { + self.bytes.eq_ignore_ascii_case(&other.bytes) + } +} + +/// Returns a slice of the given string for the byte range \[`begin`..`end`). +/// +/// # Panics +/// +/// Panics when `begin` and `end` do not point to code point boundaries, +/// or point beyond the end of the string. +impl ops::Index> for Wtf8 { + type Output = Wtf8; + + #[inline] + fn index(&self, range: ops::Range) -> &Wtf8 { + // is_code_point_boundary checks that the index is in [0, .len()] + if range.start <= range.end + && is_code_point_boundary(self, range.start) + && is_code_point_boundary(self, range.end) + { + unsafe { slice_unchecked(self, range.start, range.end) } + } else { + slice_error_fail(self, range.start, range.end) + } + } +} + +/// Returns a slice of the given string from byte `begin` to its end. +/// +/// # Panics +/// +/// Panics when `begin` is not at a code point boundary, +/// or is beyond the end of the string. +impl ops::Index> for Wtf8 { + type Output = Wtf8; + + #[inline] + fn index(&self, range: ops::RangeFrom) -> &Wtf8 { + // is_code_point_boundary checks that the index is in [0, .len()] + if is_code_point_boundary(self, range.start) { + unsafe { slice_unchecked(self, range.start, self.len()) } + } else { + slice_error_fail(self, range.start, self.len()) + } + } +} + +/// Returns a slice of the given string from its beginning to byte `end`. +/// +/// # Panics +/// +/// Panics when `end` is not at a code point boundary, +/// or is beyond the end of the string. +impl ops::Index> for Wtf8 { + type Output = Wtf8; + + #[inline] + fn index(&self, range: ops::RangeTo) -> &Wtf8 { + // is_code_point_boundary checks that the index is in [0, .len()] + if is_code_point_boundary(self, range.end) { + unsafe { slice_unchecked(self, 0, range.end) } + } else { + slice_error_fail(self, 0, range.end) + } + } +} + +impl ops::Index for Wtf8 { + type Output = Wtf8; + + #[inline] + fn index(&self, _range: ops::RangeFull) -> &Wtf8 { + self + } +} + +#[inline] +fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 { + // The first byte is assumed to be 0xED + 0xD800 | (second_byte as u16 & 0x3F) << 6 | third_byte as u16 & 0x3F +} + +#[inline] +fn decode_surrogate_pair(lead: u16, trail: u16) -> char { + let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32); + unsafe { char::from_u32_unchecked(code_point) } +} + +/// Copied from str::is_char_boundary +#[inline] +pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool { + if index == 0 { + return true; + } + match slice.bytes.get(index) { + None => index == slice.len(), + Some(&b) => (b as i8) >= -0x40, + } +} + +/// Verify that `index` is at the edge of either a valid UTF-8 codepoint +/// (i.e. a codepoint that's not a surrogate) or of the whole string. +/// +/// These are the cases currently permitted by `OsStr::slice_encoded_bytes`. +/// Splitting between surrogates is valid as far as WTF-8 is concerned, but +/// we do not permit it in the public API because WTF-8 is considered an +/// implementation detail. +#[track_caller] +#[inline] +pub fn check_utf8_boundary(slice: &Wtf8, index: usize) { + if index == 0 { + return; + } + match slice.bytes.get(index) { + Some(0xED) => (), // Might be a surrogate + Some(&b) if (b as i8) >= -0x40 => return, + Some(_) => panic!("byte index {index} is not a codepoint boundary"), + None if index == slice.len() => return, + None => panic!("byte index {index} is out of bounds"), + } + if slice.bytes[index + 1] >= 0xA0 { + // There's a surrogate after index. Now check before index. + if index >= 3 && slice.bytes[index - 3] == 0xED && slice.bytes[index - 2] >= 0xA0 { + panic!("byte index {index} lies between surrogate codepoints"); + } + } +} + +/// Copied from core::str::raw::slice_unchecked +#[inline] +pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { + // SAFETY: memory layout of a &[u8] and &Wtf8 are the same + unsafe { + let len = end - begin; + let start = s.as_bytes().as_ptr().add(begin); + Wtf8::from_bytes_unchecked(slice::from_raw_parts(start, len)) + } +} + +/// Copied from core::str::raw::slice_error_fail +#[inline(never)] +pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! { + assert!(begin <= end); + panic!("index {begin} and/or {end} in `{s:?}` do not lie on character boundary"); +} + +/// Iterator for the code points of a WTF-8 string. +/// +/// Created with the method `.code_points()`. +#[derive(Clone)] +pub struct Wtf8CodePoints<'a> { + bytes: slice::Iter<'a, u8>, +} + +impl Iterator for Wtf8CodePoints<'_> { + type Item = CodePoint; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: `self.bytes` has been created from a WTF-8 string + unsafe { next_code_point(&mut self.bytes).map(|c| CodePoint { value: c }) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.bytes.len(); + (len.saturating_add(3) / 4, Some(len)) + } +} + +/// Generates a wide character sequence for potentially ill-formed UTF-16. +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct EncodeWide<'a> { + code_points: Wtf8CodePoints<'a>, + extra: u16, +} + +// Copied from libunicode/u_str.rs +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for EncodeWide<'_> { + type Item = u16; + + #[inline] + fn next(&mut self) -> Option { + if self.extra != 0 { + let tmp = self.extra; + self.extra = 0; + return Some(tmp); + } + + let mut buf = [0; MAX_LEN_UTF16]; + self.code_points.next().map(|code_point| { + let n = encode_utf16_raw(code_point.value, &mut buf).len(); + if n == 2 { + self.extra = buf[1]; + } + buf[0] + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (low, high) = self.code_points.size_hint(); + let ext = (self.extra != 0) as usize; + // every code point gets either one u16 or two u16, + // so this iterator is between 1 or 2 times as + // long as the underlying iterator. + (low + ext, high.and_then(|n| n.checked_mul(2)).and_then(|n| n.checked_add(ext))) + } +} + +#[stable(feature = "encode_wide_fused_iterator", since = "1.62.0")] +impl FusedIterator for EncodeWide<'_> {} + +impl Hash for CodePoint { + #[inline] + fn hash(&self, state: &mut H) { + self.value.hash(state) + } +} + +impl Hash for Wtf8Buf { + #[inline] + fn hash(&self, state: &mut H) { + state.write(&self.bytes); + 0xfeu8.hash(state) + } +} + +impl Hash for Wtf8 { + #[inline] + fn hash(&self, state: &mut H) { + state.write(&self.bytes); + 0xfeu8.hash(state) + } +} + +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl CloneToUninit for Wtf8 { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: we're just a transparent wrapper around [u8] + unsafe { self.bytes.clone_to_uninit(dst) } + } +} diff --git a/library/alloc/src/wtf8/tests.rs b/library/alloc/src/wtf8/tests.rs new file mode 100644 index 00000000000..b57c99a8452 --- /dev/null +++ b/library/alloc/src/wtf8/tests.rs @@ -0,0 +1,751 @@ +use super::*; + +#[test] +fn code_point_from_u32() { + assert!(CodePoint::from_u32(0).is_some()); + assert!(CodePoint::from_u32(0xD800).is_some()); + assert!(CodePoint::from_u32(0x10FFFF).is_some()); + assert!(CodePoint::from_u32(0x110000).is_none()); +} + +#[test] +fn code_point_to_u32() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + assert_eq!(c(0).to_u32(), 0); + assert_eq!(c(0xD800).to_u32(), 0xD800); + assert_eq!(c(0x10FFFF).to_u32(), 0x10FFFF); +} + +#[test] +fn code_point_to_lead_surrogate() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + assert_eq!(c(0).to_lead_surrogate(), None); + assert_eq!(c(0xE9).to_lead_surrogate(), None); + assert_eq!(c(0xD800).to_lead_surrogate(), Some(0xD800)); + assert_eq!(c(0xDBFF).to_lead_surrogate(), Some(0xDBFF)); + assert_eq!(c(0xDC00).to_lead_surrogate(), None); + assert_eq!(c(0xDFFF).to_lead_surrogate(), None); + assert_eq!(c(0x1F4A9).to_lead_surrogate(), None); + assert_eq!(c(0x10FFFF).to_lead_surrogate(), None); +} + +#[test] +fn code_point_to_trail_surrogate() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + assert_eq!(c(0).to_trail_surrogate(), None); + assert_eq!(c(0xE9).to_trail_surrogate(), None); + assert_eq!(c(0xD800).to_trail_surrogate(), None); + assert_eq!(c(0xDBFF).to_trail_surrogate(), None); + assert_eq!(c(0xDC00).to_trail_surrogate(), Some(0xDC00)); + assert_eq!(c(0xDFFF).to_trail_surrogate(), Some(0xDFFF)); + assert_eq!(c(0x1F4A9).to_trail_surrogate(), None); + assert_eq!(c(0x10FFFF).to_trail_surrogate(), None); +} + +#[test] +fn code_point_from_char() { + assert_eq!(CodePoint::from_char('a').to_u32(), 0x61); + assert_eq!(CodePoint::from_char('💩').to_u32(), 0x1F4A9); +} + +#[test] +fn code_point_to_string() { + assert_eq!(format!("{:?}", CodePoint::from_char('a')), "U+0061"); + assert_eq!(format!("{:?}", CodePoint::from_char('💩')), "U+1F4A9"); +} + +#[test] +fn code_point_to_char() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + assert_eq!(c(0x61).to_char(), Some('a')); + assert_eq!(c(0x1F4A9).to_char(), Some('💩')); + assert_eq!(c(0xD800).to_char(), None); +} + +#[test] +fn code_point_to_char_lossy() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + assert_eq!(c(0x61).to_char_lossy(), 'a'); + assert_eq!(c(0x1F4A9).to_char_lossy(), '💩'); + assert_eq!(c(0xD800).to_char_lossy(), '\u{FFFD}'); +} + +#[test] +fn wtf8buf_new() { + assert_eq!(Wtf8Buf::new().bytes, b""); +} + +#[test] +fn wtf8buf_from_str() { + assert_eq!(Wtf8Buf::from_str("").bytes, b""); + assert_eq!(Wtf8Buf::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +fn wtf8buf_from_string() { + assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b""); + assert_eq!(Wtf8Buf::from_string(String::from("aé 💩")).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +fn wtf8buf_from_wide() { + let buf = Wtf8Buf::from_wide(&[]); + assert_eq!(buf.bytes, b""); + assert!(buf.is_known_utf8); + + let buf = Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xDCA9]); + assert_eq!(buf.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert!(buf.is_known_utf8); + + let buf = Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]); + assert_eq!(buf.bytes, b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9"); + assert!(!buf.is_known_utf8); + + let buf = Wtf8Buf::from_wide(&[0xD800]); + assert_eq!(buf.bytes, b"\xED\xA0\x80"); + assert!(!buf.is_known_utf8); + + let buf = Wtf8Buf::from_wide(&[0xDBFF]); + assert_eq!(buf.bytes, b"\xED\xAF\xBF"); + assert!(!buf.is_known_utf8); + + let buf = Wtf8Buf::from_wide(&[0xDC00]); + assert_eq!(buf.bytes, b"\xED\xB0\x80"); + assert!(!buf.is_known_utf8); + + let buf = Wtf8Buf::from_wide(&[0xDFFF]); + assert_eq!(buf.bytes, b"\xED\xBF\xBF"); + assert!(!buf.is_known_utf8); +} + +#[test] +fn wtf8buf_push_str() { + let mut string = Wtf8Buf::new(); + assert_eq!(string.bytes, b""); + assert!(string.is_known_utf8); + + string.push_str("aé 💩"); + assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert!(string.is_known_utf8); +} + +#[test] +fn wtf8buf_push_char() { + let mut string = Wtf8Buf::from_str("aé "); + assert_eq!(string.bytes, b"a\xC3\xA9 "); + assert!(string.is_known_utf8); + + string.push_char('💩'); + assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert!(string.is_known_utf8); +} + +#[test] +fn wtf8buf_push() { + let mut string = Wtf8Buf::from_str("aé "); + assert_eq!(string.bytes, b"a\xC3\xA9 "); + assert!(string.is_known_utf8); + + string.push(CodePoint::from_char('💩')); + assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert!(string.is_known_utf8); + + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + + let mut string = Wtf8Buf::new(); + string.push(c(0xD83D)); // lead + assert!(!string.is_known_utf8); + string.push(c(0xDCA9)); // trail + assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! + + let mut string = Wtf8Buf::new(); + string.push(c(0xD83D)); // lead + assert!(!string.is_known_utf8); + string.push(c(0x20)); // not surrogate + string.push(c(0xDCA9)); // trail + assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); + + let mut string = Wtf8Buf::new(); + string.push(c(0xD800)); // lead + assert!(!string.is_known_utf8); + string.push(c(0xDBFF)); // lead + assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); + + let mut string = Wtf8Buf::new(); + string.push(c(0xD800)); // lead + assert!(!string.is_known_utf8); + string.push(c(0xE000)); // not surrogate + assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); + + let mut string = Wtf8Buf::new(); + string.push(c(0xD7FF)); // not surrogate + assert!(string.is_known_utf8); + string.push(c(0xDC00)); // trail + assert!(!string.is_known_utf8); + assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); + + let mut string = Wtf8Buf::new(); + string.push(c(0x61)); // not surrogate, < 3 bytes + assert!(string.is_known_utf8); + string.push(c(0xDC00)); // trail + assert!(!string.is_known_utf8); + assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); + + let mut string = Wtf8Buf::new(); + string.push(c(0xDC00)); // trail + assert!(!string.is_known_utf8); + assert_eq!(string.bytes, b"\xED\xB0\x80"); +} + +#[test] +fn wtf8buf_push_wtf8() { + let mut string = Wtf8Buf::from_str("aé"); + assert_eq!(string.bytes, b"a\xC3\xA9"); + string.push_wtf8(Wtf8::from_str(" 💩")); + assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert!(string.is_known_utf8); + + fn w(v: &[u8]) -> &Wtf8 { + unsafe { Wtf8::from_bytes_unchecked(v) } + } + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\xA0\xBD")); // lead + string.push_wtf8(w(b"\xED\xB2\xA9")); // trail + assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\xA0\xBD")); // lead + string.push_wtf8(w(b" ")); // not surrogate + string.push_wtf8(w(b"\xED\xB2\xA9")); // trail + assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); + assert!(!string.is_known_utf8); + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\xA0\x80")); // lead + string.push_wtf8(w(b"\xED\xAF\xBF")); // lead + assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); + assert!(!string.is_known_utf8); + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\xA0\x80")); // lead + string.push_wtf8(w(b"\xEE\x80\x80")); // not surrogate + assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); + assert!(!string.is_known_utf8); + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\x9F\xBF")); // not surrogate + string.push_wtf8(w(b"\xED\xB0\x80")); // trail + assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); + assert!(!string.is_known_utf8); + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"a")); // not surrogate, < 3 bytes + string.push_wtf8(w(b"\xED\xB0\x80")); // trail + assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); + assert!(!string.is_known_utf8); + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\xB0\x80")); // trail + assert_eq!(string.bytes, b"\xED\xB0\x80"); + assert!(!string.is_known_utf8); +} + +#[test] +fn wtf8buf_truncate() { + let mut string = Wtf8Buf::from_str("aé"); + assert!(string.is_known_utf8); + + string.truncate(3); + assert_eq!(string.bytes, b"a\xC3\xA9"); + assert!(string.is_known_utf8); + + string.truncate(1); + assert_eq!(string.bytes, b"a"); + assert!(string.is_known_utf8); + + string.truncate(0); + assert_eq!(string.bytes, b""); + assert!(string.is_known_utf8); +} + +#[test] +fn wtf8buf_truncate_around_non_bmp() { + let mut string = Wtf8Buf::from_str("💩"); + assert!(string.is_known_utf8); + + string.truncate(4); + assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); + assert!(string.is_known_utf8); + + string.truncate(0); + assert_eq!(string.bytes, b""); + assert!(string.is_known_utf8); +} + +#[test] +#[should_panic] +fn wtf8buf_truncate_fail_code_point_boundary() { + let mut string = Wtf8Buf::from_str("aé"); + string.truncate(2); +} + +#[test] +#[should_panic] +fn wtf8buf_truncate_fail_longer() { + let mut string = Wtf8Buf::from_str("aé"); + string.truncate(4); +} + +#[test] +#[should_panic] +fn wtf8buf_truncate_splitting_non_bmp3() { + let mut string = Wtf8Buf::from_str("💩"); + assert!(string.is_known_utf8); + string.truncate(3); +} + +#[test] +#[should_panic] +fn wtf8buf_truncate_splitting_non_bmp2() { + let mut string = Wtf8Buf::from_str("💩"); + assert!(string.is_known_utf8); + string.truncate(2); +} + +#[test] +#[should_panic] +fn wtf8buf_truncate_splitting_non_bmp1() { + let mut string = Wtf8Buf::from_str("💩"); + assert!(string.is_known_utf8); + string.truncate(1); +} + +#[test] +fn wtf8buf_into_string() { + let mut string = Wtf8Buf::from_str("aé 💩"); + assert!(string.is_known_utf8); + assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩"))); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert!(!string.is_known_utf8); + assert_eq!(string.clone().into_string(), Err(string)); +} + +#[test] +fn wtf8buf_into_string_lossy() { + let mut string = Wtf8Buf::from_str("aé 💩"); + assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩")); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�")); +} + +#[test] +fn wtf8buf_from_iterator() { + fn f(values: &[u32]) -> Wtf8Buf { + values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::() + } + assert_eq!( + f(&[0x61, 0xE9, 0x20, 0x1F4A9]), + Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true } + ); + + assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! + assert_eq!( + f(&[0xD83D, 0x20, 0xDCA9]), + Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false } + ); + assert_eq!( + f(&[0xD800, 0xDBFF]), + Wtf8Buf { bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), is_known_utf8: false } + ); + assert_eq!( + f(&[0xD800, 0xE000]), + Wtf8Buf { bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + f(&[0xD7FF, 0xDC00]), + Wtf8Buf { bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + f(&[0x61, 0xDC00]), + Wtf8Buf { bytes: b"\x61\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!(f(&[0xDC00]), Wtf8Buf { bytes: b"\xED\xB0\x80".to_vec(), is_known_utf8: false }); +} + +#[test] +fn wtf8buf_extend() { + fn e(initial: &[u32], extended: &[u32]) -> Wtf8Buf { + fn c(value: &u32) -> CodePoint { + CodePoint::from_u32(*value).unwrap() + } + let mut string = initial.iter().map(c).collect::(); + string.extend(extended.iter().map(c)); + string + } + + assert_eq!( + e(&[0x61, 0xE9], &[0x20, 0x1F4A9]), + Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true } + ); + + assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! + assert_eq!( + e(&[0xD83D, 0x20], &[0xDCA9]), + Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[0xD800], &[0xDBFF]), + Wtf8Buf { bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[0xD800], &[0xE000]), + Wtf8Buf { bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[0xD7FF], &[0xDC00]), + Wtf8Buf { bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[0x61], &[0xDC00]), + Wtf8Buf { bytes: b"\x61\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[], &[0xDC00]), + Wtf8Buf { bytes: b"\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); +} + +#[test] +fn wtf8buf_show() { + let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r"); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!(format!("{string:?}"), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\""); +} + +#[test] +fn wtf8buf_as_slice() { + assert_eq!(Wtf8Buf::from_str("aé").as_slice(), Wtf8::from_str("aé")); +} + +#[test] +fn wtf8buf_show_str() { + let text = "a\té 💩\r"; + let string = Wtf8Buf::from_str(text); + assert_eq!(format!("{text:?}"), format!("{string:?}")); +} + +#[test] +fn wtf8_from_str() { + assert_eq!(&Wtf8::from_str("").bytes, b""); + assert_eq!(&Wtf8::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +fn wtf8_len() { + assert_eq!(Wtf8::from_str("").len(), 0); + assert_eq!(Wtf8::from_str("aé 💩").len(), 8); +} + +#[test] +fn wtf8_slice() { + assert_eq!(&Wtf8::from_str("aé 💩")[1..4].bytes, b"\xC3\xA9 "); +} + +#[test] +#[should_panic] +fn wtf8_slice_not_code_point_boundary() { + let _ = &Wtf8::from_str("aé 💩")[2..4]; +} + +#[test] +fn wtf8_slice_from() { + assert_eq!(&Wtf8::from_str("aé 💩")[1..].bytes, b"\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +#[should_panic] +fn wtf8_slice_from_not_code_point_boundary() { + let _ = &Wtf8::from_str("aé 💩")[2..]; +} + +#[test] +fn wtf8_slice_to() { + assert_eq!(&Wtf8::from_str("aé 💩")[..4].bytes, b"a\xC3\xA9 "); +} + +#[test] +#[should_panic] +fn wtf8_slice_to_not_code_point_boundary() { + let _ = &Wtf8::from_str("aé 💩")[5..]; +} + +#[test] +fn wtf8_ascii_byte_at() { + let slice = Wtf8::from_str("aé 💩"); + assert_eq!(slice.ascii_byte_at(0), b'a'); + assert_eq!(slice.ascii_byte_at(1), b'\xFF'); + assert_eq!(slice.ascii_byte_at(2), b'\xFF'); + assert_eq!(slice.ascii_byte_at(3), b' '); + assert_eq!(slice.ascii_byte_at(4), b'\xFF'); +} + +#[test] +fn wtf8_code_points() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + fn cp(string: &Wtf8Buf) -> Vec> { + string.code_points().map(|c| c.to_char()).collect::>() + } + let mut string = Wtf8Buf::from_str("é "); + assert_eq!(cp(&string), [Some('é'), Some(' ')]); + string.push(c(0xD83D)); + assert_eq!(cp(&string), [Some('é'), Some(' '), None]); + string.push(c(0xDCA9)); + assert_eq!(cp(&string), [Some('é'), Some(' '), Some('💩')]); +} + +#[test] +fn wtf8_as_str() { + assert_eq!(Wtf8::from_str("").as_str(), Ok("")); + assert_eq!(Wtf8::from_str("aé 💩").as_str(), Ok("aé 💩")); + let mut string = Wtf8Buf::new(); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert!(string.as_str().is_err()); +} + +#[test] +fn wtf8_to_string_lossy() { + assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed("")); + assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩")); + let mut string = Wtf8Buf::from_str("aé 💩"); + string.push(CodePoint::from_u32(0xD800).unwrap()); + let expected: Cow<'_, str> = Cow::Owned(String::from("aé 💩�")); + assert_eq!(string.to_string_lossy(), expected); +} + +#[test] +fn wtf8_display() { + fn d(b: &[u8]) -> String { + (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string() + } + + assert_eq!("", d("".as_bytes())); + assert_eq!("aé 💩", d("aé 💩".as_bytes())); + + let mut string = Wtf8Buf::from_str("aé 💩"); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!("aé 💩�", d(string.as_inner())); +} + +#[test] +fn wtf8_encode_wide() { + let mut string = Wtf8Buf::from_str("aé "); + string.push(CodePoint::from_u32(0xD83D).unwrap()); + string.push_char('💩'); + assert_eq!( + string.encode_wide().collect::>(), + vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9] + ); +} + +#[test] +fn wtf8_encode_wide_size_hint() { + let string = Wtf8Buf::from_str("\u{12345}"); + let mut iter = string.encode_wide(); + assert_eq!((1, Some(8)), iter.size_hint()); + iter.next().unwrap(); + assert_eq!((1, Some(1)), iter.size_hint()); + iter.next().unwrap(); + assert_eq!((0, Some(0)), iter.size_hint()); + assert!(iter.next().is_none()); +} + +#[test] +fn wtf8_clone_into() { + let mut string = Wtf8Buf::new(); + Wtf8::from_str("green").clone_into(&mut string); + assert_eq!(string.bytes, b"green"); + + let mut string = Wtf8Buf::from_str("green"); + Wtf8::from_str("").clone_into(&mut string); + assert_eq!(string.bytes, b""); + + let mut string = Wtf8Buf::from_str("red"); + Wtf8::from_str("green").clone_into(&mut string); + assert_eq!(string.bytes, b"green"); + + let mut string = Wtf8Buf::from_str("green"); + Wtf8::from_str("red").clone_into(&mut string); + assert_eq!(string.bytes, b"red"); + + let mut string = Wtf8Buf::from_str("green"); + assert!(string.is_known_utf8); + unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").clone_into(&mut string) }; + assert_eq!(string.bytes, b"\xED\xA0\x80"); + assert!(!string.is_known_utf8); +} + +#[test] +fn wtf8_to_ascii_lowercase() { + let lowercase = Wtf8::from_str("").to_ascii_lowercase(); + assert_eq!(lowercase.bytes, b""); + + let lowercase = Wtf8::from_str("GrEeN gRaPeS! 🍇").to_ascii_lowercase(); + assert_eq!(lowercase.bytes, b"green grapes! \xf0\x9f\x8d\x87"); + + let lowercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_ascii_lowercase() }; + assert_eq!(lowercase.bytes, b"\xED\xA0\x80"); + assert!(!lowercase.is_known_utf8); +} + +#[test] +fn wtf8_to_ascii_uppercase() { + let uppercase = Wtf8::from_str("").to_ascii_uppercase(); + assert_eq!(uppercase.bytes, b""); + + let uppercase = Wtf8::from_str("GrEeN gRaPeS! 🍇").to_ascii_uppercase(); + assert_eq!(uppercase.bytes, b"GREEN GRAPES! \xf0\x9f\x8d\x87"); + + let uppercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_ascii_uppercase() }; + assert_eq!(uppercase.bytes, b"\xED\xA0\x80"); + assert!(!uppercase.is_known_utf8); +} + +#[test] +fn wtf8_make_ascii_lowercase() { + let mut lowercase = Wtf8Buf::from_str(""); + lowercase.make_ascii_lowercase(); + assert_eq!(lowercase.bytes, b""); + + let mut lowercase = Wtf8Buf::from_str("GrEeN gRaPeS! 🍇"); + lowercase.make_ascii_lowercase(); + assert_eq!(lowercase.bytes, b"green grapes! \xf0\x9f\x8d\x87"); + + let mut lowercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + lowercase.make_ascii_lowercase(); + assert_eq!(lowercase.bytes, b"\xED\xA0\x80"); + assert!(!lowercase.is_known_utf8); +} + +#[test] +fn wtf8_make_ascii_uppercase() { + let mut uppercase = Wtf8Buf::from_str(""); + uppercase.make_ascii_uppercase(); + assert_eq!(uppercase.bytes, b""); + + let mut uppercase = Wtf8Buf::from_str("GrEeN gRaPeS! 🍇"); + uppercase.make_ascii_uppercase(); + assert_eq!(uppercase.bytes, b"GREEN GRAPES! \xf0\x9f\x8d\x87"); + + let mut uppercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + uppercase.make_ascii_uppercase(); + assert_eq!(uppercase.bytes, b"\xED\xA0\x80"); + assert!(!uppercase.is_known_utf8); +} + +#[test] +fn wtf8_to_owned() { + let string = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + assert_eq!(string.bytes, b"\xED\xA0\x80"); + assert!(!string.is_known_utf8); +} + +#[test] +fn wtf8_valid_utf8_boundaries() { + let mut string = Wtf8Buf::from_str("aé 💩"); + string.push(CodePoint::from_u32(0xD800).unwrap()); + string.push(CodePoint::from_u32(0xD800).unwrap()); + check_utf8_boundary(&string, 0); + check_utf8_boundary(&string, 1); + check_utf8_boundary(&string, 3); + check_utf8_boundary(&string, 4); + check_utf8_boundary(&string, 8); + check_utf8_boundary(&string, 14); + assert_eq!(string.len(), 14); + + string.push_char('a'); + check_utf8_boundary(&string, 14); + check_utf8_boundary(&string, 15); + + let mut string = Wtf8Buf::from_str("a"); + string.push(CodePoint::from_u32(0xD800).unwrap()); + check_utf8_boundary(&string, 1); + + let mut string = Wtf8Buf::from_str("\u{D7FF}"); + string.push(CodePoint::from_u32(0xD800).unwrap()); + check_utf8_boundary(&string, 3); + + let mut string = Wtf8Buf::new(); + string.push(CodePoint::from_u32(0xD800).unwrap()); + string.push_char('\u{D7FF}'); + check_utf8_boundary(&string, 3); +} + +#[test] +#[should_panic(expected = "byte index 4 is out of bounds")] +fn wtf8_utf8_boundary_out_of_bounds() { + let string = Wtf8::from_str("aé"); + check_utf8_boundary(&string, 4); +} + +#[test] +#[should_panic(expected = "byte index 1 is not a codepoint boundary")] +fn wtf8_utf8_boundary_inside_codepoint() { + let string = Wtf8::from_str("é"); + check_utf8_boundary(&string, 1); +} + +#[test] +#[should_panic(expected = "byte index 1 is not a codepoint boundary")] +fn wtf8_utf8_boundary_inside_surrogate() { + let mut string = Wtf8Buf::new(); + string.push(CodePoint::from_u32(0xD800).unwrap()); + check_utf8_boundary(&string, 1); +} + +#[test] +#[should_panic(expected = "byte index 3 lies between surrogate codepoints")] +fn wtf8_utf8_boundary_between_surrogates() { + let mut string = Wtf8Buf::new(); + string.push(CodePoint::from_u32(0xD800).unwrap()); + string.push(CodePoint::from_u32(0xD800).unwrap()); + check_utf8_boundary(&string, 3); +} + +#[test] +fn wobbled_wtf8_plus_bytes_isnt_utf8() { + let mut string: Wtf8Buf = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + assert!(!string.is_known_utf8); + string.extend_from_slice(b"some utf-8"); + assert!(!string.is_known_utf8); +} + +#[test] +fn wobbled_wtf8_plus_str_isnt_utf8() { + let mut string: Wtf8Buf = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + assert!(!string.is_known_utf8); + string.push_str("some utf-8"); + assert!(!string.is_known_utf8); +} + +#[test] +fn unwobbly_wtf8_plus_utf8_is_utf8() { + let mut string: Wtf8Buf = Wtf8Buf::from_str("hello world"); + assert!(string.is_known_utf8); + string.push_str("some utf-8"); + assert!(string.is_known_utf8); +} diff --git a/library/core/src/wtf8.rs b/library/core/src/wtf8.rs new file mode 100644 index 00000000000..50bde88b5a4 --- /dev/null +++ b/library/core/src/wtf8.rs @@ -0,0 +1,1083 @@ +//! Implementation of [the WTF-8 encoding](https://simonsapin.github.io/wtf-8/). +//! +//! This library uses Rust’s type system to maintain +//! [well-formedness](https://simonsapin.github.io/wtf-8/#well-formed), +//! like the `String` and `&str` types do for UTF-8. +//! +//! Since [WTF-8 must not be used +//! for interchange](https://simonsapin.github.io/wtf-8/#intended-audience), +//! this library deliberately does not provide access to the underlying bytes +//! of WTF-8 strings, +//! nor can it decode WTF-8 from arbitrary bytes. +//! WTF-8 strings can be obtained from UTF-8, UTF-16, or code points. + +// this module is imported from @SimonSapin's repo and has tons of dead code on +// unix (it's mostly used on windows), so don't worry about dead code here. +#![allow(dead_code)] + +#[cfg(test)] +mod tests; + +use core::char::{MAX_LEN_UTF8, MAX_LEN_UTF16, encode_utf8_raw, encode_utf16_raw}; +use core::clone::CloneToUninit; +use core::str::next_code_point; + +use crate::borrow::Cow; +use crate::collections::TryReserveError; +use crate::hash::{Hash, Hasher}; +use crate::iter::FusedIterator; +use crate::rc::Rc; +use crate::sync::Arc; +use crate::sys_common::AsInner; +use crate::{fmt, mem, ops, slice, str}; + +const UTF8_REPLACEMENT_CHARACTER: &str = "\u{FFFD}"; + +/// A Unicode code point: from U+0000 to U+10FFFF. +/// +/// Compares with the `char` type, +/// which represents a Unicode scalar value: +/// a code point that is not a surrogate (U+D800 to U+DFFF). +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] +pub struct CodePoint { + value: u32, +} + +/// Format the code point as `U+` followed by four to six hexadecimal digits. +/// Example: `U+1F4A9` +impl fmt::Debug for CodePoint { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(formatter, "U+{:04X}", self.value) + } +} + +impl CodePoint { + /// Unsafely creates a new `CodePoint` without checking the value. + /// + /// Only use when `value` is known to be less than or equal to 0x10FFFF. + #[inline] + pub unsafe fn from_u32_unchecked(value: u32) -> CodePoint { + CodePoint { value } + } + + /// Creates a new `CodePoint` if the value is a valid code point. + /// + /// Returns `None` if `value` is above 0x10FFFF. + #[inline] + pub fn from_u32(value: u32) -> Option { + match value { + 0..=0x10FFFF => Some(CodePoint { value }), + _ => None, + } + } + + /// Creates a new `CodePoint` from a `char`. + /// + /// Since all Unicode scalar values are code points, this always succeeds. + #[inline] + pub fn from_char(value: char) -> CodePoint { + CodePoint { value: value as u32 } + } + + /// Returns the numeric value of the code point. + #[inline] + pub fn to_u32(&self) -> u32 { + self.value + } + + /// Returns the numeric value of the code point if it is a leading surrogate. + #[inline] + pub fn to_lead_surrogate(&self) -> Option { + match self.value { + lead @ 0xD800..=0xDBFF => Some(lead as u16), + _ => None, + } + } + + /// Returns the numeric value of the code point if it is a trailing surrogate. + #[inline] + pub fn to_trail_surrogate(&self) -> Option { + match self.value { + trail @ 0xDC00..=0xDFFF => Some(trail as u16), + _ => None, + } + } + + /// Optionally returns a Unicode scalar value for the code point. + /// + /// Returns `None` if the code point is a surrogate (from U+D800 to U+DFFF). + #[inline] + pub fn to_char(&self) -> Option { + match self.value { + 0xD800..=0xDFFF => None, + _ => Some(unsafe { char::from_u32_unchecked(self.value) }), + } + } + + /// Returns a Unicode scalar value for the code point. + /// + /// Returns `'\u{FFFD}'` (the replacement character “�”) + /// if the code point is a surrogate (from U+D800 to U+DFFF). + #[inline] + pub fn to_char_lossy(&self) -> char { + self.to_char().unwrap_or('\u{FFFD}') + } +} + +/// An owned, growable string of well-formed WTF-8 data. +/// +/// Similar to `String`, but can additionally contain surrogate code points +/// if they’re not in a surrogate pair. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone)] +pub struct Wtf8Buf { + bytes: Vec, + + /// Do we know that `bytes` holds a valid UTF-8 encoding? We can easily + /// know this if we're constructed from a `String` or `&str`. + /// + /// It is possible for `bytes` to have valid UTF-8 without this being + /// set, such as when we're concatenating `&Wtf8`'s and surrogates become + /// paired, as we don't bother to rescan the entire string. + is_known_utf8: bool, +} + +impl ops::Deref for Wtf8Buf { + type Target = Wtf8; + + fn deref(&self) -> &Wtf8 { + self.as_slice() + } +} + +impl ops::DerefMut for Wtf8Buf { + fn deref_mut(&mut self) -> &mut Wtf8 { + self.as_mut_slice() + } +} + +/// Formats the string in double quotes, with characters escaped according to +/// [`char::escape_debug`] and unpaired surrogates represented as `\u{xxxx}`, +/// where each `x` is a hexadecimal digit. +/// +/// For example, the code units [U+0061, U+D800, U+000A] are formatted as +/// `"a\u{D800}\n"`. +impl fmt::Debug for Wtf8Buf { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, formatter) + } +} + +/// Formats the string with unpaired surrogates substituted with the replacement +/// character, U+FFFD. +impl fmt::Display for Wtf8Buf { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(s) = self.as_known_utf8() { + fmt::Display::fmt(s, formatter) + } else { + fmt::Display::fmt(&**self, formatter) + } + } +} + +impl Wtf8Buf { + /// Creates a new, empty WTF-8 string. + #[inline] + pub fn new() -> Wtf8Buf { + Wtf8Buf { bytes: Vec::new(), is_known_utf8: true } + } + + /// Creates a new, empty WTF-8 string with pre-allocated capacity for `capacity` bytes. + #[inline] + pub fn with_capacity(capacity: usize) -> Wtf8Buf { + Wtf8Buf { bytes: Vec::with_capacity(capacity), is_known_utf8: true } + } + + /// Creates a WTF-8 string from a WTF-8 byte vec. + /// + /// Since the byte vec is not checked for valid WTF-8, this function is + /// marked unsafe. + #[inline] + pub unsafe fn from_bytes_unchecked(value: Vec) -> Wtf8Buf { + Wtf8Buf { bytes: value, is_known_utf8: false } + } + + /// Creates a WTF-8 string from a UTF-8 `String`. + /// + /// This takes ownership of the `String` and does not copy. + /// + /// Since WTF-8 is a superset of UTF-8, this always succeeds. + #[inline] + pub const fn from_string(string: String) -> Wtf8Buf { + Wtf8Buf { bytes: string.into_bytes(), is_known_utf8: true } + } + + /// Creates a WTF-8 string from a UTF-8 `&str` slice. + /// + /// This copies the content of the slice. + /// + /// Since WTF-8 is a superset of UTF-8, this always succeeds. + #[inline] + pub fn from_str(s: &str) -> Wtf8Buf { + Wtf8Buf { bytes: s.as_bytes().to_vec(), is_known_utf8: true } + } + + pub fn clear(&mut self) { + self.bytes.clear(); + self.is_known_utf8 = true; + } + + /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units. + /// + /// This is lossless: calling `.encode_wide()` on the resulting string + /// will always return the original code units. + pub fn from_wide(v: &[u16]) -> Wtf8Buf { + let mut string = Wtf8Buf::with_capacity(v.len()); + for item in char::decode_utf16(v.iter().cloned()) { + match item { + Ok(ch) => string.push_char(ch), + Err(surrogate) => { + let surrogate = surrogate.unpaired_surrogate(); + // Surrogates are known to be in the code point range. + let code_point = unsafe { CodePoint::from_u32_unchecked(surrogate as u32) }; + // The string will now contain an unpaired surrogate. + string.is_known_utf8 = false; + // Skip the WTF-8 concatenation check, + // surrogate pairs are already decoded by decode_utf16 + string.push_code_point_unchecked(code_point); + } + } + } + string + } + + /// Appends the given `char` to the end of this string. + /// This does **not** include the WTF-8 concatenation check or `is_known_utf8` check. + /// Copied from String::push. + fn push_code_point_unchecked(&mut self, code_point: CodePoint) { + let mut bytes = [0; MAX_LEN_UTF8]; + let bytes = encode_utf8_raw(code_point.value, &mut bytes); + self.bytes.extend_from_slice(bytes) + } + + #[inline] + pub fn as_slice(&self) -> &Wtf8 { + unsafe { Wtf8::from_bytes_unchecked(&self.bytes) } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut Wtf8 { + // Safety: `Wtf8` doesn't expose any way to mutate the bytes that would + // cause them to change from well-formed UTF-8 to ill-formed UTF-8, + // which would break the assumptions of the `is_known_utf8` field. + unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) } + } + + /// Converts the string to UTF-8 without validation, if it was created from + /// valid UTF-8. + #[inline] + fn as_known_utf8(&self) -> Option<&str> { + if self.is_known_utf8 { + // SAFETY: The buffer is known to be valid UTF-8. + Some(unsafe { str::from_utf8_unchecked(self.as_bytes()) }) + } else { + None + } + } + + /// Reserves capacity for at least `additional` more bytes to be inserted + /// in the given `Wtf8Buf`. + /// The collection may reserve more space to avoid frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.bytes.reserve(additional) + } + + /// Tries to reserve capacity for at least `additional` more bytes to be + /// inserted in the given `Wtf8Buf`. The `Wtf8Buf` may reserve more space to + /// avoid frequent reallocations. After calling `try_reserve`, capacity will + /// be greater than or equal to `self.len() + additional`. Does nothing if + /// capacity is already sufficient. This method preserves the contents even + /// if an error occurs. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + #[inline] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.bytes.try_reserve(additional) + } + + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.bytes.reserve_exact(additional) + } + + /// Tries to reserve the minimum capacity for exactly `additional` more + /// bytes to be inserted in the given `Wtf8Buf`. After calling + /// `try_reserve_exact`, capacity will be greater than or equal to + /// `self.len() + additional` if it returns `Ok(())`. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the `Wtf8Buf` more space than it + /// requests. Therefore, capacity can not be relied upon to be precisely + /// minimal. Prefer [`try_reserve`] if future insertions are expected. + /// + /// [`try_reserve`]: Wtf8Buf::try_reserve + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + #[inline] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.bytes.try_reserve_exact(additional) + } + + #[inline] + pub fn shrink_to_fit(&mut self) { + self.bytes.shrink_to_fit() + } + + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.bytes.shrink_to(min_capacity) + } + + #[inline] + pub fn leak<'a>(self) -> &'a mut Wtf8 { + unsafe { Wtf8::from_mut_bytes_unchecked(self.bytes.leak()) } + } + + /// Returns the number of bytes that this string buffer can hold without reallocating. + #[inline] + pub fn capacity(&self) -> usize { + self.bytes.capacity() + } + + /// Append a UTF-8 slice at the end of the string. + #[inline] + pub fn push_str(&mut self, other: &str) { + self.bytes.extend_from_slice(other.as_bytes()) + } + + /// Append a WTF-8 slice at the end of the string. + /// + /// This replaces newly paired surrogates at the boundary + /// with a supplementary code point, + /// like concatenating ill-formed UTF-16 strings effectively would. + #[inline] + pub fn push_wtf8(&mut self, other: &Wtf8) { + match ((&*self).final_lead_surrogate(), other.initial_trail_surrogate()) { + // Replace newly paired surrogates by a supplementary code point. + (Some(lead), Some(trail)) => { + let len_without_lead_surrogate = self.len() - 3; + self.bytes.truncate(len_without_lead_surrogate); + let other_without_trail_surrogate = &other.bytes[3..]; + // 4 bytes for the supplementary code point + self.bytes.reserve(4 + other_without_trail_surrogate.len()); + self.push_char(decode_surrogate_pair(lead, trail)); + self.bytes.extend_from_slice(other_without_trail_surrogate); + } + _ => { + // If we'll be pushing a string containing a surrogate, we may + // no longer have UTF-8. + if self.is_known_utf8 && other.next_surrogate(0).is_some() { + self.is_known_utf8 = false; + } + + self.bytes.extend_from_slice(&other.bytes); + } + } + } + + /// Append a Unicode scalar value at the end of the string. + #[inline] + pub fn push_char(&mut self, c: char) { + self.push_code_point_unchecked(CodePoint::from_char(c)) + } + + /// Append a code point at the end of the string. + /// + /// This replaces newly paired surrogates at the boundary + /// with a supplementary code point, + /// like concatenating ill-formed UTF-16 strings effectively would. + #[inline] + pub fn push(&mut self, code_point: CodePoint) { + if let Some(trail) = code_point.to_trail_surrogate() { + if let Some(lead) = (&*self).final_lead_surrogate() { + let len_without_lead_surrogate = self.len() - 3; + self.bytes.truncate(len_without_lead_surrogate); + self.push_char(decode_surrogate_pair(lead, trail)); + return; + } + + // We're pushing a trailing surrogate. + self.is_known_utf8 = false; + } else if code_point.to_lead_surrogate().is_some() { + // We're pushing a leading surrogate. + self.is_known_utf8 = false; + } + + // No newly paired surrogates at the boundary. + self.push_code_point_unchecked(code_point) + } + + /// Shortens a string to the specified length. + /// + /// # Panics + /// + /// Panics if `new_len` > current length, + /// or if `new_len` is not a code point boundary. + #[inline] + pub fn truncate(&mut self, new_len: usize) { + assert!(is_code_point_boundary(self, new_len)); + self.bytes.truncate(new_len) + } + + /// Consumes the WTF-8 string and tries to convert it to a vec of bytes. + #[inline] + pub fn into_bytes(self) -> Vec { + self.bytes + } + + /// Consumes the WTF-8 string and tries to convert it to UTF-8. + /// + /// This does not copy the data. + /// + /// If the contents are not well-formed UTF-8 + /// (that is, if the string contains surrogates), + /// the original WTF-8 string is returned instead. + pub fn into_string(self) -> Result { + if self.is_known_utf8 || self.next_surrogate(0).is_none() { + Ok(unsafe { String::from_utf8_unchecked(self.bytes) }) + } else { + Err(self) + } + } + + /// Consumes the WTF-8 string and converts it lossily to UTF-8. + /// + /// This does not copy the data (but may overwrite parts of it in place). + /// + /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”) + pub fn into_string_lossy(mut self) -> String { + if !self.is_known_utf8 { + let mut pos = 0; + while let Some((surrogate_pos, _)) = self.next_surrogate(pos) { + pos = surrogate_pos + 3; + // Surrogates and the replacement character are all 3 bytes, so + // they can substituted in-place. + self.bytes[surrogate_pos..pos] + .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); + } + } + unsafe { String::from_utf8_unchecked(self.bytes) } + } + + /// Converts this `Wtf8Buf` into a boxed `Wtf8`. + #[inline] + pub fn into_box(self) -> Box { + // SAFETY: relies on `Wtf8` being `repr(transparent)`. + unsafe { mem::transmute(self.bytes.into_boxed_slice()) } + } + + /// Converts a `Box` into a `Wtf8Buf`. + pub fn from_box(boxed: Box) -> Wtf8Buf { + let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) }; + Wtf8Buf { bytes: bytes.into_vec(), is_known_utf8: false } + } + + /// Provides plumbing to core `Vec::extend_from_slice`. + /// More well behaving alternative to allowing outer types + /// full mutable access to the core `Vec`. + #[inline] + pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { + self.bytes.extend_from_slice(other); + self.is_known_utf8 = false; + } +} + +/// Creates a new WTF-8 string from an iterator of code points. +/// +/// This replaces surrogate code point pairs with supplementary code points, +/// like concatenating ill-formed UTF-16 strings effectively would. +impl FromIterator for Wtf8Buf { + fn from_iter>(iter: T) -> Wtf8Buf { + let mut string = Wtf8Buf::new(); + string.extend(iter); + string + } +} + +/// Append code points from an iterator to the string. +/// +/// This replaces surrogate code point pairs with supplementary code points, +/// like concatenating ill-formed UTF-16 strings effectively would. +impl Extend for Wtf8Buf { + fn extend>(&mut self, iter: T) { + let iterator = iter.into_iter(); + let (low, _high) = iterator.size_hint(); + // Lower bound of one byte per code point (ASCII only) + self.bytes.reserve(low); + iterator.for_each(move |code_point| self.push(code_point)); + } + + #[inline] + fn extend_one(&mut self, code_point: CodePoint) { + self.push(code_point); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + // Lower bound of one byte per code point (ASCII only) + self.bytes.reserve(additional); + } +} + +/// A borrowed slice of well-formed WTF-8 data. +/// +/// Similar to `&str`, but can additionally contain surrogate code points +/// if they’re not in a surrogate pair. +#[derive(Eq, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct Wtf8 { + bytes: [u8], +} + +impl AsInner<[u8]> for Wtf8 { + #[inline] + fn as_inner(&self) -> &[u8] { + &self.bytes + } +} + +/// Formats the string in double quotes, with characters escaped according to +/// [`char::escape_debug`] and unpaired surrogates represented as `\u{xxxx}`, +/// where each `x` is a hexadecimal digit. +impl fmt::Debug for Wtf8 { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fn write_str_escaped(f: &mut fmt::Formatter<'_>, s: &str) -> fmt::Result { + use crate::fmt::Write; + for c in s.chars().flat_map(|c| c.escape_debug()) { + f.write_char(c)? + } + Ok(()) + } + + formatter.write_str("\"")?; + let mut pos = 0; + while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) { + write_str_escaped(formatter, unsafe { + str::from_utf8_unchecked(&self.bytes[pos..surrogate_pos]) + })?; + write!(formatter, "\\u{{{:x}}}", surrogate)?; + pos = surrogate_pos + 3; + } + write_str_escaped(formatter, unsafe { str::from_utf8_unchecked(&self.bytes[pos..]) })?; + formatter.write_str("\"") + } +} + +/// Formats the string with unpaired surrogates substituted with the replacement +/// character, U+FFFD. +impl fmt::Display for Wtf8 { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + let wtf8_bytes = &self.bytes; + let mut pos = 0; + loop { + match self.next_surrogate(pos) { + Some((surrogate_pos, _)) => { + formatter.write_str(unsafe { + str::from_utf8_unchecked(&wtf8_bytes[pos..surrogate_pos]) + })?; + formatter.write_str(UTF8_REPLACEMENT_CHARACTER)?; + pos = surrogate_pos + 3; + } + None => { + let s = unsafe { str::from_utf8_unchecked(&wtf8_bytes[pos..]) }; + if pos == 0 { return s.fmt(formatter) } else { return formatter.write_str(s) } + } + } + } + } +} + +impl Wtf8 { + /// Creates a WTF-8 slice from a UTF-8 `&str` slice. + /// + /// Since WTF-8 is a superset of UTF-8, this always succeeds. + #[inline] + pub fn from_str(value: &str) -> &Wtf8 { + unsafe { Wtf8::from_bytes_unchecked(value.as_bytes()) } + } + + /// Creates a WTF-8 slice from a WTF-8 byte slice. + /// + /// Since the byte slice is not checked for valid WTF-8, this functions is + /// marked unsafe. + #[inline] + pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { + // SAFETY: start with &[u8], end with fancy &[u8] + unsafe { &*(value as *const [u8] as *const Wtf8) } + } + + /// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice. + /// + /// Since the byte slice is not checked for valid WTF-8, this functions is + /// marked unsafe. + #[inline] + unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 { + // SAFETY: start with &mut [u8], end with fancy &mut [u8] + unsafe { &mut *(value as *mut [u8] as *mut Wtf8) } + } + + /// Returns the length, in WTF-8 bytes. + #[inline] + pub fn len(&self) -> usize { + self.bytes.len() + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.bytes.is_empty() + } + + /// Returns the code point at `position` if it is in the ASCII range, + /// or `b'\xFF'` otherwise. + /// + /// # Panics + /// + /// Panics if `position` is beyond the end of the string. + #[inline] + pub fn ascii_byte_at(&self, position: usize) -> u8 { + match self.bytes[position] { + ascii_byte @ 0x00..=0x7F => ascii_byte, + _ => 0xFF, + } + } + + /// Returns an iterator for the string’s code points. + #[inline] + pub fn code_points(&self) -> Wtf8CodePoints<'_> { + Wtf8CodePoints { bytes: self.bytes.iter() } + } + + /// Access raw bytes of WTF-8 data + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.bytes + } + + /// Tries to convert the string to UTF-8 and return a `&str` slice. + /// + /// Returns `None` if the string contains surrogates. + /// + /// This does not copy the data. + #[inline] + pub fn as_str(&self) -> Result<&str, str::Utf8Error> { + str::from_utf8(&self.bytes) + } + + /// Creates an owned `Wtf8Buf` from a borrowed `Wtf8`. + pub fn to_owned(&self) -> Wtf8Buf { + Wtf8Buf { bytes: self.bytes.to_vec(), is_known_utf8: false } + } + + /// Lossily converts the string to UTF-8. + /// Returns a UTF-8 `&str` slice if the contents are well-formed in UTF-8. + /// + /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”). + /// + /// This only copies the data if necessary (if it contains any surrogate). + pub fn to_string_lossy(&self) -> Cow<'_, str> { + let Some((surrogate_pos, _)) = self.next_surrogate(0) else { + return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }); + }; + let wtf8_bytes = &self.bytes; + let mut utf8_bytes = Vec::with_capacity(self.len()); + utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]); + utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); + let mut pos = surrogate_pos + 3; + loop { + match self.next_surrogate(pos) { + Some((surrogate_pos, _)) => { + utf8_bytes.extend_from_slice(&wtf8_bytes[pos..surrogate_pos]); + utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); + pos = surrogate_pos + 3; + } + None => { + utf8_bytes.extend_from_slice(&wtf8_bytes[pos..]); + return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) }); + } + } + } + } + + /// Converts the WTF-8 string to potentially ill-formed UTF-16 + /// and return an iterator of 16-bit code units. + /// + /// This is lossless: + /// calling `Wtf8Buf::from_ill_formed_utf16` on the resulting code units + /// would always return the original WTF-8 string. + #[inline] + pub fn encode_wide(&self) -> EncodeWide<'_> { + EncodeWide { code_points: self.code_points(), extra: 0 } + } + + #[inline] + fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> { + let mut iter = self.bytes[pos..].iter(); + loop { + let b = *iter.next()?; + if b < 0x80 { + pos += 1; + } else if b < 0xE0 { + iter.next(); + pos += 2; + } else if b == 0xED { + match (iter.next(), iter.next()) { + (Some(&b2), Some(&b3)) if b2 >= 0xA0 => { + return Some((pos, decode_surrogate(b2, b3))); + } + _ => pos += 3, + } + } else if b < 0xF0 { + iter.next(); + iter.next(); + pos += 3; + } else { + iter.next(); + iter.next(); + iter.next(); + pos += 4; + } + } + } + + #[inline] + fn final_lead_surrogate(&self) -> Option { + match self.bytes { + [.., 0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)), + _ => None, + } + } + + #[inline] + fn initial_trail_surrogate(&self) -> Option { + match self.bytes { + [0xED, b2 @ 0xB0..=0xBF, b3, ..] => Some(decode_surrogate(b2, b3)), + _ => None, + } + } + + pub fn clone_into(&self, buf: &mut Wtf8Buf) { + buf.is_known_utf8 = false; + self.bytes.clone_into(&mut buf.bytes); + } + + /// Boxes this `Wtf8`. + #[inline] + pub fn into_box(&self) -> Box { + let boxed: Box<[u8]> = self.bytes.into(); + unsafe { mem::transmute(boxed) } + } + + /// Creates a boxed, empty `Wtf8`. + pub fn empty_box() -> Box { + let boxed: Box<[u8]> = Default::default(); + unsafe { mem::transmute(boxed) } + } + + #[inline] + pub fn into_arc(&self) -> Arc { + let arc: Arc<[u8]> = Arc::from(&self.bytes); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Wtf8) } + } + + #[inline] + pub fn into_rc(&self) -> Rc { + let rc: Rc<[u8]> = Rc::from(&self.bytes); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Wtf8) } + } + + #[inline] + pub fn make_ascii_lowercase(&mut self) { + self.bytes.make_ascii_lowercase() + } + + #[inline] + pub fn make_ascii_uppercase(&mut self) { + self.bytes.make_ascii_uppercase() + } + + #[inline] + pub fn to_ascii_lowercase(&self) -> Wtf8Buf { + Wtf8Buf { bytes: self.bytes.to_ascii_lowercase(), is_known_utf8: false } + } + + #[inline] + pub fn to_ascii_uppercase(&self) -> Wtf8Buf { + Wtf8Buf { bytes: self.bytes.to_ascii_uppercase(), is_known_utf8: false } + } + + #[inline] + pub fn is_ascii(&self) -> bool { + self.bytes.is_ascii() + } + + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { + self.bytes.eq_ignore_ascii_case(&other.bytes) + } +} + +/// Returns a slice of the given string for the byte range \[`begin`..`end`). +/// +/// # Panics +/// +/// Panics when `begin` and `end` do not point to code point boundaries, +/// or point beyond the end of the string. +impl ops::Index> for Wtf8 { + type Output = Wtf8; + + #[inline] + fn index(&self, range: ops::Range) -> &Wtf8 { + // is_code_point_boundary checks that the index is in [0, .len()] + if range.start <= range.end + && is_code_point_boundary(self, range.start) + && is_code_point_boundary(self, range.end) + { + unsafe { slice_unchecked(self, range.start, range.end) } + } else { + slice_error_fail(self, range.start, range.end) + } + } +} + +/// Returns a slice of the given string from byte `begin` to its end. +/// +/// # Panics +/// +/// Panics when `begin` is not at a code point boundary, +/// or is beyond the end of the string. +impl ops::Index> for Wtf8 { + type Output = Wtf8; + + #[inline] + fn index(&self, range: ops::RangeFrom) -> &Wtf8 { + // is_code_point_boundary checks that the index is in [0, .len()] + if is_code_point_boundary(self, range.start) { + unsafe { slice_unchecked(self, range.start, self.len()) } + } else { + slice_error_fail(self, range.start, self.len()) + } + } +} + +/// Returns a slice of the given string from its beginning to byte `end`. +/// +/// # Panics +/// +/// Panics when `end` is not at a code point boundary, +/// or is beyond the end of the string. +impl ops::Index> for Wtf8 { + type Output = Wtf8; + + #[inline] + fn index(&self, range: ops::RangeTo) -> &Wtf8 { + // is_code_point_boundary checks that the index is in [0, .len()] + if is_code_point_boundary(self, range.end) { + unsafe { slice_unchecked(self, 0, range.end) } + } else { + slice_error_fail(self, 0, range.end) + } + } +} + +impl ops::Index for Wtf8 { + type Output = Wtf8; + + #[inline] + fn index(&self, _range: ops::RangeFull) -> &Wtf8 { + self + } +} + +#[inline] +fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 { + // The first byte is assumed to be 0xED + 0xD800 | (second_byte as u16 & 0x3F) << 6 | third_byte as u16 & 0x3F +} + +#[inline] +fn decode_surrogate_pair(lead: u16, trail: u16) -> char { + let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32); + unsafe { char::from_u32_unchecked(code_point) } +} + +/// Copied from str::is_char_boundary +#[inline] +pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool { + if index == 0 { + return true; + } + match slice.bytes.get(index) { + None => index == slice.len(), + Some(&b) => (b as i8) >= -0x40, + } +} + +/// Verify that `index` is at the edge of either a valid UTF-8 codepoint +/// (i.e. a codepoint that's not a surrogate) or of the whole string. +/// +/// These are the cases currently permitted by `OsStr::slice_encoded_bytes`. +/// Splitting between surrogates is valid as far as WTF-8 is concerned, but +/// we do not permit it in the public API because WTF-8 is considered an +/// implementation detail. +#[track_caller] +#[inline] +pub fn check_utf8_boundary(slice: &Wtf8, index: usize) { + if index == 0 { + return; + } + match slice.bytes.get(index) { + Some(0xED) => (), // Might be a surrogate + Some(&b) if (b as i8) >= -0x40 => return, + Some(_) => panic!("byte index {index} is not a codepoint boundary"), + None if index == slice.len() => return, + None => panic!("byte index {index} is out of bounds"), + } + if slice.bytes[index + 1] >= 0xA0 { + // There's a surrogate after index. Now check before index. + if index >= 3 && slice.bytes[index - 3] == 0xED && slice.bytes[index - 2] >= 0xA0 { + panic!("byte index {index} lies between surrogate codepoints"); + } + } +} + +/// Copied from core::str::raw::slice_unchecked +#[inline] +pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { + // SAFETY: memory layout of a &[u8] and &Wtf8 are the same + unsafe { + let len = end - begin; + let start = s.as_bytes().as_ptr().add(begin); + Wtf8::from_bytes_unchecked(slice::from_raw_parts(start, len)) + } +} + +/// Copied from core::str::raw::slice_error_fail +#[inline(never)] +pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! { + assert!(begin <= end); + panic!("index {begin} and/or {end} in `{s:?}` do not lie on character boundary"); +} + +/// Iterator for the code points of a WTF-8 string. +/// +/// Created with the method `.code_points()`. +#[derive(Clone)] +pub struct Wtf8CodePoints<'a> { + bytes: slice::Iter<'a, u8>, +} + +impl Iterator for Wtf8CodePoints<'_> { + type Item = CodePoint; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: `self.bytes` has been created from a WTF-8 string + unsafe { next_code_point(&mut self.bytes).map(|c| CodePoint { value: c }) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.bytes.len(); + (len.saturating_add(3) / 4, Some(len)) + } +} + +/// Generates a wide character sequence for potentially ill-formed UTF-16. +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct EncodeWide<'a> { + code_points: Wtf8CodePoints<'a>, + extra: u16, +} + +// Copied from libunicode/u_str.rs +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for EncodeWide<'_> { + type Item = u16; + + #[inline] + fn next(&mut self) -> Option { + if self.extra != 0 { + let tmp = self.extra; + self.extra = 0; + return Some(tmp); + } + + let mut buf = [0; MAX_LEN_UTF16]; + self.code_points.next().map(|code_point| { + let n = encode_utf16_raw(code_point.value, &mut buf).len(); + if n == 2 { + self.extra = buf[1]; + } + buf[0] + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (low, high) = self.code_points.size_hint(); + let ext = (self.extra != 0) as usize; + // every code point gets either one u16 or two u16, + // so this iterator is between 1 or 2 times as + // long as the underlying iterator. + (low + ext, high.and_then(|n| n.checked_mul(2)).and_then(|n| n.checked_add(ext))) + } +} + +#[stable(feature = "encode_wide_fused_iterator", since = "1.62.0")] +impl FusedIterator for EncodeWide<'_> {} + +impl Hash for CodePoint { + #[inline] + fn hash(&self, state: &mut H) { + self.value.hash(state) + } +} + +impl Hash for Wtf8Buf { + #[inline] + fn hash(&self, state: &mut H) { + state.write(&self.bytes); + 0xfeu8.hash(state) + } +} + +impl Hash for Wtf8 { + #[inline] + fn hash(&self, state: &mut H) { + state.write(&self.bytes); + 0xfeu8.hash(state) + } +} + +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl CloneToUninit for Wtf8 { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: we're just a transparent wrapper around [u8] + unsafe { self.bytes.clone_to_uninit(dst) } + } +} diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs deleted file mode 100644 index 50bde88b5a4..00000000000 --- a/library/std/src/sys_common/wtf8.rs +++ /dev/null @@ -1,1083 +0,0 @@ -//! Implementation of [the WTF-8 encoding](https://simonsapin.github.io/wtf-8/). -//! -//! This library uses Rust’s type system to maintain -//! [well-formedness](https://simonsapin.github.io/wtf-8/#well-formed), -//! like the `String` and `&str` types do for UTF-8. -//! -//! Since [WTF-8 must not be used -//! for interchange](https://simonsapin.github.io/wtf-8/#intended-audience), -//! this library deliberately does not provide access to the underlying bytes -//! of WTF-8 strings, -//! nor can it decode WTF-8 from arbitrary bytes. -//! WTF-8 strings can be obtained from UTF-8, UTF-16, or code points. - -// this module is imported from @SimonSapin's repo and has tons of dead code on -// unix (it's mostly used on windows), so don't worry about dead code here. -#![allow(dead_code)] - -#[cfg(test)] -mod tests; - -use core::char::{MAX_LEN_UTF8, MAX_LEN_UTF16, encode_utf8_raw, encode_utf16_raw}; -use core::clone::CloneToUninit; -use core::str::next_code_point; - -use crate::borrow::Cow; -use crate::collections::TryReserveError; -use crate::hash::{Hash, Hasher}; -use crate::iter::FusedIterator; -use crate::rc::Rc; -use crate::sync::Arc; -use crate::sys_common::AsInner; -use crate::{fmt, mem, ops, slice, str}; - -const UTF8_REPLACEMENT_CHARACTER: &str = "\u{FFFD}"; - -/// A Unicode code point: from U+0000 to U+10FFFF. -/// -/// Compares with the `char` type, -/// which represents a Unicode scalar value: -/// a code point that is not a surrogate (U+D800 to U+DFFF). -#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] -pub struct CodePoint { - value: u32, -} - -/// Format the code point as `U+` followed by four to six hexadecimal digits. -/// Example: `U+1F4A9` -impl fmt::Debug for CodePoint { - #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "U+{:04X}", self.value) - } -} - -impl CodePoint { - /// Unsafely creates a new `CodePoint` without checking the value. - /// - /// Only use when `value` is known to be less than or equal to 0x10FFFF. - #[inline] - pub unsafe fn from_u32_unchecked(value: u32) -> CodePoint { - CodePoint { value } - } - - /// Creates a new `CodePoint` if the value is a valid code point. - /// - /// Returns `None` if `value` is above 0x10FFFF. - #[inline] - pub fn from_u32(value: u32) -> Option { - match value { - 0..=0x10FFFF => Some(CodePoint { value }), - _ => None, - } - } - - /// Creates a new `CodePoint` from a `char`. - /// - /// Since all Unicode scalar values are code points, this always succeeds. - #[inline] - pub fn from_char(value: char) -> CodePoint { - CodePoint { value: value as u32 } - } - - /// Returns the numeric value of the code point. - #[inline] - pub fn to_u32(&self) -> u32 { - self.value - } - - /// Returns the numeric value of the code point if it is a leading surrogate. - #[inline] - pub fn to_lead_surrogate(&self) -> Option { - match self.value { - lead @ 0xD800..=0xDBFF => Some(lead as u16), - _ => None, - } - } - - /// Returns the numeric value of the code point if it is a trailing surrogate. - #[inline] - pub fn to_trail_surrogate(&self) -> Option { - match self.value { - trail @ 0xDC00..=0xDFFF => Some(trail as u16), - _ => None, - } - } - - /// Optionally returns a Unicode scalar value for the code point. - /// - /// Returns `None` if the code point is a surrogate (from U+D800 to U+DFFF). - #[inline] - pub fn to_char(&self) -> Option { - match self.value { - 0xD800..=0xDFFF => None, - _ => Some(unsafe { char::from_u32_unchecked(self.value) }), - } - } - - /// Returns a Unicode scalar value for the code point. - /// - /// Returns `'\u{FFFD}'` (the replacement character “�”) - /// if the code point is a surrogate (from U+D800 to U+DFFF). - #[inline] - pub fn to_char_lossy(&self) -> char { - self.to_char().unwrap_or('\u{FFFD}') - } -} - -/// An owned, growable string of well-formed WTF-8 data. -/// -/// Similar to `String`, but can additionally contain surrogate code points -/// if they’re not in a surrogate pair. -#[derive(Eq, PartialEq, Ord, PartialOrd, Clone)] -pub struct Wtf8Buf { - bytes: Vec, - - /// Do we know that `bytes` holds a valid UTF-8 encoding? We can easily - /// know this if we're constructed from a `String` or `&str`. - /// - /// It is possible for `bytes` to have valid UTF-8 without this being - /// set, such as when we're concatenating `&Wtf8`'s and surrogates become - /// paired, as we don't bother to rescan the entire string. - is_known_utf8: bool, -} - -impl ops::Deref for Wtf8Buf { - type Target = Wtf8; - - fn deref(&self) -> &Wtf8 { - self.as_slice() - } -} - -impl ops::DerefMut for Wtf8Buf { - fn deref_mut(&mut self) -> &mut Wtf8 { - self.as_mut_slice() - } -} - -/// Formats the string in double quotes, with characters escaped according to -/// [`char::escape_debug`] and unpaired surrogates represented as `\u{xxxx}`, -/// where each `x` is a hexadecimal digit. -/// -/// For example, the code units [U+0061, U+D800, U+000A] are formatted as -/// `"a\u{D800}\n"`. -impl fmt::Debug for Wtf8Buf { - #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, formatter) - } -} - -/// Formats the string with unpaired surrogates substituted with the replacement -/// character, U+FFFD. -impl fmt::Display for Wtf8Buf { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(s) = self.as_known_utf8() { - fmt::Display::fmt(s, formatter) - } else { - fmt::Display::fmt(&**self, formatter) - } - } -} - -impl Wtf8Buf { - /// Creates a new, empty WTF-8 string. - #[inline] - pub fn new() -> Wtf8Buf { - Wtf8Buf { bytes: Vec::new(), is_known_utf8: true } - } - - /// Creates a new, empty WTF-8 string with pre-allocated capacity for `capacity` bytes. - #[inline] - pub fn with_capacity(capacity: usize) -> Wtf8Buf { - Wtf8Buf { bytes: Vec::with_capacity(capacity), is_known_utf8: true } - } - - /// Creates a WTF-8 string from a WTF-8 byte vec. - /// - /// Since the byte vec is not checked for valid WTF-8, this function is - /// marked unsafe. - #[inline] - pub unsafe fn from_bytes_unchecked(value: Vec) -> Wtf8Buf { - Wtf8Buf { bytes: value, is_known_utf8: false } - } - - /// Creates a WTF-8 string from a UTF-8 `String`. - /// - /// This takes ownership of the `String` and does not copy. - /// - /// Since WTF-8 is a superset of UTF-8, this always succeeds. - #[inline] - pub const fn from_string(string: String) -> Wtf8Buf { - Wtf8Buf { bytes: string.into_bytes(), is_known_utf8: true } - } - - /// Creates a WTF-8 string from a UTF-8 `&str` slice. - /// - /// This copies the content of the slice. - /// - /// Since WTF-8 is a superset of UTF-8, this always succeeds. - #[inline] - pub fn from_str(s: &str) -> Wtf8Buf { - Wtf8Buf { bytes: s.as_bytes().to_vec(), is_known_utf8: true } - } - - pub fn clear(&mut self) { - self.bytes.clear(); - self.is_known_utf8 = true; - } - - /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units. - /// - /// This is lossless: calling `.encode_wide()` on the resulting string - /// will always return the original code units. - pub fn from_wide(v: &[u16]) -> Wtf8Buf { - let mut string = Wtf8Buf::with_capacity(v.len()); - for item in char::decode_utf16(v.iter().cloned()) { - match item { - Ok(ch) => string.push_char(ch), - Err(surrogate) => { - let surrogate = surrogate.unpaired_surrogate(); - // Surrogates are known to be in the code point range. - let code_point = unsafe { CodePoint::from_u32_unchecked(surrogate as u32) }; - // The string will now contain an unpaired surrogate. - string.is_known_utf8 = false; - // Skip the WTF-8 concatenation check, - // surrogate pairs are already decoded by decode_utf16 - string.push_code_point_unchecked(code_point); - } - } - } - string - } - - /// Appends the given `char` to the end of this string. - /// This does **not** include the WTF-8 concatenation check or `is_known_utf8` check. - /// Copied from String::push. - fn push_code_point_unchecked(&mut self, code_point: CodePoint) { - let mut bytes = [0; MAX_LEN_UTF8]; - let bytes = encode_utf8_raw(code_point.value, &mut bytes); - self.bytes.extend_from_slice(bytes) - } - - #[inline] - pub fn as_slice(&self) -> &Wtf8 { - unsafe { Wtf8::from_bytes_unchecked(&self.bytes) } - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut Wtf8 { - // Safety: `Wtf8` doesn't expose any way to mutate the bytes that would - // cause them to change from well-formed UTF-8 to ill-formed UTF-8, - // which would break the assumptions of the `is_known_utf8` field. - unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) } - } - - /// Converts the string to UTF-8 without validation, if it was created from - /// valid UTF-8. - #[inline] - fn as_known_utf8(&self) -> Option<&str> { - if self.is_known_utf8 { - // SAFETY: The buffer is known to be valid UTF-8. - Some(unsafe { str::from_utf8_unchecked(self.as_bytes()) }) - } else { - None - } - } - - /// Reserves capacity for at least `additional` more bytes to be inserted - /// in the given `Wtf8Buf`. - /// The collection may reserve more space to avoid frequent reallocations. - /// - /// # Panics - /// - /// Panics if the new capacity exceeds `isize::MAX` bytes. - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.bytes.reserve(additional) - } - - /// Tries to reserve capacity for at least `additional` more bytes to be - /// inserted in the given `Wtf8Buf`. The `Wtf8Buf` may reserve more space to - /// avoid frequent reallocations. After calling `try_reserve`, capacity will - /// be greater than or equal to `self.len() + additional`. Does nothing if - /// capacity is already sufficient. This method preserves the contents even - /// if an error occurs. - /// - /// # Errors - /// - /// If the capacity overflows, or the allocator reports a failure, then an error - /// is returned. - #[inline] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.bytes.try_reserve(additional) - } - - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - self.bytes.reserve_exact(additional) - } - - /// Tries to reserve the minimum capacity for exactly `additional` more - /// bytes to be inserted in the given `Wtf8Buf`. After calling - /// `try_reserve_exact`, capacity will be greater than or equal to - /// `self.len() + additional` if it returns `Ok(())`. - /// Does nothing if the capacity is already sufficient. - /// - /// Note that the allocator may give the `Wtf8Buf` more space than it - /// requests. Therefore, capacity can not be relied upon to be precisely - /// minimal. Prefer [`try_reserve`] if future insertions are expected. - /// - /// [`try_reserve`]: Wtf8Buf::try_reserve - /// - /// # Errors - /// - /// If the capacity overflows, or the allocator reports a failure, then an error - /// is returned. - #[inline] - pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.bytes.try_reserve_exact(additional) - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - self.bytes.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.bytes.shrink_to(min_capacity) - } - - #[inline] - pub fn leak<'a>(self) -> &'a mut Wtf8 { - unsafe { Wtf8::from_mut_bytes_unchecked(self.bytes.leak()) } - } - - /// Returns the number of bytes that this string buffer can hold without reallocating. - #[inline] - pub fn capacity(&self) -> usize { - self.bytes.capacity() - } - - /// Append a UTF-8 slice at the end of the string. - #[inline] - pub fn push_str(&mut self, other: &str) { - self.bytes.extend_from_slice(other.as_bytes()) - } - - /// Append a WTF-8 slice at the end of the string. - /// - /// This replaces newly paired surrogates at the boundary - /// with a supplementary code point, - /// like concatenating ill-formed UTF-16 strings effectively would. - #[inline] - pub fn push_wtf8(&mut self, other: &Wtf8) { - match ((&*self).final_lead_surrogate(), other.initial_trail_surrogate()) { - // Replace newly paired surrogates by a supplementary code point. - (Some(lead), Some(trail)) => { - let len_without_lead_surrogate = self.len() - 3; - self.bytes.truncate(len_without_lead_surrogate); - let other_without_trail_surrogate = &other.bytes[3..]; - // 4 bytes for the supplementary code point - self.bytes.reserve(4 + other_without_trail_surrogate.len()); - self.push_char(decode_surrogate_pair(lead, trail)); - self.bytes.extend_from_slice(other_without_trail_surrogate); - } - _ => { - // If we'll be pushing a string containing a surrogate, we may - // no longer have UTF-8. - if self.is_known_utf8 && other.next_surrogate(0).is_some() { - self.is_known_utf8 = false; - } - - self.bytes.extend_from_slice(&other.bytes); - } - } - } - - /// Append a Unicode scalar value at the end of the string. - #[inline] - pub fn push_char(&mut self, c: char) { - self.push_code_point_unchecked(CodePoint::from_char(c)) - } - - /// Append a code point at the end of the string. - /// - /// This replaces newly paired surrogates at the boundary - /// with a supplementary code point, - /// like concatenating ill-formed UTF-16 strings effectively would. - #[inline] - pub fn push(&mut self, code_point: CodePoint) { - if let Some(trail) = code_point.to_trail_surrogate() { - if let Some(lead) = (&*self).final_lead_surrogate() { - let len_without_lead_surrogate = self.len() - 3; - self.bytes.truncate(len_without_lead_surrogate); - self.push_char(decode_surrogate_pair(lead, trail)); - return; - } - - // We're pushing a trailing surrogate. - self.is_known_utf8 = false; - } else if code_point.to_lead_surrogate().is_some() { - // We're pushing a leading surrogate. - self.is_known_utf8 = false; - } - - // No newly paired surrogates at the boundary. - self.push_code_point_unchecked(code_point) - } - - /// Shortens a string to the specified length. - /// - /// # Panics - /// - /// Panics if `new_len` > current length, - /// or if `new_len` is not a code point boundary. - #[inline] - pub fn truncate(&mut self, new_len: usize) { - assert!(is_code_point_boundary(self, new_len)); - self.bytes.truncate(new_len) - } - - /// Consumes the WTF-8 string and tries to convert it to a vec of bytes. - #[inline] - pub fn into_bytes(self) -> Vec { - self.bytes - } - - /// Consumes the WTF-8 string and tries to convert it to UTF-8. - /// - /// This does not copy the data. - /// - /// If the contents are not well-formed UTF-8 - /// (that is, if the string contains surrogates), - /// the original WTF-8 string is returned instead. - pub fn into_string(self) -> Result { - if self.is_known_utf8 || self.next_surrogate(0).is_none() { - Ok(unsafe { String::from_utf8_unchecked(self.bytes) }) - } else { - Err(self) - } - } - - /// Consumes the WTF-8 string and converts it lossily to UTF-8. - /// - /// This does not copy the data (but may overwrite parts of it in place). - /// - /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”) - pub fn into_string_lossy(mut self) -> String { - if !self.is_known_utf8 { - let mut pos = 0; - while let Some((surrogate_pos, _)) = self.next_surrogate(pos) { - pos = surrogate_pos + 3; - // Surrogates and the replacement character are all 3 bytes, so - // they can substituted in-place. - self.bytes[surrogate_pos..pos] - .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); - } - } - unsafe { String::from_utf8_unchecked(self.bytes) } - } - - /// Converts this `Wtf8Buf` into a boxed `Wtf8`. - #[inline] - pub fn into_box(self) -> Box { - // SAFETY: relies on `Wtf8` being `repr(transparent)`. - unsafe { mem::transmute(self.bytes.into_boxed_slice()) } - } - - /// Converts a `Box` into a `Wtf8Buf`. - pub fn from_box(boxed: Box) -> Wtf8Buf { - let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) }; - Wtf8Buf { bytes: bytes.into_vec(), is_known_utf8: false } - } - - /// Provides plumbing to core `Vec::extend_from_slice`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. - #[inline] - pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { - self.bytes.extend_from_slice(other); - self.is_known_utf8 = false; - } -} - -/// Creates a new WTF-8 string from an iterator of code points. -/// -/// This replaces surrogate code point pairs with supplementary code points, -/// like concatenating ill-formed UTF-16 strings effectively would. -impl FromIterator for Wtf8Buf { - fn from_iter>(iter: T) -> Wtf8Buf { - let mut string = Wtf8Buf::new(); - string.extend(iter); - string - } -} - -/// Append code points from an iterator to the string. -/// -/// This replaces surrogate code point pairs with supplementary code points, -/// like concatenating ill-formed UTF-16 strings effectively would. -impl Extend for Wtf8Buf { - fn extend>(&mut self, iter: T) { - let iterator = iter.into_iter(); - let (low, _high) = iterator.size_hint(); - // Lower bound of one byte per code point (ASCII only) - self.bytes.reserve(low); - iterator.for_each(move |code_point| self.push(code_point)); - } - - #[inline] - fn extend_one(&mut self, code_point: CodePoint) { - self.push(code_point); - } - - #[inline] - fn extend_reserve(&mut self, additional: usize) { - // Lower bound of one byte per code point (ASCII only) - self.bytes.reserve(additional); - } -} - -/// A borrowed slice of well-formed WTF-8 data. -/// -/// Similar to `&str`, but can additionally contain surrogate code points -/// if they’re not in a surrogate pair. -#[derive(Eq, Ord, PartialEq, PartialOrd)] -#[repr(transparent)] -pub struct Wtf8 { - bytes: [u8], -} - -impl AsInner<[u8]> for Wtf8 { - #[inline] - fn as_inner(&self) -> &[u8] { - &self.bytes - } -} - -/// Formats the string in double quotes, with characters escaped according to -/// [`char::escape_debug`] and unpaired surrogates represented as `\u{xxxx}`, -/// where each `x` is a hexadecimal digit. -impl fmt::Debug for Wtf8 { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fn write_str_escaped(f: &mut fmt::Formatter<'_>, s: &str) -> fmt::Result { - use crate::fmt::Write; - for c in s.chars().flat_map(|c| c.escape_debug()) { - f.write_char(c)? - } - Ok(()) - } - - formatter.write_str("\"")?; - let mut pos = 0; - while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) { - write_str_escaped(formatter, unsafe { - str::from_utf8_unchecked(&self.bytes[pos..surrogate_pos]) - })?; - write!(formatter, "\\u{{{:x}}}", surrogate)?; - pos = surrogate_pos + 3; - } - write_str_escaped(formatter, unsafe { str::from_utf8_unchecked(&self.bytes[pos..]) })?; - formatter.write_str("\"") - } -} - -/// Formats the string with unpaired surrogates substituted with the replacement -/// character, U+FFFD. -impl fmt::Display for Wtf8 { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - let wtf8_bytes = &self.bytes; - let mut pos = 0; - loop { - match self.next_surrogate(pos) { - Some((surrogate_pos, _)) => { - formatter.write_str(unsafe { - str::from_utf8_unchecked(&wtf8_bytes[pos..surrogate_pos]) - })?; - formatter.write_str(UTF8_REPLACEMENT_CHARACTER)?; - pos = surrogate_pos + 3; - } - None => { - let s = unsafe { str::from_utf8_unchecked(&wtf8_bytes[pos..]) }; - if pos == 0 { return s.fmt(formatter) } else { return formatter.write_str(s) } - } - } - } - } -} - -impl Wtf8 { - /// Creates a WTF-8 slice from a UTF-8 `&str` slice. - /// - /// Since WTF-8 is a superset of UTF-8, this always succeeds. - #[inline] - pub fn from_str(value: &str) -> &Wtf8 { - unsafe { Wtf8::from_bytes_unchecked(value.as_bytes()) } - } - - /// Creates a WTF-8 slice from a WTF-8 byte slice. - /// - /// Since the byte slice is not checked for valid WTF-8, this functions is - /// marked unsafe. - #[inline] - pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { - // SAFETY: start with &[u8], end with fancy &[u8] - unsafe { &*(value as *const [u8] as *const Wtf8) } - } - - /// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice. - /// - /// Since the byte slice is not checked for valid WTF-8, this functions is - /// marked unsafe. - #[inline] - unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 { - // SAFETY: start with &mut [u8], end with fancy &mut [u8] - unsafe { &mut *(value as *mut [u8] as *mut Wtf8) } - } - - /// Returns the length, in WTF-8 bytes. - #[inline] - pub fn len(&self) -> usize { - self.bytes.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.bytes.is_empty() - } - - /// Returns the code point at `position` if it is in the ASCII range, - /// or `b'\xFF'` otherwise. - /// - /// # Panics - /// - /// Panics if `position` is beyond the end of the string. - #[inline] - pub fn ascii_byte_at(&self, position: usize) -> u8 { - match self.bytes[position] { - ascii_byte @ 0x00..=0x7F => ascii_byte, - _ => 0xFF, - } - } - - /// Returns an iterator for the string’s code points. - #[inline] - pub fn code_points(&self) -> Wtf8CodePoints<'_> { - Wtf8CodePoints { bytes: self.bytes.iter() } - } - - /// Access raw bytes of WTF-8 data - #[inline] - pub fn as_bytes(&self) -> &[u8] { - &self.bytes - } - - /// Tries to convert the string to UTF-8 and return a `&str` slice. - /// - /// Returns `None` if the string contains surrogates. - /// - /// This does not copy the data. - #[inline] - pub fn as_str(&self) -> Result<&str, str::Utf8Error> { - str::from_utf8(&self.bytes) - } - - /// Creates an owned `Wtf8Buf` from a borrowed `Wtf8`. - pub fn to_owned(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_vec(), is_known_utf8: false } - } - - /// Lossily converts the string to UTF-8. - /// Returns a UTF-8 `&str` slice if the contents are well-formed in UTF-8. - /// - /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”). - /// - /// This only copies the data if necessary (if it contains any surrogate). - pub fn to_string_lossy(&self) -> Cow<'_, str> { - let Some((surrogate_pos, _)) = self.next_surrogate(0) else { - return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }); - }; - let wtf8_bytes = &self.bytes; - let mut utf8_bytes = Vec::with_capacity(self.len()); - utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]); - utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); - let mut pos = surrogate_pos + 3; - loop { - match self.next_surrogate(pos) { - Some((surrogate_pos, _)) => { - utf8_bytes.extend_from_slice(&wtf8_bytes[pos..surrogate_pos]); - utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); - pos = surrogate_pos + 3; - } - None => { - utf8_bytes.extend_from_slice(&wtf8_bytes[pos..]); - return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) }); - } - } - } - } - - /// Converts the WTF-8 string to potentially ill-formed UTF-16 - /// and return an iterator of 16-bit code units. - /// - /// This is lossless: - /// calling `Wtf8Buf::from_ill_formed_utf16` on the resulting code units - /// would always return the original WTF-8 string. - #[inline] - pub fn encode_wide(&self) -> EncodeWide<'_> { - EncodeWide { code_points: self.code_points(), extra: 0 } - } - - #[inline] - fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> { - let mut iter = self.bytes[pos..].iter(); - loop { - let b = *iter.next()?; - if b < 0x80 { - pos += 1; - } else if b < 0xE0 { - iter.next(); - pos += 2; - } else if b == 0xED { - match (iter.next(), iter.next()) { - (Some(&b2), Some(&b3)) if b2 >= 0xA0 => { - return Some((pos, decode_surrogate(b2, b3))); - } - _ => pos += 3, - } - } else if b < 0xF0 { - iter.next(); - iter.next(); - pos += 3; - } else { - iter.next(); - iter.next(); - iter.next(); - pos += 4; - } - } - } - - #[inline] - fn final_lead_surrogate(&self) -> Option { - match self.bytes { - [.., 0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)), - _ => None, - } - } - - #[inline] - fn initial_trail_surrogate(&self) -> Option { - match self.bytes { - [0xED, b2 @ 0xB0..=0xBF, b3, ..] => Some(decode_surrogate(b2, b3)), - _ => None, - } - } - - pub fn clone_into(&self, buf: &mut Wtf8Buf) { - buf.is_known_utf8 = false; - self.bytes.clone_into(&mut buf.bytes); - } - - /// Boxes this `Wtf8`. - #[inline] - pub fn into_box(&self) -> Box { - let boxed: Box<[u8]> = self.bytes.into(); - unsafe { mem::transmute(boxed) } - } - - /// Creates a boxed, empty `Wtf8`. - pub fn empty_box() -> Box { - let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - let arc: Arc<[u8]> = Arc::from(&self.bytes); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Wtf8) } - } - - #[inline] - pub fn into_rc(&self) -> Rc { - let rc: Rc<[u8]> = Rc::from(&self.bytes); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Wtf8) } - } - - #[inline] - pub fn make_ascii_lowercase(&mut self) { - self.bytes.make_ascii_lowercase() - } - - #[inline] - pub fn make_ascii_uppercase(&mut self) { - self.bytes.make_ascii_uppercase() - } - - #[inline] - pub fn to_ascii_lowercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_lowercase(), is_known_utf8: false } - } - - #[inline] - pub fn to_ascii_uppercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_uppercase(), is_known_utf8: false } - } - - #[inline] - pub fn is_ascii(&self) -> bool { - self.bytes.is_ascii() - } - - #[inline] - pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { - self.bytes.eq_ignore_ascii_case(&other.bytes) - } -} - -/// Returns a slice of the given string for the byte range \[`begin`..`end`). -/// -/// # Panics -/// -/// Panics when `begin` and `end` do not point to code point boundaries, -/// or point beyond the end of the string. -impl ops::Index> for Wtf8 { - type Output = Wtf8; - - #[inline] - fn index(&self, range: ops::Range) -> &Wtf8 { - // is_code_point_boundary checks that the index is in [0, .len()] - if range.start <= range.end - && is_code_point_boundary(self, range.start) - && is_code_point_boundary(self, range.end) - { - unsafe { slice_unchecked(self, range.start, range.end) } - } else { - slice_error_fail(self, range.start, range.end) - } - } -} - -/// Returns a slice of the given string from byte `begin` to its end. -/// -/// # Panics -/// -/// Panics when `begin` is not at a code point boundary, -/// or is beyond the end of the string. -impl ops::Index> for Wtf8 { - type Output = Wtf8; - - #[inline] - fn index(&self, range: ops::RangeFrom) -> &Wtf8 { - // is_code_point_boundary checks that the index is in [0, .len()] - if is_code_point_boundary(self, range.start) { - unsafe { slice_unchecked(self, range.start, self.len()) } - } else { - slice_error_fail(self, range.start, self.len()) - } - } -} - -/// Returns a slice of the given string from its beginning to byte `end`. -/// -/// # Panics -/// -/// Panics when `end` is not at a code point boundary, -/// or is beyond the end of the string. -impl ops::Index> for Wtf8 { - type Output = Wtf8; - - #[inline] - fn index(&self, range: ops::RangeTo) -> &Wtf8 { - // is_code_point_boundary checks that the index is in [0, .len()] - if is_code_point_boundary(self, range.end) { - unsafe { slice_unchecked(self, 0, range.end) } - } else { - slice_error_fail(self, 0, range.end) - } - } -} - -impl ops::Index for Wtf8 { - type Output = Wtf8; - - #[inline] - fn index(&self, _range: ops::RangeFull) -> &Wtf8 { - self - } -} - -#[inline] -fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 { - // The first byte is assumed to be 0xED - 0xD800 | (second_byte as u16 & 0x3F) << 6 | third_byte as u16 & 0x3F -} - -#[inline] -fn decode_surrogate_pair(lead: u16, trail: u16) -> char { - let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32); - unsafe { char::from_u32_unchecked(code_point) } -} - -/// Copied from str::is_char_boundary -#[inline] -pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool { - if index == 0 { - return true; - } - match slice.bytes.get(index) { - None => index == slice.len(), - Some(&b) => (b as i8) >= -0x40, - } -} - -/// Verify that `index` is at the edge of either a valid UTF-8 codepoint -/// (i.e. a codepoint that's not a surrogate) or of the whole string. -/// -/// These are the cases currently permitted by `OsStr::slice_encoded_bytes`. -/// Splitting between surrogates is valid as far as WTF-8 is concerned, but -/// we do not permit it in the public API because WTF-8 is considered an -/// implementation detail. -#[track_caller] -#[inline] -pub fn check_utf8_boundary(slice: &Wtf8, index: usize) { - if index == 0 { - return; - } - match slice.bytes.get(index) { - Some(0xED) => (), // Might be a surrogate - Some(&b) if (b as i8) >= -0x40 => return, - Some(_) => panic!("byte index {index} is not a codepoint boundary"), - None if index == slice.len() => return, - None => panic!("byte index {index} is out of bounds"), - } - if slice.bytes[index + 1] >= 0xA0 { - // There's a surrogate after index. Now check before index. - if index >= 3 && slice.bytes[index - 3] == 0xED && slice.bytes[index - 2] >= 0xA0 { - panic!("byte index {index} lies between surrogate codepoints"); - } - } -} - -/// Copied from core::str::raw::slice_unchecked -#[inline] -pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { - // SAFETY: memory layout of a &[u8] and &Wtf8 are the same - unsafe { - let len = end - begin; - let start = s.as_bytes().as_ptr().add(begin); - Wtf8::from_bytes_unchecked(slice::from_raw_parts(start, len)) - } -} - -/// Copied from core::str::raw::slice_error_fail -#[inline(never)] -pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! { - assert!(begin <= end); - panic!("index {begin} and/or {end} in `{s:?}` do not lie on character boundary"); -} - -/// Iterator for the code points of a WTF-8 string. -/// -/// Created with the method `.code_points()`. -#[derive(Clone)] -pub struct Wtf8CodePoints<'a> { - bytes: slice::Iter<'a, u8>, -} - -impl Iterator for Wtf8CodePoints<'_> { - type Item = CodePoint; - - #[inline] - fn next(&mut self) -> Option { - // SAFETY: `self.bytes` has been created from a WTF-8 string - unsafe { next_code_point(&mut self.bytes).map(|c| CodePoint { value: c }) } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.bytes.len(); - (len.saturating_add(3) / 4, Some(len)) - } -} - -/// Generates a wide character sequence for potentially ill-formed UTF-16. -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct EncodeWide<'a> { - code_points: Wtf8CodePoints<'a>, - extra: u16, -} - -// Copied from libunicode/u_str.rs -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for EncodeWide<'_> { - type Item = u16; - - #[inline] - fn next(&mut self) -> Option { - if self.extra != 0 { - let tmp = self.extra; - self.extra = 0; - return Some(tmp); - } - - let mut buf = [0; MAX_LEN_UTF16]; - self.code_points.next().map(|code_point| { - let n = encode_utf16_raw(code_point.value, &mut buf).len(); - if n == 2 { - self.extra = buf[1]; - } - buf[0] - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.code_points.size_hint(); - let ext = (self.extra != 0) as usize; - // every code point gets either one u16 or two u16, - // so this iterator is between 1 or 2 times as - // long as the underlying iterator. - (low + ext, high.and_then(|n| n.checked_mul(2)).and_then(|n| n.checked_add(ext))) - } -} - -#[stable(feature = "encode_wide_fused_iterator", since = "1.62.0")] -impl FusedIterator for EncodeWide<'_> {} - -impl Hash for CodePoint { - #[inline] - fn hash(&self, state: &mut H) { - self.value.hash(state) - } -} - -impl Hash for Wtf8Buf { - #[inline] - fn hash(&self, state: &mut H) { - state.write(&self.bytes); - 0xfeu8.hash(state) - } -} - -impl Hash for Wtf8 { - #[inline] - fn hash(&self, state: &mut H) { - state.write(&self.bytes); - 0xfeu8.hash(state) - } -} - -#[unstable(feature = "clone_to_uninit", issue = "126799")] -unsafe impl CloneToUninit for Wtf8 { - #[inline] - #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut u8) { - // SAFETY: we're just a transparent wrapper around [u8] - unsafe { self.bytes.clone_to_uninit(dst) } - } -} diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs deleted file mode 100644 index b57c99a8452..00000000000 --- a/library/std/src/sys_common/wtf8/tests.rs +++ /dev/null @@ -1,751 +0,0 @@ -use super::*; - -#[test] -fn code_point_from_u32() { - assert!(CodePoint::from_u32(0).is_some()); - assert!(CodePoint::from_u32(0xD800).is_some()); - assert!(CodePoint::from_u32(0x10FFFF).is_some()); - assert!(CodePoint::from_u32(0x110000).is_none()); -} - -#[test] -fn code_point_to_u32() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - assert_eq!(c(0).to_u32(), 0); - assert_eq!(c(0xD800).to_u32(), 0xD800); - assert_eq!(c(0x10FFFF).to_u32(), 0x10FFFF); -} - -#[test] -fn code_point_to_lead_surrogate() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - assert_eq!(c(0).to_lead_surrogate(), None); - assert_eq!(c(0xE9).to_lead_surrogate(), None); - assert_eq!(c(0xD800).to_lead_surrogate(), Some(0xD800)); - assert_eq!(c(0xDBFF).to_lead_surrogate(), Some(0xDBFF)); - assert_eq!(c(0xDC00).to_lead_surrogate(), None); - assert_eq!(c(0xDFFF).to_lead_surrogate(), None); - assert_eq!(c(0x1F4A9).to_lead_surrogate(), None); - assert_eq!(c(0x10FFFF).to_lead_surrogate(), None); -} - -#[test] -fn code_point_to_trail_surrogate() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - assert_eq!(c(0).to_trail_surrogate(), None); - assert_eq!(c(0xE9).to_trail_surrogate(), None); - assert_eq!(c(0xD800).to_trail_surrogate(), None); - assert_eq!(c(0xDBFF).to_trail_surrogate(), None); - assert_eq!(c(0xDC00).to_trail_surrogate(), Some(0xDC00)); - assert_eq!(c(0xDFFF).to_trail_surrogate(), Some(0xDFFF)); - assert_eq!(c(0x1F4A9).to_trail_surrogate(), None); - assert_eq!(c(0x10FFFF).to_trail_surrogate(), None); -} - -#[test] -fn code_point_from_char() { - assert_eq!(CodePoint::from_char('a').to_u32(), 0x61); - assert_eq!(CodePoint::from_char('💩').to_u32(), 0x1F4A9); -} - -#[test] -fn code_point_to_string() { - assert_eq!(format!("{:?}", CodePoint::from_char('a')), "U+0061"); - assert_eq!(format!("{:?}", CodePoint::from_char('💩')), "U+1F4A9"); -} - -#[test] -fn code_point_to_char() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - assert_eq!(c(0x61).to_char(), Some('a')); - assert_eq!(c(0x1F4A9).to_char(), Some('💩')); - assert_eq!(c(0xD800).to_char(), None); -} - -#[test] -fn code_point_to_char_lossy() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - assert_eq!(c(0x61).to_char_lossy(), 'a'); - assert_eq!(c(0x1F4A9).to_char_lossy(), '💩'); - assert_eq!(c(0xD800).to_char_lossy(), '\u{FFFD}'); -} - -#[test] -fn wtf8buf_new() { - assert_eq!(Wtf8Buf::new().bytes, b""); -} - -#[test] -fn wtf8buf_from_str() { - assert_eq!(Wtf8Buf::from_str("").bytes, b""); - assert_eq!(Wtf8Buf::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); -} - -#[test] -fn wtf8buf_from_string() { - assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b""); - assert_eq!(Wtf8Buf::from_string(String::from("aé 💩")).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); -} - -#[test] -fn wtf8buf_from_wide() { - let buf = Wtf8Buf::from_wide(&[]); - assert_eq!(buf.bytes, b""); - assert!(buf.is_known_utf8); - - let buf = Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xDCA9]); - assert_eq!(buf.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - assert!(buf.is_known_utf8); - - let buf = Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]); - assert_eq!(buf.bytes, b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9"); - assert!(!buf.is_known_utf8); - - let buf = Wtf8Buf::from_wide(&[0xD800]); - assert_eq!(buf.bytes, b"\xED\xA0\x80"); - assert!(!buf.is_known_utf8); - - let buf = Wtf8Buf::from_wide(&[0xDBFF]); - assert_eq!(buf.bytes, b"\xED\xAF\xBF"); - assert!(!buf.is_known_utf8); - - let buf = Wtf8Buf::from_wide(&[0xDC00]); - assert_eq!(buf.bytes, b"\xED\xB0\x80"); - assert!(!buf.is_known_utf8); - - let buf = Wtf8Buf::from_wide(&[0xDFFF]); - assert_eq!(buf.bytes, b"\xED\xBF\xBF"); - assert!(!buf.is_known_utf8); -} - -#[test] -fn wtf8buf_push_str() { - let mut string = Wtf8Buf::new(); - assert_eq!(string.bytes, b""); - assert!(string.is_known_utf8); - - string.push_str("aé 💩"); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - assert!(string.is_known_utf8); -} - -#[test] -fn wtf8buf_push_char() { - let mut string = Wtf8Buf::from_str("aé "); - assert_eq!(string.bytes, b"a\xC3\xA9 "); - assert!(string.is_known_utf8); - - string.push_char('💩'); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - assert!(string.is_known_utf8); -} - -#[test] -fn wtf8buf_push() { - let mut string = Wtf8Buf::from_str("aé "); - assert_eq!(string.bytes, b"a\xC3\xA9 "); - assert!(string.is_known_utf8); - - string.push(CodePoint::from_char('💩')); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - assert!(string.is_known_utf8); - - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - - let mut string = Wtf8Buf::new(); - string.push(c(0xD83D)); // lead - assert!(!string.is_known_utf8); - string.push(c(0xDCA9)); // trail - assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! - - let mut string = Wtf8Buf::new(); - string.push(c(0xD83D)); // lead - assert!(!string.is_known_utf8); - string.push(c(0x20)); // not surrogate - string.push(c(0xDCA9)); // trail - assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); - - let mut string = Wtf8Buf::new(); - string.push(c(0xD800)); // lead - assert!(!string.is_known_utf8); - string.push(c(0xDBFF)); // lead - assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); - - let mut string = Wtf8Buf::new(); - string.push(c(0xD800)); // lead - assert!(!string.is_known_utf8); - string.push(c(0xE000)); // not surrogate - assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); - - let mut string = Wtf8Buf::new(); - string.push(c(0xD7FF)); // not surrogate - assert!(string.is_known_utf8); - string.push(c(0xDC00)); // trail - assert!(!string.is_known_utf8); - assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); - - let mut string = Wtf8Buf::new(); - string.push(c(0x61)); // not surrogate, < 3 bytes - assert!(string.is_known_utf8); - string.push(c(0xDC00)); // trail - assert!(!string.is_known_utf8); - assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); - - let mut string = Wtf8Buf::new(); - string.push(c(0xDC00)); // trail - assert!(!string.is_known_utf8); - assert_eq!(string.bytes, b"\xED\xB0\x80"); -} - -#[test] -fn wtf8buf_push_wtf8() { - let mut string = Wtf8Buf::from_str("aé"); - assert_eq!(string.bytes, b"a\xC3\xA9"); - string.push_wtf8(Wtf8::from_str(" 💩")); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - assert!(string.is_known_utf8); - - fn w(v: &[u8]) -> &Wtf8 { - unsafe { Wtf8::from_bytes_unchecked(v) } - } - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\xBD")); // lead - string.push_wtf8(w(b"\xED\xB2\xA9")); // trail - assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\xBD")); // lead - string.push_wtf8(w(b" ")); // not surrogate - string.push_wtf8(w(b"\xED\xB2\xA9")); // trail - assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); - assert!(!string.is_known_utf8); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\x80")); // lead - string.push_wtf8(w(b"\xED\xAF\xBF")); // lead - assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); - assert!(!string.is_known_utf8); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\x80")); // lead - string.push_wtf8(w(b"\xEE\x80\x80")); // not surrogate - assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); - assert!(!string.is_known_utf8); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\x9F\xBF")); // not surrogate - string.push_wtf8(w(b"\xED\xB0\x80")); // trail - assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); - assert!(!string.is_known_utf8); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"a")); // not surrogate, < 3 bytes - string.push_wtf8(w(b"\xED\xB0\x80")); // trail - assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); - assert!(!string.is_known_utf8); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xB0\x80")); // trail - assert_eq!(string.bytes, b"\xED\xB0\x80"); - assert!(!string.is_known_utf8); -} - -#[test] -fn wtf8buf_truncate() { - let mut string = Wtf8Buf::from_str("aé"); - assert!(string.is_known_utf8); - - string.truncate(3); - assert_eq!(string.bytes, b"a\xC3\xA9"); - assert!(string.is_known_utf8); - - string.truncate(1); - assert_eq!(string.bytes, b"a"); - assert!(string.is_known_utf8); - - string.truncate(0); - assert_eq!(string.bytes, b""); - assert!(string.is_known_utf8); -} - -#[test] -fn wtf8buf_truncate_around_non_bmp() { - let mut string = Wtf8Buf::from_str("💩"); - assert!(string.is_known_utf8); - - string.truncate(4); - assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); - assert!(string.is_known_utf8); - - string.truncate(0); - assert_eq!(string.bytes, b""); - assert!(string.is_known_utf8); -} - -#[test] -#[should_panic] -fn wtf8buf_truncate_fail_code_point_boundary() { - let mut string = Wtf8Buf::from_str("aé"); - string.truncate(2); -} - -#[test] -#[should_panic] -fn wtf8buf_truncate_fail_longer() { - let mut string = Wtf8Buf::from_str("aé"); - string.truncate(4); -} - -#[test] -#[should_panic] -fn wtf8buf_truncate_splitting_non_bmp3() { - let mut string = Wtf8Buf::from_str("💩"); - assert!(string.is_known_utf8); - string.truncate(3); -} - -#[test] -#[should_panic] -fn wtf8buf_truncate_splitting_non_bmp2() { - let mut string = Wtf8Buf::from_str("💩"); - assert!(string.is_known_utf8); - string.truncate(2); -} - -#[test] -#[should_panic] -fn wtf8buf_truncate_splitting_non_bmp1() { - let mut string = Wtf8Buf::from_str("💩"); - assert!(string.is_known_utf8); - string.truncate(1); -} - -#[test] -fn wtf8buf_into_string() { - let mut string = Wtf8Buf::from_str("aé 💩"); - assert!(string.is_known_utf8); - assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩"))); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert!(!string.is_known_utf8); - assert_eq!(string.clone().into_string(), Err(string)); -} - -#[test] -fn wtf8buf_into_string_lossy() { - let mut string = Wtf8Buf::from_str("aé 💩"); - assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩")); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�")); -} - -#[test] -fn wtf8buf_from_iterator() { - fn f(values: &[u32]) -> Wtf8Buf { - values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::() - } - assert_eq!( - f(&[0x61, 0xE9, 0x20, 0x1F4A9]), - Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true } - ); - - assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! - assert_eq!( - f(&[0xD83D, 0x20, 0xDCA9]), - Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false } - ); - assert_eq!( - f(&[0xD800, 0xDBFF]), - Wtf8Buf { bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), is_known_utf8: false } - ); - assert_eq!( - f(&[0xD800, 0xE000]), - Wtf8Buf { bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), is_known_utf8: false } - ); - assert_eq!( - f(&[0xD7FF, 0xDC00]), - Wtf8Buf { bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), is_known_utf8: false } - ); - assert_eq!( - f(&[0x61, 0xDC00]), - Wtf8Buf { bytes: b"\x61\xED\xB0\x80".to_vec(), is_known_utf8: false } - ); - assert_eq!(f(&[0xDC00]), Wtf8Buf { bytes: b"\xED\xB0\x80".to_vec(), is_known_utf8: false }); -} - -#[test] -fn wtf8buf_extend() { - fn e(initial: &[u32], extended: &[u32]) -> Wtf8Buf { - fn c(value: &u32) -> CodePoint { - CodePoint::from_u32(*value).unwrap() - } - let mut string = initial.iter().map(c).collect::(); - string.extend(extended.iter().map(c)); - string - } - - assert_eq!( - e(&[0x61, 0xE9], &[0x20, 0x1F4A9]), - Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true } - ); - - assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! - assert_eq!( - e(&[0xD83D, 0x20], &[0xDCA9]), - Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false } - ); - assert_eq!( - e(&[0xD800], &[0xDBFF]), - Wtf8Buf { bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), is_known_utf8: false } - ); - assert_eq!( - e(&[0xD800], &[0xE000]), - Wtf8Buf { bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), is_known_utf8: false } - ); - assert_eq!( - e(&[0xD7FF], &[0xDC00]), - Wtf8Buf { bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), is_known_utf8: false } - ); - assert_eq!( - e(&[0x61], &[0xDC00]), - Wtf8Buf { bytes: b"\x61\xED\xB0\x80".to_vec(), is_known_utf8: false } - ); - assert_eq!( - e(&[], &[0xDC00]), - Wtf8Buf { bytes: b"\xED\xB0\x80".to_vec(), is_known_utf8: false } - ); -} - -#[test] -fn wtf8buf_show() { - let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(format!("{string:?}"), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\""); -} - -#[test] -fn wtf8buf_as_slice() { - assert_eq!(Wtf8Buf::from_str("aé").as_slice(), Wtf8::from_str("aé")); -} - -#[test] -fn wtf8buf_show_str() { - let text = "a\té 💩\r"; - let string = Wtf8Buf::from_str(text); - assert_eq!(format!("{text:?}"), format!("{string:?}")); -} - -#[test] -fn wtf8_from_str() { - assert_eq!(&Wtf8::from_str("").bytes, b""); - assert_eq!(&Wtf8::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); -} - -#[test] -fn wtf8_len() { - assert_eq!(Wtf8::from_str("").len(), 0); - assert_eq!(Wtf8::from_str("aé 💩").len(), 8); -} - -#[test] -fn wtf8_slice() { - assert_eq!(&Wtf8::from_str("aé 💩")[1..4].bytes, b"\xC3\xA9 "); -} - -#[test] -#[should_panic] -fn wtf8_slice_not_code_point_boundary() { - let _ = &Wtf8::from_str("aé 💩")[2..4]; -} - -#[test] -fn wtf8_slice_from() { - assert_eq!(&Wtf8::from_str("aé 💩")[1..].bytes, b"\xC3\xA9 \xF0\x9F\x92\xA9"); -} - -#[test] -#[should_panic] -fn wtf8_slice_from_not_code_point_boundary() { - let _ = &Wtf8::from_str("aé 💩")[2..]; -} - -#[test] -fn wtf8_slice_to() { - assert_eq!(&Wtf8::from_str("aé 💩")[..4].bytes, b"a\xC3\xA9 "); -} - -#[test] -#[should_panic] -fn wtf8_slice_to_not_code_point_boundary() { - let _ = &Wtf8::from_str("aé 💩")[5..]; -} - -#[test] -fn wtf8_ascii_byte_at() { - let slice = Wtf8::from_str("aé 💩"); - assert_eq!(slice.ascii_byte_at(0), b'a'); - assert_eq!(slice.ascii_byte_at(1), b'\xFF'); - assert_eq!(slice.ascii_byte_at(2), b'\xFF'); - assert_eq!(slice.ascii_byte_at(3), b' '); - assert_eq!(slice.ascii_byte_at(4), b'\xFF'); -} - -#[test] -fn wtf8_code_points() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - fn cp(string: &Wtf8Buf) -> Vec> { - string.code_points().map(|c| c.to_char()).collect::>() - } - let mut string = Wtf8Buf::from_str("é "); - assert_eq!(cp(&string), [Some('é'), Some(' ')]); - string.push(c(0xD83D)); - assert_eq!(cp(&string), [Some('é'), Some(' '), None]); - string.push(c(0xDCA9)); - assert_eq!(cp(&string), [Some('é'), Some(' '), Some('💩')]); -} - -#[test] -fn wtf8_as_str() { - assert_eq!(Wtf8::from_str("").as_str(), Ok("")); - assert_eq!(Wtf8::from_str("aé 💩").as_str(), Ok("aé 💩")); - let mut string = Wtf8Buf::new(); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert!(string.as_str().is_err()); -} - -#[test] -fn wtf8_to_string_lossy() { - assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed("")); - assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩")); - let mut string = Wtf8Buf::from_str("aé 💩"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - let expected: Cow<'_, str> = Cow::Owned(String::from("aé 💩�")); - assert_eq!(string.to_string_lossy(), expected); -} - -#[test] -fn wtf8_display() { - fn d(b: &[u8]) -> String { - (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string() - } - - assert_eq!("", d("".as_bytes())); - assert_eq!("aé 💩", d("aé 💩".as_bytes())); - - let mut string = Wtf8Buf::from_str("aé 💩"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!("aé 💩�", d(string.as_inner())); -} - -#[test] -fn wtf8_encode_wide() { - let mut string = Wtf8Buf::from_str("aé "); - string.push(CodePoint::from_u32(0xD83D).unwrap()); - string.push_char('💩'); - assert_eq!( - string.encode_wide().collect::>(), - vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9] - ); -} - -#[test] -fn wtf8_encode_wide_size_hint() { - let string = Wtf8Buf::from_str("\u{12345}"); - let mut iter = string.encode_wide(); - assert_eq!((1, Some(8)), iter.size_hint()); - iter.next().unwrap(); - assert_eq!((1, Some(1)), iter.size_hint()); - iter.next().unwrap(); - assert_eq!((0, Some(0)), iter.size_hint()); - assert!(iter.next().is_none()); -} - -#[test] -fn wtf8_clone_into() { - let mut string = Wtf8Buf::new(); - Wtf8::from_str("green").clone_into(&mut string); - assert_eq!(string.bytes, b"green"); - - let mut string = Wtf8Buf::from_str("green"); - Wtf8::from_str("").clone_into(&mut string); - assert_eq!(string.bytes, b""); - - let mut string = Wtf8Buf::from_str("red"); - Wtf8::from_str("green").clone_into(&mut string); - assert_eq!(string.bytes, b"green"); - - let mut string = Wtf8Buf::from_str("green"); - Wtf8::from_str("red").clone_into(&mut string); - assert_eq!(string.bytes, b"red"); - - let mut string = Wtf8Buf::from_str("green"); - assert!(string.is_known_utf8); - unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").clone_into(&mut string) }; - assert_eq!(string.bytes, b"\xED\xA0\x80"); - assert!(!string.is_known_utf8); -} - -#[test] -fn wtf8_to_ascii_lowercase() { - let lowercase = Wtf8::from_str("").to_ascii_lowercase(); - assert_eq!(lowercase.bytes, b""); - - let lowercase = Wtf8::from_str("GrEeN gRaPeS! 🍇").to_ascii_lowercase(); - assert_eq!(lowercase.bytes, b"green grapes! \xf0\x9f\x8d\x87"); - - let lowercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_ascii_lowercase() }; - assert_eq!(lowercase.bytes, b"\xED\xA0\x80"); - assert!(!lowercase.is_known_utf8); -} - -#[test] -fn wtf8_to_ascii_uppercase() { - let uppercase = Wtf8::from_str("").to_ascii_uppercase(); - assert_eq!(uppercase.bytes, b""); - - let uppercase = Wtf8::from_str("GrEeN gRaPeS! 🍇").to_ascii_uppercase(); - assert_eq!(uppercase.bytes, b"GREEN GRAPES! \xf0\x9f\x8d\x87"); - - let uppercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_ascii_uppercase() }; - assert_eq!(uppercase.bytes, b"\xED\xA0\x80"); - assert!(!uppercase.is_known_utf8); -} - -#[test] -fn wtf8_make_ascii_lowercase() { - let mut lowercase = Wtf8Buf::from_str(""); - lowercase.make_ascii_lowercase(); - assert_eq!(lowercase.bytes, b""); - - let mut lowercase = Wtf8Buf::from_str("GrEeN gRaPeS! 🍇"); - lowercase.make_ascii_lowercase(); - assert_eq!(lowercase.bytes, b"green grapes! \xf0\x9f\x8d\x87"); - - let mut lowercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; - lowercase.make_ascii_lowercase(); - assert_eq!(lowercase.bytes, b"\xED\xA0\x80"); - assert!(!lowercase.is_known_utf8); -} - -#[test] -fn wtf8_make_ascii_uppercase() { - let mut uppercase = Wtf8Buf::from_str(""); - uppercase.make_ascii_uppercase(); - assert_eq!(uppercase.bytes, b""); - - let mut uppercase = Wtf8Buf::from_str("GrEeN gRaPeS! 🍇"); - uppercase.make_ascii_uppercase(); - assert_eq!(uppercase.bytes, b"GREEN GRAPES! \xf0\x9f\x8d\x87"); - - let mut uppercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; - uppercase.make_ascii_uppercase(); - assert_eq!(uppercase.bytes, b"\xED\xA0\x80"); - assert!(!uppercase.is_known_utf8); -} - -#[test] -fn wtf8_to_owned() { - let string = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; - assert_eq!(string.bytes, b"\xED\xA0\x80"); - assert!(!string.is_known_utf8); -} - -#[test] -fn wtf8_valid_utf8_boundaries() { - let mut string = Wtf8Buf::from_str("aé 💩"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - string.push(CodePoint::from_u32(0xD800).unwrap()); - check_utf8_boundary(&string, 0); - check_utf8_boundary(&string, 1); - check_utf8_boundary(&string, 3); - check_utf8_boundary(&string, 4); - check_utf8_boundary(&string, 8); - check_utf8_boundary(&string, 14); - assert_eq!(string.len(), 14); - - string.push_char('a'); - check_utf8_boundary(&string, 14); - check_utf8_boundary(&string, 15); - - let mut string = Wtf8Buf::from_str("a"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - check_utf8_boundary(&string, 1); - - let mut string = Wtf8Buf::from_str("\u{D7FF}"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - check_utf8_boundary(&string, 3); - - let mut string = Wtf8Buf::new(); - string.push(CodePoint::from_u32(0xD800).unwrap()); - string.push_char('\u{D7FF}'); - check_utf8_boundary(&string, 3); -} - -#[test] -#[should_panic(expected = "byte index 4 is out of bounds")] -fn wtf8_utf8_boundary_out_of_bounds() { - let string = Wtf8::from_str("aé"); - check_utf8_boundary(&string, 4); -} - -#[test] -#[should_panic(expected = "byte index 1 is not a codepoint boundary")] -fn wtf8_utf8_boundary_inside_codepoint() { - let string = Wtf8::from_str("é"); - check_utf8_boundary(&string, 1); -} - -#[test] -#[should_panic(expected = "byte index 1 is not a codepoint boundary")] -fn wtf8_utf8_boundary_inside_surrogate() { - let mut string = Wtf8Buf::new(); - string.push(CodePoint::from_u32(0xD800).unwrap()); - check_utf8_boundary(&string, 1); -} - -#[test] -#[should_panic(expected = "byte index 3 lies between surrogate codepoints")] -fn wtf8_utf8_boundary_between_surrogates() { - let mut string = Wtf8Buf::new(); - string.push(CodePoint::from_u32(0xD800).unwrap()); - string.push(CodePoint::from_u32(0xD800).unwrap()); - check_utf8_boundary(&string, 3); -} - -#[test] -fn wobbled_wtf8_plus_bytes_isnt_utf8() { - let mut string: Wtf8Buf = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; - assert!(!string.is_known_utf8); - string.extend_from_slice(b"some utf-8"); - assert!(!string.is_known_utf8); -} - -#[test] -fn wobbled_wtf8_plus_str_isnt_utf8() { - let mut string: Wtf8Buf = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; - assert!(!string.is_known_utf8); - string.push_str("some utf-8"); - assert!(!string.is_known_utf8); -} - -#[test] -fn unwobbly_wtf8_plus_utf8_is_utf8() { - let mut string: Wtf8Buf = Wtf8Buf::from_str("hello world"); - assert!(string.is_known_utf8); - string.push_str("some utf-8"); - assert!(string.is_known_utf8); -} -- cgit 1.4.1-3-g733a5 From 2914291e09cb13aab64207f9e11f2aaf74de3904 Mon Sep 17 00:00:00 2001 From: ltdk Date: Wed, 13 Aug 2025 01:16:42 -0400 Subject: Move WTF-8 code from std to core/alloc --- library/alloc/src/lib.rs | 3 + library/alloc/src/wtf8/mod.rs | 674 +++++------------------------------- library/alloc/src/wtf8/tests.rs | 209 +++++------ library/alloctests/lib.rs | 12 +- library/alloctests/tests/lib.rs | 1 + library/core/src/lib.rs | 2 + library/core/src/num/niche_types.rs | 15 + library/core/src/wtf8.rs | 642 +++++----------------------------- library/coretests/tests/lib.rs | 1 + library/coretests/tests/wtf8.rs | 1 + library/std/src/lib.rs | 1 + library/std/src/os/windows/ffi.rs | 38 +- library/std/src/sys/os_str/wtf8.rs | 8 +- library/std/src/sys_common/mod.rs | 1 - src/tools/tidy/src/unit_tests.rs | 1 + 15 files changed, 331 insertions(+), 1278 deletions(-) create mode 100644 library/coretests/tests/wtf8.rs diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 639c5d4c930..711092ae8eb 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -159,6 +159,7 @@ #![feature(unicode_internals)] #![feature(unsize)] #![feature(unwrap_infallible)] +#![feature(wtf8_internals)] // tidy-alphabetical-end // // Language features: @@ -232,6 +233,8 @@ pub mod sync; #[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync)))] pub mod task; pub mod vec; +#[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))] +pub mod wtf8; #[doc(hidden)] #[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")] diff --git a/library/alloc/src/wtf8/mod.rs b/library/alloc/src/wtf8/mod.rs index 50bde88b5a4..95d317a5efb 100644 --- a/library/alloc/src/wtf8/mod.rs +++ b/library/alloc/src/wtf8/mod.rs @@ -1,135 +1,42 @@ -//! Implementation of [the WTF-8 encoding](https://simonsapin.github.io/wtf-8/). -//! -//! This library uses Rust’s type system to maintain -//! [well-formedness](https://simonsapin.github.io/wtf-8/#well-formed), -//! like the `String` and `&str` types do for UTF-8. -//! -//! Since [WTF-8 must not be used -//! for interchange](https://simonsapin.github.io/wtf-8/#intended-audience), -//! this library deliberately does not provide access to the underlying bytes -//! of WTF-8 strings, -//! nor can it decode WTF-8 from arbitrary bytes. -//! WTF-8 strings can be obtained from UTF-8, UTF-16, or code points. - -// this module is imported from @SimonSapin's repo and has tons of dead code on -// unix (it's mostly used on windows), so don't worry about dead code here. -#![allow(dead_code)] +//! Heap-allocated counterpart to core `wtf8` module. +#![unstable( + feature = "wtf8_internals", + issue = "none", + reason = "this is internal code for representing OsStr on some platforms and not a public API" +)] +// rustdoc bug: doc(hidden) on the module won't stop types in the module from showing up in trait +// implementations, so, we'll have to add more doc(hidden)s anyway +#![doc(hidden)] + +// Note: This module is also included in the alloctests crate using #[path] to +// run the tests. See the comment there for an explanation why this is the case. #[cfg(test)] mod tests; -use core::char::{MAX_LEN_UTF8, MAX_LEN_UTF16, encode_utf8_raw, encode_utf16_raw}; -use core::clone::CloneToUninit; -use core::str::next_code_point; +use core::char::{MAX_LEN_UTF8, encode_utf8_raw}; +use core::hash::{Hash, Hasher}; +pub use core::wtf8::{CodePoint, Wtf8}; +#[cfg(not(test))] +pub use core::wtf8::{EncodeWide, Wtf8CodePoints}; +use core::{fmt, mem, ops, str}; -use crate::borrow::Cow; +use crate::borrow::{Cow, ToOwned}; +use crate::boxed::Box; use crate::collections::TryReserveError; -use crate::hash::{Hash, Hasher}; -use crate::iter::FusedIterator; +#[cfg(not(test))] use crate::rc::Rc; +use crate::string::String; +#[cfg(all(not(test), target_has_atomic = "ptr"))] use crate::sync::Arc; -use crate::sys_common::AsInner; -use crate::{fmt, mem, ops, slice, str}; - -const UTF8_REPLACEMENT_CHARACTER: &str = "\u{FFFD}"; - -/// A Unicode code point: from U+0000 to U+10FFFF. -/// -/// Compares with the `char` type, -/// which represents a Unicode scalar value: -/// a code point that is not a surrogate (U+D800 to U+DFFF). -#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] -pub struct CodePoint { - value: u32, -} - -/// Format the code point as `U+` followed by four to six hexadecimal digits. -/// Example: `U+1F4A9` -impl fmt::Debug for CodePoint { - #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "U+{:04X}", self.value) - } -} - -impl CodePoint { - /// Unsafely creates a new `CodePoint` without checking the value. - /// - /// Only use when `value` is known to be less than or equal to 0x10FFFF. - #[inline] - pub unsafe fn from_u32_unchecked(value: u32) -> CodePoint { - CodePoint { value } - } - - /// Creates a new `CodePoint` if the value is a valid code point. - /// - /// Returns `None` if `value` is above 0x10FFFF. - #[inline] - pub fn from_u32(value: u32) -> Option { - match value { - 0..=0x10FFFF => Some(CodePoint { value }), - _ => None, - } - } - - /// Creates a new `CodePoint` from a `char`. - /// - /// Since all Unicode scalar values are code points, this always succeeds. - #[inline] - pub fn from_char(value: char) -> CodePoint { - CodePoint { value: value as u32 } - } - - /// Returns the numeric value of the code point. - #[inline] - pub fn to_u32(&self) -> u32 { - self.value - } - - /// Returns the numeric value of the code point if it is a leading surrogate. - #[inline] - pub fn to_lead_surrogate(&self) -> Option { - match self.value { - lead @ 0xD800..=0xDBFF => Some(lead as u16), - _ => None, - } - } - - /// Returns the numeric value of the code point if it is a trailing surrogate. - #[inline] - pub fn to_trail_surrogate(&self) -> Option { - match self.value { - trail @ 0xDC00..=0xDFFF => Some(trail as u16), - _ => None, - } - } - - /// Optionally returns a Unicode scalar value for the code point. - /// - /// Returns `None` if the code point is a surrogate (from U+D800 to U+DFFF). - #[inline] - pub fn to_char(&self) -> Option { - match self.value { - 0xD800..=0xDFFF => None, - _ => Some(unsafe { char::from_u32_unchecked(self.value) }), - } - } - - /// Returns a Unicode scalar value for the code point. - /// - /// Returns `'\u{FFFD}'` (the replacement character “�”) - /// if the code point is a surrogate (from U+D800 to U+DFFF). - #[inline] - pub fn to_char_lossy(&self) -> char { - self.to_char().unwrap_or('\u{FFFD}') - } -} +use crate::vec::Vec; /// An owned, growable string of well-formed WTF-8 data. /// /// Similar to `String`, but can additionally contain surrogate code points /// if they’re not in a surrogate pair. #[derive(Eq, PartialEq, Ord, PartialOrd, Clone)] +#[doc(hidden)] pub struct Wtf8Buf { bytes: Vec, @@ -181,6 +88,7 @@ impl fmt::Display for Wtf8Buf { } } +#[cfg_attr(test, allow(dead_code))] impl Wtf8Buf { /// Creates a new, empty WTF-8 string. #[inline] @@ -245,7 +153,9 @@ impl Wtf8Buf { string.is_known_utf8 = false; // Skip the WTF-8 concatenation check, // surrogate pairs are already decoded by decode_utf16 - string.push_code_point_unchecked(code_point); + unsafe { + string.push_code_point_unchecked(code_point); + } } } } @@ -255,9 +165,9 @@ impl Wtf8Buf { /// Appends the given `char` to the end of this string. /// This does **not** include the WTF-8 concatenation check or `is_known_utf8` check. /// Copied from String::push. - fn push_code_point_unchecked(&mut self, code_point: CodePoint) { + unsafe fn push_code_point_unchecked(&mut self, code_point: CodePoint) { let mut bytes = [0; MAX_LEN_UTF8]; - let bytes = encode_utf8_raw(code_point.value, &mut bytes); + let bytes = encode_utf8_raw(code_point.to_u32(), &mut bytes); self.bytes.extend_from_slice(bytes) } @@ -379,7 +289,7 @@ impl Wtf8Buf { (Some(lead), Some(trail)) => { let len_without_lead_surrogate = self.len() - 3; self.bytes.truncate(len_without_lead_surrogate); - let other_without_trail_surrogate = &other.bytes[3..]; + let other_without_trail_surrogate = &other.as_bytes()[3..]; // 4 bytes for the supplementary code point self.bytes.reserve(4 + other_without_trail_surrogate.len()); self.push_char(decode_surrogate_pair(lead, trail)); @@ -392,7 +302,7 @@ impl Wtf8Buf { self.is_known_utf8 = false; } - self.bytes.extend_from_slice(&other.bytes); + self.bytes.extend_from_slice(other.as_bytes()); } } } @@ -400,7 +310,8 @@ impl Wtf8Buf { /// Append a Unicode scalar value at the end of the string. #[inline] pub fn push_char(&mut self, c: char) { - self.push_code_point_unchecked(CodePoint::from_char(c)) + // SAFETY: It's always safe to push a char. + unsafe { self.push_code_point_unchecked(CodePoint::from_char(c)) } } /// Append a code point at the end of the string. @@ -426,7 +337,7 @@ impl Wtf8Buf { } // No newly paired surrogates at the boundary. - self.push_code_point_unchecked(code_point) + unsafe { self.push_code_point_unchecked(code_point) } } /// Shortens a string to the specified length. @@ -437,7 +348,7 @@ impl Wtf8Buf { /// or if `new_len` is not a code point boundary. #[inline] pub fn truncate(&mut self, new_len: usize) { - assert!(is_code_point_boundary(self, new_len)); + assert!(self.is_code_point_boundary(new_len)); self.bytes.truncate(new_len) } @@ -474,8 +385,7 @@ impl Wtf8Buf { pos = surrogate_pos + 3; // Surrogates and the replacement character are all 3 bytes, so // they can substituted in-place. - self.bytes[surrogate_pos..pos] - .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); + self.bytes[surrogate_pos..pos].copy_from_slice("\u{FFFD}".as_bytes()); } } unsafe { String::from_utf8_unchecked(self.bytes) } @@ -498,7 +408,7 @@ impl Wtf8Buf { /// More well behaving alternative to allowing outer types /// full mutable access to the core `Vec`. #[inline] - pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { + pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { self.bytes.extend_from_slice(other); self.is_known_utf8 = false; } @@ -541,153 +451,13 @@ impl Extend for Wtf8Buf { } } -/// A borrowed slice of well-formed WTF-8 data. -/// -/// Similar to `&str`, but can additionally contain surrogate code points -/// if they’re not in a surrogate pair. -#[derive(Eq, Ord, PartialEq, PartialOrd)] -#[repr(transparent)] -pub struct Wtf8 { - bytes: [u8], -} - -impl AsInner<[u8]> for Wtf8 { - #[inline] - fn as_inner(&self) -> &[u8] { - &self.bytes - } -} - -/// Formats the string in double quotes, with characters escaped according to -/// [`char::escape_debug`] and unpaired surrogates represented as `\u{xxxx}`, -/// where each `x` is a hexadecimal digit. -impl fmt::Debug for Wtf8 { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fn write_str_escaped(f: &mut fmt::Formatter<'_>, s: &str) -> fmt::Result { - use crate::fmt::Write; - for c in s.chars().flat_map(|c| c.escape_debug()) { - f.write_char(c)? - } - Ok(()) - } - - formatter.write_str("\"")?; - let mut pos = 0; - while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) { - write_str_escaped(formatter, unsafe { - str::from_utf8_unchecked(&self.bytes[pos..surrogate_pos]) - })?; - write!(formatter, "\\u{{{:x}}}", surrogate)?; - pos = surrogate_pos + 3; - } - write_str_escaped(formatter, unsafe { str::from_utf8_unchecked(&self.bytes[pos..]) })?; - formatter.write_str("\"") - } -} - -/// Formats the string with unpaired surrogates substituted with the replacement -/// character, U+FFFD. -impl fmt::Display for Wtf8 { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - let wtf8_bytes = &self.bytes; - let mut pos = 0; - loop { - match self.next_surrogate(pos) { - Some((surrogate_pos, _)) => { - formatter.write_str(unsafe { - str::from_utf8_unchecked(&wtf8_bytes[pos..surrogate_pos]) - })?; - formatter.write_str(UTF8_REPLACEMENT_CHARACTER)?; - pos = surrogate_pos + 3; - } - None => { - let s = unsafe { str::from_utf8_unchecked(&wtf8_bytes[pos..]) }; - if pos == 0 { return s.fmt(formatter) } else { return formatter.write_str(s) } - } - } - } - } -} - -impl Wtf8 { - /// Creates a WTF-8 slice from a UTF-8 `&str` slice. - /// - /// Since WTF-8 is a superset of UTF-8, this always succeeds. - #[inline] - pub fn from_str(value: &str) -> &Wtf8 { - unsafe { Wtf8::from_bytes_unchecked(value.as_bytes()) } - } - - /// Creates a WTF-8 slice from a WTF-8 byte slice. - /// - /// Since the byte slice is not checked for valid WTF-8, this functions is - /// marked unsafe. - #[inline] - pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { - // SAFETY: start with &[u8], end with fancy &[u8] - unsafe { &*(value as *const [u8] as *const Wtf8) } - } - - /// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice. - /// - /// Since the byte slice is not checked for valid WTF-8, this functions is - /// marked unsafe. - #[inline] - unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 { - // SAFETY: start with &mut [u8], end with fancy &mut [u8] - unsafe { &mut *(value as *mut [u8] as *mut Wtf8) } - } - - /// Returns the length, in WTF-8 bytes. - #[inline] - pub fn len(&self) -> usize { - self.bytes.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.bytes.is_empty() - } - - /// Returns the code point at `position` if it is in the ASCII range, - /// or `b'\xFF'` otherwise. - /// - /// # Panics - /// - /// Panics if `position` is beyond the end of the string. - #[inline] - pub fn ascii_byte_at(&self, position: usize) -> u8 { - match self.bytes[position] { - ascii_byte @ 0x00..=0x7F => ascii_byte, - _ => 0xFF, - } - } - - /// Returns an iterator for the string’s code points. - #[inline] - pub fn code_points(&self) -> Wtf8CodePoints<'_> { - Wtf8CodePoints { bytes: self.bytes.iter() } - } - - /// Access raw bytes of WTF-8 data - #[inline] - pub fn as_bytes(&self) -> &[u8] { - &self.bytes - } - - /// Tries to convert the string to UTF-8 and return a `&str` slice. - /// - /// Returns `None` if the string contains surrogates. - /// - /// This does not copy the data. - #[inline] - pub fn as_str(&self) -> Result<&str, str::Utf8Error> { - str::from_utf8(&self.bytes) - } +// helps diff +mod wtf8 { + use super::*; /// Creates an owned `Wtf8Buf` from a borrowed `Wtf8`. - pub fn to_owned(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_vec(), is_known_utf8: false } + pub(super) fn to_owned(slice: &Wtf8) -> Wtf8Buf { + Wtf8Buf { bytes: slice.as_bytes().to_vec(), is_known_utf8: false } } /// Lossily converts the string to UTF-8. @@ -696,20 +466,20 @@ impl Wtf8 { /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”). /// /// This only copies the data if necessary (if it contains any surrogate). - pub fn to_string_lossy(&self) -> Cow<'_, str> { - let Some((surrogate_pos, _)) = self.next_surrogate(0) else { - return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }); + pub(super) fn to_string_lossy(slice: &Wtf8) -> Cow<'_, str> { + let Some((surrogate_pos, _)) = slice.next_surrogate(0) else { + return Cow::Borrowed(unsafe { str::from_utf8_unchecked(slice.as_bytes()) }); }; - let wtf8_bytes = &self.bytes; - let mut utf8_bytes = Vec::with_capacity(self.len()); + let wtf8_bytes = slice.as_bytes(); + let mut utf8_bytes = Vec::with_capacity(slice.len()); utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]); - utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); + utf8_bytes.extend_from_slice("\u{FFFD}".as_bytes()); let mut pos = surrogate_pos + 3; loop { - match self.next_surrogate(pos) { + match slice.next_surrogate(pos) { Some((surrogate_pos, _)) => { utf8_bytes.extend_from_slice(&wtf8_bytes[pos..surrogate_pos]); - utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); + utf8_bytes.extend_from_slice("\u{FFFD}".as_bytes()); pos = surrogate_pos + 3; } None => { @@ -720,342 +490,76 @@ impl Wtf8 { } } - /// Converts the WTF-8 string to potentially ill-formed UTF-16 - /// and return an iterator of 16-bit code units. - /// - /// This is lossless: - /// calling `Wtf8Buf::from_ill_formed_utf16` on the resulting code units - /// would always return the original WTF-8 string. #[inline] - pub fn encode_wide(&self) -> EncodeWide<'_> { - EncodeWide { code_points: self.code_points(), extra: 0 } + pub(super) fn clone_into(slice: &Wtf8, buf: &mut Wtf8Buf) { + buf.is_known_utf8 = false; + slice.as_bytes().clone_into(&mut buf.bytes); } +} - #[inline] - fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> { - let mut iter = self.bytes[pos..].iter(); - loop { - let b = *iter.next()?; - if b < 0x80 { - pos += 1; - } else if b < 0xE0 { - iter.next(); - pos += 2; - } else if b == 0xED { - match (iter.next(), iter.next()) { - (Some(&b2), Some(&b3)) if b2 >= 0xA0 => { - return Some((pos, decode_surrogate(b2, b3))); - } - _ => pos += 3, - } - } else if b < 0xF0 { - iter.next(); - iter.next(); - pos += 3; - } else { - iter.next(); - iter.next(); - iter.next(); - pos += 4; - } - } - } +use self::wtf8::{to_owned, to_string_lossy, clone_into}; - #[inline] - fn final_lead_surrogate(&self) -> Option { - match self.bytes { - [.., 0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)), - _ => None, - } +#[cfg(not(test))] +impl Wtf8 { + #[rustc_allow_incoherent_impl] + pub fn to_owned(&self) -> Wtf8Buf { + to_owned(self) } - #[inline] - fn initial_trail_surrogate(&self) -> Option { - match self.bytes { - [0xED, b2 @ 0xB0..=0xBF, b3, ..] => Some(decode_surrogate(b2, b3)), - _ => None, - } + #[rustc_allow_incoherent_impl] + pub fn clone_into(&self, buf: &mut Wtf8Buf) { + clone_into(self, buf) } - pub fn clone_into(&self, buf: &mut Wtf8Buf) { - buf.is_known_utf8 = false; - self.bytes.clone_into(&mut buf.bytes); + #[rustc_allow_incoherent_impl] + pub fn to_string_lossy(&self) -> Cow<'_, str> { + to_string_lossy(self) } - /// Boxes this `Wtf8`. - #[inline] + #[rustc_allow_incoherent_impl] pub fn into_box(&self) -> Box { - let boxed: Box<[u8]> = self.bytes.into(); + let boxed: Box<[u8]> = self.as_bytes().into(); unsafe { mem::transmute(boxed) } } - /// Creates a boxed, empty `Wtf8`. + #[rustc_allow_incoherent_impl] pub fn empty_box() -> Box { let boxed: Box<[u8]> = Default::default(); unsafe { mem::transmute(boxed) } } - #[inline] + #[cfg(target_has_atomic = "ptr")] + #[rustc_allow_incoherent_impl] pub fn into_arc(&self) -> Arc { - let arc: Arc<[u8]> = Arc::from(&self.bytes); + let arc: Arc<[u8]> = Arc::from(self.as_bytes()); unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Wtf8) } } - #[inline] + #[rustc_allow_incoherent_impl] pub fn into_rc(&self) -> Rc { - let rc: Rc<[u8]> = Rc::from(&self.bytes); + let rc: Rc<[u8]> = Rc::from(self.as_bytes()); unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Wtf8) } } #[inline] - pub fn make_ascii_lowercase(&mut self) { - self.bytes.make_ascii_lowercase() - } - - #[inline] - pub fn make_ascii_uppercase(&mut self) { - self.bytes.make_ascii_uppercase() - } - - #[inline] + #[rustc_allow_incoherent_impl] pub fn to_ascii_lowercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_lowercase(), is_known_utf8: false } + Wtf8Buf { bytes: self.as_bytes().to_ascii_lowercase(), is_known_utf8: false } } #[inline] + #[rustc_allow_incoherent_impl] pub fn to_ascii_uppercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_uppercase(), is_known_utf8: false } - } - - #[inline] - pub fn is_ascii(&self) -> bool { - self.bytes.is_ascii() - } - - #[inline] - pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { - self.bytes.eq_ignore_ascii_case(&other.bytes) - } -} - -/// Returns a slice of the given string for the byte range \[`begin`..`end`). -/// -/// # Panics -/// -/// Panics when `begin` and `end` do not point to code point boundaries, -/// or point beyond the end of the string. -impl ops::Index> for Wtf8 { - type Output = Wtf8; - - #[inline] - fn index(&self, range: ops::Range) -> &Wtf8 { - // is_code_point_boundary checks that the index is in [0, .len()] - if range.start <= range.end - && is_code_point_boundary(self, range.start) - && is_code_point_boundary(self, range.end) - { - unsafe { slice_unchecked(self, range.start, range.end) } - } else { - slice_error_fail(self, range.start, range.end) - } - } -} - -/// Returns a slice of the given string from byte `begin` to its end. -/// -/// # Panics -/// -/// Panics when `begin` is not at a code point boundary, -/// or is beyond the end of the string. -impl ops::Index> for Wtf8 { - type Output = Wtf8; - - #[inline] - fn index(&self, range: ops::RangeFrom) -> &Wtf8 { - // is_code_point_boundary checks that the index is in [0, .len()] - if is_code_point_boundary(self, range.start) { - unsafe { slice_unchecked(self, range.start, self.len()) } - } else { - slice_error_fail(self, range.start, self.len()) - } + Wtf8Buf { bytes: self.as_bytes().to_ascii_uppercase(), is_known_utf8: false } } } -/// Returns a slice of the given string from its beginning to byte `end`. -/// -/// # Panics -/// -/// Panics when `end` is not at a code point boundary, -/// or is beyond the end of the string. -impl ops::Index> for Wtf8 { - type Output = Wtf8; - - #[inline] - fn index(&self, range: ops::RangeTo) -> &Wtf8 { - // is_code_point_boundary checks that the index is in [0, .len()] - if is_code_point_boundary(self, range.end) { - unsafe { slice_unchecked(self, 0, range.end) } - } else { - slice_error_fail(self, 0, range.end) - } - } -} - -impl ops::Index for Wtf8 { - type Output = Wtf8; - - #[inline] - fn index(&self, _range: ops::RangeFull) -> &Wtf8 { - self - } -} - -#[inline] -fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 { - // The first byte is assumed to be 0xED - 0xD800 | (second_byte as u16 & 0x3F) << 6 | third_byte as u16 & 0x3F -} - #[inline] fn decode_surrogate_pair(lead: u16, trail: u16) -> char { let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32); unsafe { char::from_u32_unchecked(code_point) } } -/// Copied from str::is_char_boundary -#[inline] -pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool { - if index == 0 { - return true; - } - match slice.bytes.get(index) { - None => index == slice.len(), - Some(&b) => (b as i8) >= -0x40, - } -} - -/// Verify that `index` is at the edge of either a valid UTF-8 codepoint -/// (i.e. a codepoint that's not a surrogate) or of the whole string. -/// -/// These are the cases currently permitted by `OsStr::slice_encoded_bytes`. -/// Splitting between surrogates is valid as far as WTF-8 is concerned, but -/// we do not permit it in the public API because WTF-8 is considered an -/// implementation detail. -#[track_caller] -#[inline] -pub fn check_utf8_boundary(slice: &Wtf8, index: usize) { - if index == 0 { - return; - } - match slice.bytes.get(index) { - Some(0xED) => (), // Might be a surrogate - Some(&b) if (b as i8) >= -0x40 => return, - Some(_) => panic!("byte index {index} is not a codepoint boundary"), - None if index == slice.len() => return, - None => panic!("byte index {index} is out of bounds"), - } - if slice.bytes[index + 1] >= 0xA0 { - // There's a surrogate after index. Now check before index. - if index >= 3 && slice.bytes[index - 3] == 0xED && slice.bytes[index - 2] >= 0xA0 { - panic!("byte index {index} lies between surrogate codepoints"); - } - } -} - -/// Copied from core::str::raw::slice_unchecked -#[inline] -pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { - // SAFETY: memory layout of a &[u8] and &Wtf8 are the same - unsafe { - let len = end - begin; - let start = s.as_bytes().as_ptr().add(begin); - Wtf8::from_bytes_unchecked(slice::from_raw_parts(start, len)) - } -} - -/// Copied from core::str::raw::slice_error_fail -#[inline(never)] -pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! { - assert!(begin <= end); - panic!("index {begin} and/or {end} in `{s:?}` do not lie on character boundary"); -} - -/// Iterator for the code points of a WTF-8 string. -/// -/// Created with the method `.code_points()`. -#[derive(Clone)] -pub struct Wtf8CodePoints<'a> { - bytes: slice::Iter<'a, u8>, -} - -impl Iterator for Wtf8CodePoints<'_> { - type Item = CodePoint; - - #[inline] - fn next(&mut self) -> Option { - // SAFETY: `self.bytes` has been created from a WTF-8 string - unsafe { next_code_point(&mut self.bytes).map(|c| CodePoint { value: c }) } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.bytes.len(); - (len.saturating_add(3) / 4, Some(len)) - } -} - -/// Generates a wide character sequence for potentially ill-formed UTF-16. -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct EncodeWide<'a> { - code_points: Wtf8CodePoints<'a>, - extra: u16, -} - -// Copied from libunicode/u_str.rs -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for EncodeWide<'_> { - type Item = u16; - - #[inline] - fn next(&mut self) -> Option { - if self.extra != 0 { - let tmp = self.extra; - self.extra = 0; - return Some(tmp); - } - - let mut buf = [0; MAX_LEN_UTF16]; - self.code_points.next().map(|code_point| { - let n = encode_utf16_raw(code_point.value, &mut buf).len(); - if n == 2 { - self.extra = buf[1]; - } - buf[0] - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.code_points.size_hint(); - let ext = (self.extra != 0) as usize; - // every code point gets either one u16 or two u16, - // so this iterator is between 1 or 2 times as - // long as the underlying iterator. - (low + ext, high.and_then(|n| n.checked_mul(2)).and_then(|n| n.checked_add(ext))) - } -} - -#[stable(feature = "encode_wide_fused_iterator", since = "1.62.0")] -impl FusedIterator for EncodeWide<'_> {} - -impl Hash for CodePoint { - #[inline] - fn hash(&self, state: &mut H) { - self.value.hash(state) - } -} - impl Hash for Wtf8Buf { #[inline] fn hash(&self, state: &mut H) { @@ -1063,21 +567,3 @@ impl Hash for Wtf8Buf { 0xfeu8.hash(state) } } - -impl Hash for Wtf8 { - #[inline] - fn hash(&self, state: &mut H) { - state.write(&self.bytes); - 0xfeu8.hash(state) - } -} - -#[unstable(feature = "clone_to_uninit", issue = "126799")] -unsafe impl CloneToUninit for Wtf8 { - #[inline] - #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut u8) { - // SAFETY: we're just a transparent wrapper around [u8] - unsafe { self.bytes.clone_to_uninit(dst) } - } -} diff --git a/library/alloc/src/wtf8/tests.rs b/library/alloc/src/wtf8/tests.rs index b57c99a8452..291f63f9f9e 100644 --- a/library/alloc/src/wtf8/tests.rs +++ b/library/alloc/src/wtf8/tests.rs @@ -1,3 +1,5 @@ +use realalloc::string::ToString; + use super::*; #[test] @@ -82,82 +84,85 @@ fn code_point_to_char_lossy() { #[test] fn wtf8buf_new() { - assert_eq!(Wtf8Buf::new().bytes, b""); + assert_eq!(Wtf8Buf::new().as_bytes(), b""); } #[test] fn wtf8buf_from_str() { - assert_eq!(Wtf8Buf::from_str("").bytes, b""); - assert_eq!(Wtf8Buf::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert_eq!(Wtf8Buf::from_str("").as_bytes(), b""); + assert_eq!(Wtf8Buf::from_str("aé 💩").as_bytes(), b"a\xC3\xA9 \xF0\x9F\x92\xA9"); } #[test] fn wtf8buf_from_string() { - assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b""); - assert_eq!(Wtf8Buf::from_string(String::from("aé 💩")).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert_eq!(Wtf8Buf::from_string(String::from("")).as_bytes(), b""); + assert_eq!( + Wtf8Buf::from_string(String::from("aé 💩")).as_bytes(), + b"a\xC3\xA9 \xF0\x9F\x92\xA9" + ); } #[test] fn wtf8buf_from_wide() { let buf = Wtf8Buf::from_wide(&[]); - assert_eq!(buf.bytes, b""); + assert_eq!(buf.as_bytes(), b""); assert!(buf.is_known_utf8); let buf = Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xDCA9]); - assert_eq!(buf.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert_eq!(buf.as_bytes(), b"a\xC3\xA9 \xF0\x9F\x92\xA9"); assert!(buf.is_known_utf8); let buf = Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]); - assert_eq!(buf.bytes, b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9"); + assert_eq!(buf.as_bytes(), b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9"); assert!(!buf.is_known_utf8); let buf = Wtf8Buf::from_wide(&[0xD800]); - assert_eq!(buf.bytes, b"\xED\xA0\x80"); + assert_eq!(buf.as_bytes(), b"\xED\xA0\x80"); assert!(!buf.is_known_utf8); let buf = Wtf8Buf::from_wide(&[0xDBFF]); - assert_eq!(buf.bytes, b"\xED\xAF\xBF"); + assert_eq!(buf.as_bytes(), b"\xED\xAF\xBF"); assert!(!buf.is_known_utf8); let buf = Wtf8Buf::from_wide(&[0xDC00]); - assert_eq!(buf.bytes, b"\xED\xB0\x80"); + assert_eq!(buf.as_bytes(), b"\xED\xB0\x80"); assert!(!buf.is_known_utf8); let buf = Wtf8Buf::from_wide(&[0xDFFF]); - assert_eq!(buf.bytes, b"\xED\xBF\xBF"); + assert_eq!(buf.as_bytes(), b"\xED\xBF\xBF"); assert!(!buf.is_known_utf8); } #[test] fn wtf8buf_push_str() { let mut string = Wtf8Buf::new(); - assert_eq!(string.bytes, b""); + assert_eq!(string.as_bytes(), b""); assert!(string.is_known_utf8); string.push_str("aé 💩"); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert_eq!(string.as_bytes(), b"a\xC3\xA9 \xF0\x9F\x92\xA9"); assert!(string.is_known_utf8); } #[test] fn wtf8buf_push_char() { let mut string = Wtf8Buf::from_str("aé "); - assert_eq!(string.bytes, b"a\xC3\xA9 "); + assert_eq!(string.as_bytes(), b"a\xC3\xA9 "); assert!(string.is_known_utf8); string.push_char('💩'); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert_eq!(string.as_bytes(), b"a\xC3\xA9 \xF0\x9F\x92\xA9"); assert!(string.is_known_utf8); } #[test] fn wtf8buf_push() { let mut string = Wtf8Buf::from_str("aé "); - assert_eq!(string.bytes, b"a\xC3\xA9 "); + assert_eq!(string.as_bytes(), b"a\xC3\xA9 "); assert!(string.is_known_utf8); string.push(CodePoint::from_char('💩')); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert_eq!(string.as_bytes(), b"a\xC3\xA9 \xF0\x9F\x92\xA9"); assert!(string.is_known_utf8); fn c(value: u32) -> CodePoint { @@ -168,53 +173,53 @@ fn wtf8buf_push() { string.push(c(0xD83D)); // lead assert!(!string.is_known_utf8); string.push(c(0xDCA9)); // trail - assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! + assert_eq!(string.as_bytes(), b"\xF0\x9F\x92\xA9"); // Magic! let mut string = Wtf8Buf::new(); string.push(c(0xD83D)); // lead assert!(!string.is_known_utf8); string.push(c(0x20)); // not surrogate string.push(c(0xDCA9)); // trail - assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); + assert_eq!(string.as_bytes(), b"\xED\xA0\xBD \xED\xB2\xA9"); let mut string = Wtf8Buf::new(); string.push(c(0xD800)); // lead assert!(!string.is_known_utf8); string.push(c(0xDBFF)); // lead - assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); + assert_eq!(string.as_bytes(), b"\xED\xA0\x80\xED\xAF\xBF"); let mut string = Wtf8Buf::new(); string.push(c(0xD800)); // lead assert!(!string.is_known_utf8); string.push(c(0xE000)); // not surrogate - assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); + assert_eq!(string.as_bytes(), b"\xED\xA0\x80\xEE\x80\x80"); let mut string = Wtf8Buf::new(); string.push(c(0xD7FF)); // not surrogate assert!(string.is_known_utf8); string.push(c(0xDC00)); // trail assert!(!string.is_known_utf8); - assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); + assert_eq!(string.as_bytes(), b"\xED\x9F\xBF\xED\xB0\x80"); let mut string = Wtf8Buf::new(); string.push(c(0x61)); // not surrogate, < 3 bytes assert!(string.is_known_utf8); string.push(c(0xDC00)); // trail assert!(!string.is_known_utf8); - assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); + assert_eq!(string.as_bytes(), b"\x61\xED\xB0\x80"); let mut string = Wtf8Buf::new(); string.push(c(0xDC00)); // trail assert!(!string.is_known_utf8); - assert_eq!(string.bytes, b"\xED\xB0\x80"); + assert_eq!(string.as_bytes(), b"\xED\xB0\x80"); } #[test] fn wtf8buf_push_wtf8() { let mut string = Wtf8Buf::from_str("aé"); - assert_eq!(string.bytes, b"a\xC3\xA9"); + assert_eq!(string.as_bytes(), b"a\xC3\xA9"); string.push_wtf8(Wtf8::from_str(" 💩")); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert_eq!(string.as_bytes(), b"a\xC3\xA9 \xF0\x9F\x92\xA9"); assert!(string.is_known_utf8); fn w(v: &[u8]) -> &Wtf8 { @@ -224,42 +229,42 @@ fn wtf8buf_push_wtf8() { let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"\xED\xA0\xBD")); // lead string.push_wtf8(w(b"\xED\xB2\xA9")); // trail - assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! + assert_eq!(string.as_bytes(), b"\xF0\x9F\x92\xA9"); // Magic! let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"\xED\xA0\xBD")); // lead string.push_wtf8(w(b" ")); // not surrogate string.push_wtf8(w(b"\xED\xB2\xA9")); // trail - assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); + assert_eq!(string.as_bytes(), b"\xED\xA0\xBD \xED\xB2\xA9"); assert!(!string.is_known_utf8); let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"\xED\xA0\x80")); // lead string.push_wtf8(w(b"\xED\xAF\xBF")); // lead - assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); + assert_eq!(string.as_bytes(), b"\xED\xA0\x80\xED\xAF\xBF"); assert!(!string.is_known_utf8); let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"\xED\xA0\x80")); // lead string.push_wtf8(w(b"\xEE\x80\x80")); // not surrogate - assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); + assert_eq!(string.as_bytes(), b"\xED\xA0\x80\xEE\x80\x80"); assert!(!string.is_known_utf8); let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"\xED\x9F\xBF")); // not surrogate string.push_wtf8(w(b"\xED\xB0\x80")); // trail - assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); + assert_eq!(string.as_bytes(), b"\xED\x9F\xBF\xED\xB0\x80"); assert!(!string.is_known_utf8); let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"a")); // not surrogate, < 3 bytes string.push_wtf8(w(b"\xED\xB0\x80")); // trail - assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); + assert_eq!(string.as_bytes(), b"\x61\xED\xB0\x80"); assert!(!string.is_known_utf8); let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"\xED\xB0\x80")); // trail - assert_eq!(string.bytes, b"\xED\xB0\x80"); + assert_eq!(string.as_bytes(), b"\xED\xB0\x80"); assert!(!string.is_known_utf8); } @@ -269,15 +274,15 @@ fn wtf8buf_truncate() { assert!(string.is_known_utf8); string.truncate(3); - assert_eq!(string.bytes, b"a\xC3\xA9"); + assert_eq!(string.as_bytes(), b"a\xC3\xA9"); assert!(string.is_known_utf8); string.truncate(1); - assert_eq!(string.bytes, b"a"); + assert_eq!(string.as_bytes(), b"a"); assert!(string.is_known_utf8); string.truncate(0); - assert_eq!(string.bytes, b""); + assert_eq!(string.as_bytes(), b""); assert!(string.is_known_utf8); } @@ -287,11 +292,11 @@ fn wtf8buf_truncate_around_non_bmp() { assert!(string.is_known_utf8); string.truncate(4); - assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); + assert_eq!(string.as_bytes(), b"\xF0\x9F\x92\xA9"); assert!(string.is_known_utf8); string.truncate(0); - assert_eq!(string.bytes, b""); + assert_eq!(string.as_bytes(), b""); assert!(string.is_known_utf8); } @@ -361,7 +366,7 @@ fn wtf8buf_from_iterator() { Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true } ); - assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! + assert_eq!(f(&[0xD83D, 0xDCA9]).as_bytes(), b"\xF0\x9F\x92\xA9"); // Magic! assert_eq!( f(&[0xD83D, 0x20, 0xDCA9]), Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false } @@ -401,7 +406,7 @@ fn wtf8buf_extend() { Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true } ); - assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! + assert_eq!(e(&[0xD83D], &[0xDCA9]).as_bytes(), b"\xF0\x9F\x92\xA9"); // Magic! assert_eq!( e(&[0xD83D, 0x20], &[0xDCA9]), Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false } @@ -449,8 +454,8 @@ fn wtf8buf_show_str() { #[test] fn wtf8_from_str() { - assert_eq!(&Wtf8::from_str("").bytes, b""); - assert_eq!(&Wtf8::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert_eq!(&Wtf8::from_str("").as_bytes(), b""); + assert_eq!(&Wtf8::from_str("aé 💩").as_bytes(), b"a\xC3\xA9 \xF0\x9F\x92\xA9"); } #[test] @@ -461,7 +466,7 @@ fn wtf8_len() { #[test] fn wtf8_slice() { - assert_eq!(&Wtf8::from_str("aé 💩")[1..4].bytes, b"\xC3\xA9 "); + assert_eq!(&Wtf8::from_str("aé 💩")[1..4].as_bytes(), b"\xC3\xA9 "); } #[test] @@ -472,7 +477,7 @@ fn wtf8_slice_not_code_point_boundary() { #[test] fn wtf8_slice_from() { - assert_eq!(&Wtf8::from_str("aé 💩")[1..].bytes, b"\xC3\xA9 \xF0\x9F\x92\xA9"); + assert_eq!(&Wtf8::from_str("aé 💩")[1..].as_bytes(), b"\xC3\xA9 \xF0\x9F\x92\xA9"); } #[test] @@ -483,7 +488,7 @@ fn wtf8_slice_from_not_code_point_boundary() { #[test] fn wtf8_slice_to() { - assert_eq!(&Wtf8::from_str("aé 💩")[..4].bytes, b"a\xC3\xA9 "); + assert_eq!(&Wtf8::from_str("aé 💩")[..4].as_bytes(), b"a\xC3\xA9 "); } #[test] @@ -529,12 +534,12 @@ fn wtf8_as_str() { #[test] fn wtf8_to_string_lossy() { - assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed("")); - assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩")); + assert_eq!(to_string_lossy(Wtf8::from_str("")), Cow::Borrowed("")); + assert_eq!(to_string_lossy(Wtf8::from_str("aé 💩")), Cow::Borrowed("aé 💩")); let mut string = Wtf8Buf::from_str("aé 💩"); string.push(CodePoint::from_u32(0xD800).unwrap()); let expected: Cow<'_, str> = Cow::Owned(String::from("aé 💩�")); - assert_eq!(string.to_string_lossy(), expected); + assert_eq!(to_string_lossy(&string), expected); } #[test] @@ -548,7 +553,7 @@ fn wtf8_display() { let mut string = Wtf8Buf::from_str("aé 💩"); string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!("aé 💩�", d(string.as_inner())); + assert_eq!("aé 💩�", d(string.as_ref())); } #[test] @@ -577,67 +582,41 @@ fn wtf8_encode_wide_size_hint() { #[test] fn wtf8_clone_into() { let mut string = Wtf8Buf::new(); - Wtf8::from_str("green").clone_into(&mut string); - assert_eq!(string.bytes, b"green"); + clone_into(Wtf8::from_str("green"), &mut string); + assert_eq!(string.as_bytes(), b"green"); let mut string = Wtf8Buf::from_str("green"); - Wtf8::from_str("").clone_into(&mut string); - assert_eq!(string.bytes, b""); + clone_into(Wtf8::from_str(""), &mut string); + assert_eq!(string.as_bytes(), b""); let mut string = Wtf8Buf::from_str("red"); - Wtf8::from_str("green").clone_into(&mut string); - assert_eq!(string.bytes, b"green"); + clone_into(Wtf8::from_str("green"), &mut string); + assert_eq!(string.as_bytes(), b"green"); let mut string = Wtf8Buf::from_str("green"); - Wtf8::from_str("red").clone_into(&mut string); - assert_eq!(string.bytes, b"red"); + clone_into(Wtf8::from_str("red"), &mut string); + assert_eq!(string.as_bytes(), b"red"); let mut string = Wtf8Buf::from_str("green"); assert!(string.is_known_utf8); - unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").clone_into(&mut string) }; - assert_eq!(string.bytes, b"\xED\xA0\x80"); + clone_into(unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80") }, &mut string); + assert_eq!(string.as_bytes(), b"\xED\xA0\x80"); assert!(!string.is_known_utf8); } -#[test] -fn wtf8_to_ascii_lowercase() { - let lowercase = Wtf8::from_str("").to_ascii_lowercase(); - assert_eq!(lowercase.bytes, b""); - - let lowercase = Wtf8::from_str("GrEeN gRaPeS! 🍇").to_ascii_lowercase(); - assert_eq!(lowercase.bytes, b"green grapes! \xf0\x9f\x8d\x87"); - - let lowercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_ascii_lowercase() }; - assert_eq!(lowercase.bytes, b"\xED\xA0\x80"); - assert!(!lowercase.is_known_utf8); -} - -#[test] -fn wtf8_to_ascii_uppercase() { - let uppercase = Wtf8::from_str("").to_ascii_uppercase(); - assert_eq!(uppercase.bytes, b""); - - let uppercase = Wtf8::from_str("GrEeN gRaPeS! 🍇").to_ascii_uppercase(); - assert_eq!(uppercase.bytes, b"GREEN GRAPES! \xf0\x9f\x8d\x87"); - - let uppercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_ascii_uppercase() }; - assert_eq!(uppercase.bytes, b"\xED\xA0\x80"); - assert!(!uppercase.is_known_utf8); -} - #[test] fn wtf8_make_ascii_lowercase() { let mut lowercase = Wtf8Buf::from_str(""); lowercase.make_ascii_lowercase(); - assert_eq!(lowercase.bytes, b""); + assert_eq!(lowercase.as_bytes(), b""); let mut lowercase = Wtf8Buf::from_str("GrEeN gRaPeS! 🍇"); lowercase.make_ascii_lowercase(); - assert_eq!(lowercase.bytes, b"green grapes! \xf0\x9f\x8d\x87"); + assert_eq!(lowercase.as_bytes(), b"green grapes! \xf0\x9f\x8d\x87"); - let mut lowercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + let mut lowercase = to_owned(unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80") }); lowercase.make_ascii_lowercase(); - assert_eq!(lowercase.bytes, b"\xED\xA0\x80"); + assert_eq!(lowercase.as_bytes(), b"\xED\xA0\x80"); assert!(!lowercase.is_known_utf8); } @@ -645,22 +624,22 @@ fn wtf8_make_ascii_lowercase() { fn wtf8_make_ascii_uppercase() { let mut uppercase = Wtf8Buf::from_str(""); uppercase.make_ascii_uppercase(); - assert_eq!(uppercase.bytes, b""); + assert_eq!(uppercase.as_bytes(), b""); let mut uppercase = Wtf8Buf::from_str("GrEeN gRaPeS! 🍇"); uppercase.make_ascii_uppercase(); - assert_eq!(uppercase.bytes, b"GREEN GRAPES! \xf0\x9f\x8d\x87"); + assert_eq!(uppercase.as_bytes(), b"GREEN GRAPES! \xf0\x9f\x8d\x87"); - let mut uppercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + let mut uppercase = to_owned(unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80") }); uppercase.make_ascii_uppercase(); - assert_eq!(uppercase.bytes, b"\xED\xA0\x80"); + assert_eq!(uppercase.as_bytes(), b"\xED\xA0\x80"); assert!(!uppercase.is_known_utf8); } #[test] fn wtf8_to_owned() { - let string = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; - assert_eq!(string.bytes, b"\xED\xA0\x80"); + let string = to_owned(unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80") }); + assert_eq!(string.as_bytes(), b"\xED\xA0\x80"); assert!(!string.is_known_utf8); } @@ -669,44 +648,44 @@ fn wtf8_valid_utf8_boundaries() { let mut string = Wtf8Buf::from_str("aé 💩"); string.push(CodePoint::from_u32(0xD800).unwrap()); string.push(CodePoint::from_u32(0xD800).unwrap()); - check_utf8_boundary(&string, 0); - check_utf8_boundary(&string, 1); - check_utf8_boundary(&string, 3); - check_utf8_boundary(&string, 4); - check_utf8_boundary(&string, 8); - check_utf8_boundary(&string, 14); + string.check_utf8_boundary(0); + string.check_utf8_boundary(1); + string.check_utf8_boundary(3); + string.check_utf8_boundary(4); + string.check_utf8_boundary(8); + string.check_utf8_boundary(14); assert_eq!(string.len(), 14); string.push_char('a'); - check_utf8_boundary(&string, 14); - check_utf8_boundary(&string, 15); + string.check_utf8_boundary(14); + string.check_utf8_boundary(15); let mut string = Wtf8Buf::from_str("a"); string.push(CodePoint::from_u32(0xD800).unwrap()); - check_utf8_boundary(&string, 1); + string.check_utf8_boundary(1); let mut string = Wtf8Buf::from_str("\u{D7FF}"); string.push(CodePoint::from_u32(0xD800).unwrap()); - check_utf8_boundary(&string, 3); + string.check_utf8_boundary(3); let mut string = Wtf8Buf::new(); string.push(CodePoint::from_u32(0xD800).unwrap()); string.push_char('\u{D7FF}'); - check_utf8_boundary(&string, 3); + string.check_utf8_boundary(3); } #[test] #[should_panic(expected = "byte index 4 is out of bounds")] fn wtf8_utf8_boundary_out_of_bounds() { let string = Wtf8::from_str("aé"); - check_utf8_boundary(&string, 4); + string.check_utf8_boundary(4); } #[test] #[should_panic(expected = "byte index 1 is not a codepoint boundary")] fn wtf8_utf8_boundary_inside_codepoint() { let string = Wtf8::from_str("é"); - check_utf8_boundary(&string, 1); + string.check_utf8_boundary(1); } #[test] @@ -714,7 +693,7 @@ fn wtf8_utf8_boundary_inside_codepoint() { fn wtf8_utf8_boundary_inside_surrogate() { let mut string = Wtf8Buf::new(); string.push(CodePoint::from_u32(0xD800).unwrap()); - check_utf8_boundary(&string, 1); + string.check_utf8_boundary(1); } #[test] @@ -723,20 +702,22 @@ fn wtf8_utf8_boundary_between_surrogates() { let mut string = Wtf8Buf::new(); string.push(CodePoint::from_u32(0xD800).unwrap()); string.push(CodePoint::from_u32(0xD800).unwrap()); - check_utf8_boundary(&string, 3); + string.check_utf8_boundary(3); } #[test] fn wobbled_wtf8_plus_bytes_isnt_utf8() { - let mut string: Wtf8Buf = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + let mut string: Wtf8Buf = to_owned(unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80") }); assert!(!string.is_known_utf8); - string.extend_from_slice(b"some utf-8"); + unsafe { + string.extend_from_slice_unchecked(b"some utf-8"); + } assert!(!string.is_known_utf8); } #[test] fn wobbled_wtf8_plus_str_isnt_utf8() { - let mut string: Wtf8Buf = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + let mut string: Wtf8Buf = to_owned(unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80") }); assert!(!string.is_known_utf8); string.push_str("some utf-8"); assert!(!string.is_known_utf8); diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index 3241b4b0045..97de7d6a701 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -18,6 +18,8 @@ #![feature(allocator_api)] #![feature(array_into_iter_constructors)] #![feature(assert_matches)] +#![feature(char_internals)] +#![feature(char_max_len)] #![feature(core_intrinsics)] #![feature(exact_size_is_empty)] #![feature(extend_one)] @@ -41,6 +43,7 @@ #![feature(trusted_random_access)] #![feature(try_reserve_kind)] #![feature(try_trait_v2)] +#![feature(wtf8_internals)] // tidy-alphabetical-end // // Language features: @@ -68,15 +71,18 @@ extern crate test; mod testing; use realalloc::*; -// We are directly including collections and raw_vec here as both use non-public -// methods and fields in tests and as such need to have the types to test in the -// same crate as the tests themself. +// We are directly including collections, raw_vec, and wtf8 here as they use non-public +// methods and fields in tests and as such need to have the types to test in the same +// crate as the tests themself. #[path = "../alloc/src/collections/mod.rs"] mod collections; #[path = "../alloc/src/raw_vec/mod.rs"] mod raw_vec; +#[path = "../alloc/src/wtf8/mod.rs"] +mod wtf8; + #[allow(dead_code)] // Not used in all configurations pub(crate) mod test_helpers { /// Copied from `std::test_helpers::test_rng`, since these tests rely on the diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index fcfc7f8dd29..447af240a4b 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -3,6 +3,7 @@ #![feature(iter_array_chunks)] #![feature(assert_matches)] #![feature(btree_extract_if)] +#![feature(wtf8_internals)] #![feature(char_max_len)] #![feature(cow_is_borrowed)] #![feature(core_intrinsics)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 71abd707374..2b6ea7d9afc 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -362,6 +362,8 @@ pub mod slice; pub mod str; pub mod time; +pub mod wtf8; + pub mod unicode; /* Async */ diff --git a/library/core/src/num/niche_types.rs b/library/core/src/num/niche_types.rs index d57b1d433e5..610d9d8cf92 100644 --- a/library/core/src/num/niche_types.rs +++ b/library/core/src/num/niche_types.rs @@ -178,3 +178,18 @@ impl NotAllOnesHelper for u64 { impl NotAllOnesHelper for i64 { type Type = I64NotAllOnes; } + +define_valid_range_type! { + pub struct CodePointInner(u32 as u32 in 0..=0x10ffff); +} + +impl CodePointInner { + pub const ZERO: Self = CodePointInner::new(0).unwrap(); +} + +impl Default for CodePointInner { + #[inline] + fn default() -> Self { + Self::ZERO + } +} diff --git a/library/core/src/wtf8.rs b/library/core/src/wtf8.rs index 50bde88b5a4..5631993dea2 100644 --- a/library/core/src/wtf8.rs +++ b/library/core/src/wtf8.rs @@ -10,28 +10,23 @@ //! of WTF-8 strings, //! nor can it decode WTF-8 from arbitrary bytes. //! WTF-8 strings can be obtained from UTF-8, UTF-16, or code points. - -// this module is imported from @SimonSapin's repo and has tons of dead code on -// unix (it's mostly used on windows), so don't worry about dead code here. -#![allow(dead_code)] - -#[cfg(test)] -mod tests; - -use core::char::{MAX_LEN_UTF8, MAX_LEN_UTF16, encode_utf8_raw, encode_utf16_raw}; -use core::clone::CloneToUninit; -use core::str::next_code_point; - -use crate::borrow::Cow; -use crate::collections::TryReserveError; +#![unstable( + feature = "wtf8_internals", + issue = "none", + reason = "this is internal code for representing OsStr on some platforms and not a public API" +)] +// rustdoc bug: doc(hidden) on the module won't stop types in the module from showing up in trait +// implementations, so, we'll have to add more doc(hidden)s anyway +#![doc(hidden)] + +use crate::char::{MAX_LEN_UTF16, encode_utf16_raw}; +use crate::clone::CloneToUninit; +use crate::fmt::{self, Write}; use crate::hash::{Hash, Hasher}; use crate::iter::FusedIterator; -use crate::rc::Rc; -use crate::sync::Arc; -use crate::sys_common::AsInner; -use crate::{fmt, mem, ops, slice, str}; - -const UTF8_REPLACEMENT_CHARACTER: &str = "\u{FFFD}"; +use crate::num::niche_types::CodePointInner; +use crate::str::next_code_point; +use crate::{ops, slice, str}; /// A Unicode code point: from U+0000 to U+10FFFF. /// @@ -39,16 +34,15 @@ const UTF8_REPLACEMENT_CHARACTER: &str = "\u{FFFD}"; /// which represents a Unicode scalar value: /// a code point that is not a surrogate (U+D800 to U+DFFF). #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] -pub struct CodePoint { - value: u32, -} +#[doc(hidden)] +pub struct CodePoint(CodePointInner); /// Format the code point as `U+` followed by four to six hexadecimal digits. /// Example: `U+1F4A9` impl fmt::Debug for CodePoint { #[inline] fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "U+{:04X}", self.value) + write!(formatter, "U+{:04X}", self.0.as_inner()) } } @@ -58,7 +52,8 @@ impl CodePoint { /// Only use when `value` is known to be less than or equal to 0x10FFFF. #[inline] pub unsafe fn from_u32_unchecked(value: u32) -> CodePoint { - CodePoint { value } + // SAFETY: Guaranteed by caller. + CodePoint(unsafe { CodePointInner::new_unchecked(value) }) } /// Creates a new `CodePoint` if the value is a valid code point. @@ -66,10 +61,7 @@ impl CodePoint { /// Returns `None` if `value` is above 0x10FFFF. #[inline] pub fn from_u32(value: u32) -> Option { - match value { - 0..=0x10FFFF => Some(CodePoint { value }), - _ => None, - } + Some(CodePoint(CodePointInner::new(value)?)) } /// Creates a new `CodePoint` from a `char`. @@ -77,19 +69,20 @@ impl CodePoint { /// Since all Unicode scalar values are code points, this always succeeds. #[inline] pub fn from_char(value: char) -> CodePoint { - CodePoint { value: value as u32 } + // SAFETY: All char are valid for this type. + unsafe { CodePoint::from_u32_unchecked(value as u32) } } /// Returns the numeric value of the code point. #[inline] pub fn to_u32(&self) -> u32 { - self.value + self.0.as_inner() } /// Returns the numeric value of the code point if it is a leading surrogate. #[inline] pub fn to_lead_surrogate(&self) -> Option { - match self.value { + match self.to_u32() { lead @ 0xD800..=0xDBFF => Some(lead as u16), _ => None, } @@ -98,7 +91,7 @@ impl CodePoint { /// Returns the numeric value of the code point if it is a trailing surrogate. #[inline] pub fn to_trail_surrogate(&self) -> Option { - match self.value { + match self.to_u32() { trail @ 0xDC00..=0xDFFF => Some(trail as u16), _ => None, } @@ -109,9 +102,10 @@ impl CodePoint { /// Returns `None` if the code point is a surrogate (from U+D800 to U+DFFF). #[inline] pub fn to_char(&self) -> Option { - match self.value { + match self.to_u32() { 0xD800..=0xDFFF => None, - _ => Some(unsafe { char::from_u32_unchecked(self.value) }), + // SAFETY: We explicitly check that the char is valid. + valid => Some(unsafe { char::from_u32_unchecked(valid) }), } } @@ -121,423 +115,7 @@ impl CodePoint { /// if the code point is a surrogate (from U+D800 to U+DFFF). #[inline] pub fn to_char_lossy(&self) -> char { - self.to_char().unwrap_or('\u{FFFD}') - } -} - -/// An owned, growable string of well-formed WTF-8 data. -/// -/// Similar to `String`, but can additionally contain surrogate code points -/// if they’re not in a surrogate pair. -#[derive(Eq, PartialEq, Ord, PartialOrd, Clone)] -pub struct Wtf8Buf { - bytes: Vec, - - /// Do we know that `bytes` holds a valid UTF-8 encoding? We can easily - /// know this if we're constructed from a `String` or `&str`. - /// - /// It is possible for `bytes` to have valid UTF-8 without this being - /// set, such as when we're concatenating `&Wtf8`'s and surrogates become - /// paired, as we don't bother to rescan the entire string. - is_known_utf8: bool, -} - -impl ops::Deref for Wtf8Buf { - type Target = Wtf8; - - fn deref(&self) -> &Wtf8 { - self.as_slice() - } -} - -impl ops::DerefMut for Wtf8Buf { - fn deref_mut(&mut self) -> &mut Wtf8 { - self.as_mut_slice() - } -} - -/// Formats the string in double quotes, with characters escaped according to -/// [`char::escape_debug`] and unpaired surrogates represented as `\u{xxxx}`, -/// where each `x` is a hexadecimal digit. -/// -/// For example, the code units [U+0061, U+D800, U+000A] are formatted as -/// `"a\u{D800}\n"`. -impl fmt::Debug for Wtf8Buf { - #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, formatter) - } -} - -/// Formats the string with unpaired surrogates substituted with the replacement -/// character, U+FFFD. -impl fmt::Display for Wtf8Buf { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(s) = self.as_known_utf8() { - fmt::Display::fmt(s, formatter) - } else { - fmt::Display::fmt(&**self, formatter) - } - } -} - -impl Wtf8Buf { - /// Creates a new, empty WTF-8 string. - #[inline] - pub fn new() -> Wtf8Buf { - Wtf8Buf { bytes: Vec::new(), is_known_utf8: true } - } - - /// Creates a new, empty WTF-8 string with pre-allocated capacity for `capacity` bytes. - #[inline] - pub fn with_capacity(capacity: usize) -> Wtf8Buf { - Wtf8Buf { bytes: Vec::with_capacity(capacity), is_known_utf8: true } - } - - /// Creates a WTF-8 string from a WTF-8 byte vec. - /// - /// Since the byte vec is not checked for valid WTF-8, this function is - /// marked unsafe. - #[inline] - pub unsafe fn from_bytes_unchecked(value: Vec) -> Wtf8Buf { - Wtf8Buf { bytes: value, is_known_utf8: false } - } - - /// Creates a WTF-8 string from a UTF-8 `String`. - /// - /// This takes ownership of the `String` and does not copy. - /// - /// Since WTF-8 is a superset of UTF-8, this always succeeds. - #[inline] - pub const fn from_string(string: String) -> Wtf8Buf { - Wtf8Buf { bytes: string.into_bytes(), is_known_utf8: true } - } - - /// Creates a WTF-8 string from a UTF-8 `&str` slice. - /// - /// This copies the content of the slice. - /// - /// Since WTF-8 is a superset of UTF-8, this always succeeds. - #[inline] - pub fn from_str(s: &str) -> Wtf8Buf { - Wtf8Buf { bytes: s.as_bytes().to_vec(), is_known_utf8: true } - } - - pub fn clear(&mut self) { - self.bytes.clear(); - self.is_known_utf8 = true; - } - - /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units. - /// - /// This is lossless: calling `.encode_wide()` on the resulting string - /// will always return the original code units. - pub fn from_wide(v: &[u16]) -> Wtf8Buf { - let mut string = Wtf8Buf::with_capacity(v.len()); - for item in char::decode_utf16(v.iter().cloned()) { - match item { - Ok(ch) => string.push_char(ch), - Err(surrogate) => { - let surrogate = surrogate.unpaired_surrogate(); - // Surrogates are known to be in the code point range. - let code_point = unsafe { CodePoint::from_u32_unchecked(surrogate as u32) }; - // The string will now contain an unpaired surrogate. - string.is_known_utf8 = false; - // Skip the WTF-8 concatenation check, - // surrogate pairs are already decoded by decode_utf16 - string.push_code_point_unchecked(code_point); - } - } - } - string - } - - /// Appends the given `char` to the end of this string. - /// This does **not** include the WTF-8 concatenation check or `is_known_utf8` check. - /// Copied from String::push. - fn push_code_point_unchecked(&mut self, code_point: CodePoint) { - let mut bytes = [0; MAX_LEN_UTF8]; - let bytes = encode_utf8_raw(code_point.value, &mut bytes); - self.bytes.extend_from_slice(bytes) - } - - #[inline] - pub fn as_slice(&self) -> &Wtf8 { - unsafe { Wtf8::from_bytes_unchecked(&self.bytes) } - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut Wtf8 { - // Safety: `Wtf8` doesn't expose any way to mutate the bytes that would - // cause them to change from well-formed UTF-8 to ill-formed UTF-8, - // which would break the assumptions of the `is_known_utf8` field. - unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) } - } - - /// Converts the string to UTF-8 without validation, if it was created from - /// valid UTF-8. - #[inline] - fn as_known_utf8(&self) -> Option<&str> { - if self.is_known_utf8 { - // SAFETY: The buffer is known to be valid UTF-8. - Some(unsafe { str::from_utf8_unchecked(self.as_bytes()) }) - } else { - None - } - } - - /// Reserves capacity for at least `additional` more bytes to be inserted - /// in the given `Wtf8Buf`. - /// The collection may reserve more space to avoid frequent reallocations. - /// - /// # Panics - /// - /// Panics if the new capacity exceeds `isize::MAX` bytes. - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.bytes.reserve(additional) - } - - /// Tries to reserve capacity for at least `additional` more bytes to be - /// inserted in the given `Wtf8Buf`. The `Wtf8Buf` may reserve more space to - /// avoid frequent reallocations. After calling `try_reserve`, capacity will - /// be greater than or equal to `self.len() + additional`. Does nothing if - /// capacity is already sufficient. This method preserves the contents even - /// if an error occurs. - /// - /// # Errors - /// - /// If the capacity overflows, or the allocator reports a failure, then an error - /// is returned. - #[inline] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.bytes.try_reserve(additional) - } - - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - self.bytes.reserve_exact(additional) - } - - /// Tries to reserve the minimum capacity for exactly `additional` more - /// bytes to be inserted in the given `Wtf8Buf`. After calling - /// `try_reserve_exact`, capacity will be greater than or equal to - /// `self.len() + additional` if it returns `Ok(())`. - /// Does nothing if the capacity is already sufficient. - /// - /// Note that the allocator may give the `Wtf8Buf` more space than it - /// requests. Therefore, capacity can not be relied upon to be precisely - /// minimal. Prefer [`try_reserve`] if future insertions are expected. - /// - /// [`try_reserve`]: Wtf8Buf::try_reserve - /// - /// # Errors - /// - /// If the capacity overflows, or the allocator reports a failure, then an error - /// is returned. - #[inline] - pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.bytes.try_reserve_exact(additional) - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - self.bytes.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.bytes.shrink_to(min_capacity) - } - - #[inline] - pub fn leak<'a>(self) -> &'a mut Wtf8 { - unsafe { Wtf8::from_mut_bytes_unchecked(self.bytes.leak()) } - } - - /// Returns the number of bytes that this string buffer can hold without reallocating. - #[inline] - pub fn capacity(&self) -> usize { - self.bytes.capacity() - } - - /// Append a UTF-8 slice at the end of the string. - #[inline] - pub fn push_str(&mut self, other: &str) { - self.bytes.extend_from_slice(other.as_bytes()) - } - - /// Append a WTF-8 slice at the end of the string. - /// - /// This replaces newly paired surrogates at the boundary - /// with a supplementary code point, - /// like concatenating ill-formed UTF-16 strings effectively would. - #[inline] - pub fn push_wtf8(&mut self, other: &Wtf8) { - match ((&*self).final_lead_surrogate(), other.initial_trail_surrogate()) { - // Replace newly paired surrogates by a supplementary code point. - (Some(lead), Some(trail)) => { - let len_without_lead_surrogate = self.len() - 3; - self.bytes.truncate(len_without_lead_surrogate); - let other_without_trail_surrogate = &other.bytes[3..]; - // 4 bytes for the supplementary code point - self.bytes.reserve(4 + other_without_trail_surrogate.len()); - self.push_char(decode_surrogate_pair(lead, trail)); - self.bytes.extend_from_slice(other_without_trail_surrogate); - } - _ => { - // If we'll be pushing a string containing a surrogate, we may - // no longer have UTF-8. - if self.is_known_utf8 && other.next_surrogate(0).is_some() { - self.is_known_utf8 = false; - } - - self.bytes.extend_from_slice(&other.bytes); - } - } - } - - /// Append a Unicode scalar value at the end of the string. - #[inline] - pub fn push_char(&mut self, c: char) { - self.push_code_point_unchecked(CodePoint::from_char(c)) - } - - /// Append a code point at the end of the string. - /// - /// This replaces newly paired surrogates at the boundary - /// with a supplementary code point, - /// like concatenating ill-formed UTF-16 strings effectively would. - #[inline] - pub fn push(&mut self, code_point: CodePoint) { - if let Some(trail) = code_point.to_trail_surrogate() { - if let Some(lead) = (&*self).final_lead_surrogate() { - let len_without_lead_surrogate = self.len() - 3; - self.bytes.truncate(len_without_lead_surrogate); - self.push_char(decode_surrogate_pair(lead, trail)); - return; - } - - // We're pushing a trailing surrogate. - self.is_known_utf8 = false; - } else if code_point.to_lead_surrogate().is_some() { - // We're pushing a leading surrogate. - self.is_known_utf8 = false; - } - - // No newly paired surrogates at the boundary. - self.push_code_point_unchecked(code_point) - } - - /// Shortens a string to the specified length. - /// - /// # Panics - /// - /// Panics if `new_len` > current length, - /// or if `new_len` is not a code point boundary. - #[inline] - pub fn truncate(&mut self, new_len: usize) { - assert!(is_code_point_boundary(self, new_len)); - self.bytes.truncate(new_len) - } - - /// Consumes the WTF-8 string and tries to convert it to a vec of bytes. - #[inline] - pub fn into_bytes(self) -> Vec { - self.bytes - } - - /// Consumes the WTF-8 string and tries to convert it to UTF-8. - /// - /// This does not copy the data. - /// - /// If the contents are not well-formed UTF-8 - /// (that is, if the string contains surrogates), - /// the original WTF-8 string is returned instead. - pub fn into_string(self) -> Result { - if self.is_known_utf8 || self.next_surrogate(0).is_none() { - Ok(unsafe { String::from_utf8_unchecked(self.bytes) }) - } else { - Err(self) - } - } - - /// Consumes the WTF-8 string and converts it lossily to UTF-8. - /// - /// This does not copy the data (but may overwrite parts of it in place). - /// - /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”) - pub fn into_string_lossy(mut self) -> String { - if !self.is_known_utf8 { - let mut pos = 0; - while let Some((surrogate_pos, _)) = self.next_surrogate(pos) { - pos = surrogate_pos + 3; - // Surrogates and the replacement character are all 3 bytes, so - // they can substituted in-place. - self.bytes[surrogate_pos..pos] - .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); - } - } - unsafe { String::from_utf8_unchecked(self.bytes) } - } - - /// Converts this `Wtf8Buf` into a boxed `Wtf8`. - #[inline] - pub fn into_box(self) -> Box { - // SAFETY: relies on `Wtf8` being `repr(transparent)`. - unsafe { mem::transmute(self.bytes.into_boxed_slice()) } - } - - /// Converts a `Box` into a `Wtf8Buf`. - pub fn from_box(boxed: Box) -> Wtf8Buf { - let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) }; - Wtf8Buf { bytes: bytes.into_vec(), is_known_utf8: false } - } - - /// Provides plumbing to core `Vec::extend_from_slice`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. - #[inline] - pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { - self.bytes.extend_from_slice(other); - self.is_known_utf8 = false; - } -} - -/// Creates a new WTF-8 string from an iterator of code points. -/// -/// This replaces surrogate code point pairs with supplementary code points, -/// like concatenating ill-formed UTF-16 strings effectively would. -impl FromIterator for Wtf8Buf { - fn from_iter>(iter: T) -> Wtf8Buf { - let mut string = Wtf8Buf::new(); - string.extend(iter); - string - } -} - -/// Append code points from an iterator to the string. -/// -/// This replaces surrogate code point pairs with supplementary code points, -/// like concatenating ill-formed UTF-16 strings effectively would. -impl Extend for Wtf8Buf { - fn extend>(&mut self, iter: T) { - let iterator = iter.into_iter(); - let (low, _high) = iterator.size_hint(); - // Lower bound of one byte per code point (ASCII only) - self.bytes.reserve(low); - iterator.for_each(move |code_point| self.push(code_point)); - } - - #[inline] - fn extend_one(&mut self, code_point: CodePoint) { - self.push(code_point); - } - - #[inline] - fn extend_reserve(&mut self, additional: usize) { - // Lower bound of one byte per code point (ASCII only) - self.bytes.reserve(additional); + self.to_char().unwrap_or(char::REPLACEMENT_CHARACTER) } } @@ -547,13 +125,15 @@ impl Extend for Wtf8Buf { /// if they’re not in a surrogate pair. #[derive(Eq, Ord, PartialEq, PartialOrd)] #[repr(transparent)] +#[rustc_has_incoherent_inherent_impls] +#[doc(hidden)] pub struct Wtf8 { bytes: [u8], } -impl AsInner<[u8]> for Wtf8 { +impl AsRef<[u8]> for Wtf8 { #[inline] - fn as_inner(&self) -> &[u8] { + fn as_ref(&self) -> &[u8] { &self.bytes } } @@ -574,12 +154,15 @@ impl fmt::Debug for Wtf8 { formatter.write_str("\"")?; let mut pos = 0; while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) { + // SAFETY: next_surrogate provides an index for a range of valid UTF-8 bytes. write_str_escaped(formatter, unsafe { str::from_utf8_unchecked(&self.bytes[pos..surrogate_pos]) })?; write!(formatter, "\\u{{{:x}}}", surrogate)?; pos = surrogate_pos + 3; } + + // SAFETY: after next_surrogate returns None, the remainder is valid UTF-8. write_str_escaped(formatter, unsafe { str::from_utf8_unchecked(&self.bytes[pos..]) })?; formatter.write_str("\"") } @@ -594,13 +177,15 @@ impl fmt::Display for Wtf8 { loop { match self.next_surrogate(pos) { Some((surrogate_pos, _)) => { + // SAFETY: next_surrogate provides an index for a range of valid UTF-8 bytes. formatter.write_str(unsafe { str::from_utf8_unchecked(&wtf8_bytes[pos..surrogate_pos]) })?; - formatter.write_str(UTF8_REPLACEMENT_CHARACTER)?; + formatter.write_char(char::REPLACEMENT_CHARACTER)?; pos = surrogate_pos + 3; } None => { + // SAFETY: after next_surrogate returns None, the remainder is valid UTF-8. let s = unsafe { str::from_utf8_unchecked(&wtf8_bytes[pos..]) }; if pos == 0 { return s.fmt(formatter) } else { return formatter.write_str(s) } } @@ -611,10 +196,9 @@ impl fmt::Display for Wtf8 { impl Wtf8 { /// Creates a WTF-8 slice from a UTF-8 `&str` slice. - /// - /// Since WTF-8 is a superset of UTF-8, this always succeeds. #[inline] pub fn from_str(value: &str) -> &Wtf8 { + // SAFETY: Since WTF-8 is a superset of UTF-8, this always is valid. unsafe { Wtf8::from_bytes_unchecked(value.as_bytes()) } } @@ -633,7 +217,7 @@ impl Wtf8 { /// Since the byte slice is not checked for valid WTF-8, this functions is /// marked unsafe. #[inline] - unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 { + pub unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 { // SAFETY: start with &mut [u8], end with fancy &mut [u8] unsafe { &mut *(value as *mut [u8] as *mut Wtf8) } } @@ -685,41 +269,6 @@ impl Wtf8 { str::from_utf8(&self.bytes) } - /// Creates an owned `Wtf8Buf` from a borrowed `Wtf8`. - pub fn to_owned(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_vec(), is_known_utf8: false } - } - - /// Lossily converts the string to UTF-8. - /// Returns a UTF-8 `&str` slice if the contents are well-formed in UTF-8. - /// - /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”). - /// - /// This only copies the data if necessary (if it contains any surrogate). - pub fn to_string_lossy(&self) -> Cow<'_, str> { - let Some((surrogate_pos, _)) = self.next_surrogate(0) else { - return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }); - }; - let wtf8_bytes = &self.bytes; - let mut utf8_bytes = Vec::with_capacity(self.len()); - utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]); - utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); - let mut pos = surrogate_pos + 3; - loop { - match self.next_surrogate(pos) { - Some((surrogate_pos, _)) => { - utf8_bytes.extend_from_slice(&wtf8_bytes[pos..surrogate_pos]); - utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); - pos = surrogate_pos + 3; - } - None => { - utf8_bytes.extend_from_slice(&wtf8_bytes[pos..]); - return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) }); - } - } - } - } - /// Converts the WTF-8 string to potentially ill-formed UTF-16 /// and return an iterator of 16-bit code units. /// @@ -732,7 +281,7 @@ impl Wtf8 { } #[inline] - fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> { + pub fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> { let mut iter = self.bytes[pos..].iter(); loop { let b = *iter.next()?; @@ -762,7 +311,7 @@ impl Wtf8 { } #[inline] - fn final_lead_surrogate(&self) -> Option { + pub fn final_lead_surrogate(&self) -> Option { match self.bytes { [.., 0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)), _ => None, @@ -770,43 +319,13 @@ impl Wtf8 { } #[inline] - fn initial_trail_surrogate(&self) -> Option { + pub fn initial_trail_surrogate(&self) -> Option { match self.bytes { [0xED, b2 @ 0xB0..=0xBF, b3, ..] => Some(decode_surrogate(b2, b3)), _ => None, } } - pub fn clone_into(&self, buf: &mut Wtf8Buf) { - buf.is_known_utf8 = false; - self.bytes.clone_into(&mut buf.bytes); - } - - /// Boxes this `Wtf8`. - #[inline] - pub fn into_box(&self) -> Box { - let boxed: Box<[u8]> = self.bytes.into(); - unsafe { mem::transmute(boxed) } - } - - /// Creates a boxed, empty `Wtf8`. - pub fn empty_box() -> Box { - let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - let arc: Arc<[u8]> = Arc::from(&self.bytes); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Wtf8) } - } - - #[inline] - pub fn into_rc(&self) -> Rc { - let rc: Rc<[u8]> = Rc::from(&self.bytes); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Wtf8) } - } - #[inline] pub fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() @@ -818,23 +337,23 @@ impl Wtf8 { } #[inline] - pub fn to_ascii_lowercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_lowercase(), is_known_utf8: false } + pub fn is_ascii(&self) -> bool { + self.bytes.is_ascii() } #[inline] - pub fn to_ascii_uppercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_uppercase(), is_known_utf8: false } + pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { + self.bytes.eq_ignore_ascii_case(&other.bytes) } #[inline] - pub fn is_ascii(&self) -> bool { - self.bytes.is_ascii() + pub fn is_code_point_boundary(&self, index: usize) -> bool { + is_code_point_boundary(self, index) } #[inline] - pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { - self.bytes.eq_ignore_ascii_case(&other.bytes) + pub fn check_utf8_boundary(&self, index: usize) { + check_utf8_boundary(self, index) } } @@ -849,11 +368,11 @@ impl ops::Index> for Wtf8 { #[inline] fn index(&self, range: ops::Range) -> &Wtf8 { - // is_code_point_boundary checks that the index is in [0, .len()] if range.start <= range.end - && is_code_point_boundary(self, range.start) - && is_code_point_boundary(self, range.end) + && self.is_code_point_boundary(range.start) + && self.is_code_point_boundary(range.end) { + // SAFETY: is_code_point_boundary checks that the index is valid unsafe { slice_unchecked(self, range.start, range.end) } } else { slice_error_fail(self, range.start, range.end) @@ -872,8 +391,8 @@ impl ops::Index> for Wtf8 { #[inline] fn index(&self, range: ops::RangeFrom) -> &Wtf8 { - // is_code_point_boundary checks that the index is in [0, .len()] - if is_code_point_boundary(self, range.start) { + if self.is_code_point_boundary(range.start) { + // SAFETY: is_code_point_boundary checks that the index is valid unsafe { slice_unchecked(self, range.start, self.len()) } } else { slice_error_fail(self, range.start, self.len()) @@ -892,8 +411,8 @@ impl ops::Index> for Wtf8 { #[inline] fn index(&self, range: ops::RangeTo) -> &Wtf8 { - // is_code_point_boundary checks that the index is in [0, .len()] - if is_code_point_boundary(self, range.end) { + if self.is_code_point_boundary(range.end) { + // SAFETY: is_code_point_boundary checks that the index is valid unsafe { slice_unchecked(self, 0, range.end) } } else { slice_error_fail(self, 0, range.end) @@ -916,11 +435,7 @@ fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 { 0xD800 | (second_byte as u16 & 0x3F) << 6 | third_byte as u16 & 0x3F } -#[inline] -fn decode_surrogate_pair(lead: u16, trail: u16) -> char { - let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32); - unsafe { char::from_u32_unchecked(code_point) } -} +// helps diff to be unindented /// Copied from str::is_char_boundary #[inline] @@ -964,7 +479,7 @@ pub fn check_utf8_boundary(slice: &Wtf8, index: usize) { /// Copied from core::str::raw::slice_unchecked #[inline] -pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { +unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { // SAFETY: memory layout of a &[u8] and &Wtf8 are the same unsafe { let len = end - begin; @@ -975,7 +490,7 @@ pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { /// Copied from core::str::raw::slice_error_fail #[inline(never)] -pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! { +fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! { assert!(begin <= end); panic!("index {begin} and/or {end} in `{s:?}` do not lie on character boundary"); } @@ -984,6 +499,7 @@ pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! { /// /// Created with the method `.code_points()`. #[derive(Clone)] +#[doc(hidden)] pub struct Wtf8CodePoints<'a> { bytes: slice::Iter<'a, u8>, } @@ -994,7 +510,7 @@ impl Iterator for Wtf8CodePoints<'_> { #[inline] fn next(&mut self) -> Option { // SAFETY: `self.bytes` has been created from a WTF-8 string - unsafe { next_code_point(&mut self.bytes).map(|c| CodePoint { value: c }) } + unsafe { next_code_point(&mut self.bytes).map(|c| CodePoint::from_u32_unchecked(c)) } } #[inline] @@ -1004,9 +520,19 @@ impl Iterator for Wtf8CodePoints<'_> { } } +impl fmt::Debug for Wtf8CodePoints<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Wtf8CodePoints") + // SAFETY: We always leave the string in a valid state after each iteration. + .field(&unsafe { Wtf8::from_bytes_unchecked(self.bytes.as_slice()) }) + .finish() + } +} + /// Generates a wide character sequence for potentially ill-formed UTF-16. #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] +#[doc(hidden)] pub struct EncodeWide<'a> { code_points: Wtf8CodePoints<'a>, extra: u16, @@ -1027,7 +553,7 @@ impl Iterator for EncodeWide<'_> { let mut buf = [0; MAX_LEN_UTF16]; self.code_points.next().map(|code_point| { - let n = encode_utf16_raw(code_point.value, &mut buf).len(); + let n = encode_utf16_raw(code_point.to_u32(), &mut buf).len(); if n == 2 { self.extra = buf[1]; } @@ -1046,21 +572,19 @@ impl Iterator for EncodeWide<'_> { } } +impl fmt::Debug for EncodeWide<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("EncodeWide").finish_non_exhaustive() + } +} + #[stable(feature = "encode_wide_fused_iterator", since = "1.62.0")] impl FusedIterator for EncodeWide<'_> {} impl Hash for CodePoint { #[inline] fn hash(&self, state: &mut H) { - self.value.hash(state) - } -} - -impl Hash for Wtf8Buf { - #[inline] - fn hash(&self, state: &mut H) { - state.write(&self.bytes); - 0xfeu8.hash(state) + self.0.hash(state) } } diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index d2281b1df2f..4415b614817 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -194,6 +194,7 @@ mod time; mod tuple; mod unicode; mod waker; +mod wtf8; /// Copied from `std::test_helpers::test_rng`, see that function for rationale. #[track_caller] diff --git a/library/coretests/tests/wtf8.rs b/library/coretests/tests/wtf8.rs new file mode 100644 index 00000000000..9f187e70630 --- /dev/null +++ b/library/coretests/tests/wtf8.rs @@ -0,0 +1 @@ +// All `wtf8` tests live in library/alloctests/tests/wtf8.rs diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ab417b6c72f..ca76dcc5147 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -391,6 +391,7 @@ #![feature(try_with_capacity)] #![feature(unique_rc_arc)] #![feature(vec_into_raw_parts)] +#![feature(wtf8_internals)] // tidy-alphabetical-end // // Library features (unwind): diff --git a/library/std/src/os/windows/ffi.rs b/library/std/src/os/windows/ffi.rs index 496443dbbc3..345d5b74285 100644 --- a/library/std/src/os/windows/ffi.rs +++ b/library/std/src/os/windows/ffi.rs @@ -53,12 +53,13 @@ #![stable(feature = "rust1", since = "1.0.0")] +use alloc::wtf8::Wtf8Buf; + use crate::ffi::{OsStr, OsString}; +use crate::fmt; +use crate::iter::FusedIterator; use crate::sealed::Sealed; use crate::sys::os_str::Buf; -#[stable(feature = "rust1", since = "1.0.0")] -pub use crate::sys_common::wtf8::EncodeWide; -use crate::sys_common::wtf8::Wtf8Buf; use crate::sys_common::{AsInner, FromInner}; /// Windows-specific extensions to [`OsString`]. @@ -130,6 +131,35 @@ pub trait OsStrExt: Sealed { impl OsStrExt for OsStr { #[inline] fn encode_wide(&self) -> EncodeWide<'_> { - self.as_inner().inner.encode_wide() + EncodeWide { inner: self.as_inner().inner.encode_wide() } + } +} + +/// Iterator returned by [`OsStrExt::encode_wide`]. +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct EncodeWide<'a> { + inner: alloc::wtf8::EncodeWide<'a>, +} +#[stable(feature = "encode_wide_debug", since = "CURRENT_RUSTC_VERSION")] +impl fmt::Debug for EncodeWide<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.inner, f) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for EncodeWide<'_> { + type Item = u16; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() } } +#[stable(feature = "encode_wide_fused_iterator", since = "1.62.0")] +impl FusedIterator for EncodeWide<'_> {} diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index bbc704ebf86..96da891874e 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -1,12 +1,12 @@ //! The underlying OsString/OsStr implementation on Windows is a //! wrapper around the "WTF-8" encoding; see the `wtf8` module for more. +use alloc::wtf8::{Wtf8, Wtf8Buf}; use core::clone::CloneToUninit; use crate::borrow::Cow; use crate::collections::TryReserveError; use crate::rc::Rc; use crate::sync::Arc; -use crate::sys_common::wtf8::{Wtf8, Wtf8Buf, check_utf8_boundary}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, mem}; @@ -220,7 +220,9 @@ impl Buf { /// trailing surrogate half. #[inline] pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { - self.inner.extend_from_slice(other); + unsafe { + self.inner.extend_from_slice_unchecked(other); + } } } @@ -238,7 +240,7 @@ impl Slice { #[track_caller] #[inline] pub fn check_public_boundary(&self, index: usize) { - check_utf8_boundary(&self.inner, index); + self.inner.check_utf8_boundary(index); } #[inline] diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 24b6cff1309..ec45c723e0d 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -21,7 +21,6 @@ mod tests; pub mod wstr; -pub mod wtf8; // common error constructors diff --git a/src/tools/tidy/src/unit_tests.rs b/src/tools/tidy/src/unit_tests.rs index 3d14a467319..7396310ed37 100644 --- a/src/tools/tidy/src/unit_tests.rs +++ b/src/tools/tidy/src/unit_tests.rs @@ -61,6 +61,7 @@ pub fn check(root_path: &Path, stdlib: bool, bad: &mut bool) { || path.ends_with("library/alloc/src/collections/linked_list/tests.rs") || path.ends_with("library/alloc/src/collections/vec_deque/tests.rs") || path.ends_with("library/alloc/src/raw_vec/tests.rs") + || path.ends_with("library/alloc/src/wtf8/tests.rs") } }; -- cgit 1.4.1-3-g733a5 From 7c81a067ea4cfd289d30c3903ac60b113f481c87 Mon Sep 17 00:00:00 2001 From: ltdk Date: Wed, 13 Aug 2025 18:54:48 -0400 Subject: Diff-massaging commit --- library/alloc/src/wtf8/mod.rs | 75 ++++++++++++++++++--------------------- library/core/src/wtf8.rs | 82 +++++++++++++++++++------------------------ 2 files changed, 70 insertions(+), 87 deletions(-) diff --git a/library/alloc/src/wtf8/mod.rs b/library/alloc/src/wtf8/mod.rs index 95d317a5efb..047994adc44 100644 --- a/library/alloc/src/wtf8/mod.rs +++ b/library/alloc/src/wtf8/mod.rs @@ -451,53 +451,46 @@ impl Extend for Wtf8Buf { } } -// helps diff -mod wtf8 { - use super::*; - - /// Creates an owned `Wtf8Buf` from a borrowed `Wtf8`. - pub(super) fn to_owned(slice: &Wtf8) -> Wtf8Buf { - Wtf8Buf { bytes: slice.as_bytes().to_vec(), is_known_utf8: false } - } +/// Creates an owned `Wtf8Buf` from a borrowed `Wtf8`. +pub(super) fn to_owned(slice: &Wtf8) -> Wtf8Buf { + Wtf8Buf { bytes: slice.as_bytes().to_vec(), is_known_utf8: false } +} - /// Lossily converts the string to UTF-8. - /// Returns a UTF-8 `&str` slice if the contents are well-formed in UTF-8. - /// - /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”). - /// - /// This only copies the data if necessary (if it contains any surrogate). - pub(super) fn to_string_lossy(slice: &Wtf8) -> Cow<'_, str> { - let Some((surrogate_pos, _)) = slice.next_surrogate(0) else { - return Cow::Borrowed(unsafe { str::from_utf8_unchecked(slice.as_bytes()) }); - }; - let wtf8_bytes = slice.as_bytes(); - let mut utf8_bytes = Vec::with_capacity(slice.len()); - utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]); - utf8_bytes.extend_from_slice("\u{FFFD}".as_bytes()); - let mut pos = surrogate_pos + 3; - loop { - match slice.next_surrogate(pos) { - Some((surrogate_pos, _)) => { - utf8_bytes.extend_from_slice(&wtf8_bytes[pos..surrogate_pos]); - utf8_bytes.extend_from_slice("\u{FFFD}".as_bytes()); - pos = surrogate_pos + 3; - } - None => { - utf8_bytes.extend_from_slice(&wtf8_bytes[pos..]); - return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) }); - } +/// Lossily converts the string to UTF-8. +/// Returns a UTF-8 `&str` slice if the contents are well-formed in UTF-8. +/// +/// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”). +/// +/// This only copies the data if necessary (if it contains any surrogate). +pub(super) fn to_string_lossy(slice: &Wtf8) -> Cow<'_, str> { + let Some((surrogate_pos, _)) = slice.next_surrogate(0) else { + return Cow::Borrowed(unsafe { str::from_utf8_unchecked(slice.as_bytes()) }); + }; + let wtf8_bytes = slice.as_bytes(); + let mut utf8_bytes = Vec::with_capacity(slice.len()); + utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]); + utf8_bytes.extend_from_slice("\u{FFFD}".as_bytes()); + let mut pos = surrogate_pos + 3; + loop { + match slice.next_surrogate(pos) { + Some((surrogate_pos, _)) => { + utf8_bytes.extend_from_slice(&wtf8_bytes[pos..surrogate_pos]); + utf8_bytes.extend_from_slice("\u{FFFD}".as_bytes()); + pos = surrogate_pos + 3; + } + None => { + utf8_bytes.extend_from_slice(&wtf8_bytes[pos..]); + return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) }); } } } - - #[inline] - pub(super) fn clone_into(slice: &Wtf8, buf: &mut Wtf8Buf) { - buf.is_known_utf8 = false; - slice.as_bytes().clone_into(&mut buf.bytes); - } } -use self::wtf8::{to_owned, to_string_lossy, clone_into}; +#[inline] +pub(super) fn clone_into(slice: &Wtf8, buf: &mut Wtf8Buf) { + buf.is_known_utf8 = false; + slice.as_bytes().clone_into(&mut buf.bytes); +} #[cfg(not(test))] impl Wtf8 { diff --git a/library/core/src/wtf8.rs b/library/core/src/wtf8.rs index 5631993dea2..de0dfa560a3 100644 --- a/library/core/src/wtf8.rs +++ b/library/core/src/wtf8.rs @@ -345,16 +345,6 @@ impl Wtf8 { pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { self.bytes.eq_ignore_ascii_case(&other.bytes) } - - #[inline] - pub fn is_code_point_boundary(&self, index: usize) -> bool { - is_code_point_boundary(self, index) - } - - #[inline] - pub fn check_utf8_boundary(&self, index: usize) { - check_utf8_boundary(self, index) - } } /// Returns a slice of the given string for the byte range \[`begin`..`end`). @@ -435,44 +425,44 @@ fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 { 0xD800 | (second_byte as u16 & 0x3F) << 6 | third_byte as u16 & 0x3F } -// helps diff to be unindented - -/// Copied from str::is_char_boundary -#[inline] -pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool { - if index == 0 { - return true; - } - match slice.bytes.get(index) { - None => index == slice.len(), - Some(&b) => (b as i8) >= -0x40, +impl Wtf8 { + /// Copied from str::is_char_boundary + #[inline] + pub fn is_code_point_boundary(&self, index: usize) -> bool { + if index == 0 { + return true; + } + match self.bytes.get(index) { + None => index == self.len(), + Some(&b) => (b as i8) >= -0x40, + } } -} -/// Verify that `index` is at the edge of either a valid UTF-8 codepoint -/// (i.e. a codepoint that's not a surrogate) or of the whole string. -/// -/// These are the cases currently permitted by `OsStr::slice_encoded_bytes`. -/// Splitting between surrogates is valid as far as WTF-8 is concerned, but -/// we do not permit it in the public API because WTF-8 is considered an -/// implementation detail. -#[track_caller] -#[inline] -pub fn check_utf8_boundary(slice: &Wtf8, index: usize) { - if index == 0 { - return; - } - match slice.bytes.get(index) { - Some(0xED) => (), // Might be a surrogate - Some(&b) if (b as i8) >= -0x40 => return, - Some(_) => panic!("byte index {index} is not a codepoint boundary"), - None if index == slice.len() => return, - None => panic!("byte index {index} is out of bounds"), - } - if slice.bytes[index + 1] >= 0xA0 { - // There's a surrogate after index. Now check before index. - if index >= 3 && slice.bytes[index - 3] == 0xED && slice.bytes[index - 2] >= 0xA0 { - panic!("byte index {index} lies between surrogate codepoints"); + /// Verify that `index` is at the edge of either a valid UTF-8 codepoint + /// (i.e. a codepoint that's not a surrogate) or of the whole string. + /// + /// These are the cases currently permitted by `OsStr::self_encoded_bytes`. + /// Splitting between surrogates is valid as far as WTF-8 is concerned, but + /// we do not permit it in the public API because WTF-8 is considered an + /// implementation detail. + #[track_caller] + #[inline] + pub fn check_utf8_boundary(&self, index: usize) { + if index == 0 { + return; + } + match self.bytes.get(index) { + Some(0xED) => (), // Might be a surrogate + Some(&b) if (b as i8) >= -0x40 => return, + Some(_) => panic!("byte index {index} is not a codepoint boundary"), + None if index == self.len() => return, + None => panic!("byte index {index} is out of bounds"), + } + if self.bytes[index + 1] >= 0xA0 { + // There's a surrogate after index. Now check before index. + if index >= 3 && self.bytes[index - 3] == 0xED && self.bytes[index - 2] >= 0xA0 { + panic!("byte index {index} lies between surrogate codepoints"); + } } } } -- cgit 1.4.1-3-g733a5 From 7dd56b10add80e21514df3a258b02106ebb52245 Mon Sep 17 00:00:00 2001 From: Amanda Stjerna Date: Tue, 19 Aug 2025 12:32:22 +0200 Subject: Region inference: Use outlives-static constraints in constraint search Revise the extra `r: 'static` constraints added upon universe issues to add an explanation, and use that explanation during constraint blame search. This greatly simplifies the region inference logic, which now does not need to reverse-engineer the event that caused a region to outlive 'static. --- .../src/diagnostics/explain_borrow.rs | 2 +- .../rustc_borrowck/src/diagnostics/opaque_types.rs | 7 +- .../src/diagnostics/region_errors.rs | 21 +- compiler/rustc_borrowck/src/handle_placeholders.rs | 212 +++++++++++++++------ .../rustc_borrowck/src/region_infer/graphviz.rs | 10 +- compiler/rustc_borrowck/src/region_infer/mod.rs | 185 ++++++++---------- compiler/rustc_middle/src/mir/query.rs | 11 +- .../issue-111404-1.stderr | 6 +- .../higher-ranked-lifetime-error.stderr | 2 +- .../trait-bounds/due-to-where-clause.stderr | 2 +- .../hr-projection-mismatch.current.stderr | 2 +- tests/ui/nll/ice-106874.stderr | 35 ++-- .../nll/missing-universe-cause-issue-114907.stderr | 6 +- 13 files changed, 283 insertions(+), 218 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index fdca6b56540..fda96dde826 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -565,7 +565,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { let (blame_constraint, path) = self.regioncx.best_blame_constraint( borrow_region, NllRegionVariableOrigin::FreeRegion, - |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region), + outlived_region, ); let BlameConstraint { category, from_closure, cause, .. } = blame_constraint; diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs index f77f759035b..99913626418 100644 --- a/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs +++ b/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs @@ -243,10 +243,9 @@ impl<'tcx> TypeVisitor> for FindOpaqueRegion<'_, 'tcx> { let opaque_region_vid = self.regioncx.to_region_vid(opaque_region); // Find a path between the borrow region and our opaque capture. - if let Some((path, _)) = - self.regioncx.find_constraint_path_between_regions(self.borrow_region, |r| { - r == opaque_region_vid - }) + if let Some(path) = self + .regioncx + .constraint_path_between_regions(self.borrow_region, opaque_region_vid) { for constraint in path { // If we find a call in this path, then check if it defines the opaque. diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index c7d2267e5f7..bec4c934502 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -61,7 +61,7 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal - | ConstraintCategory::IllegalUniverse => "", + | ConstraintCategory::OutlivesUnnameablePlaceholder(..) => "", } } } @@ -369,11 +369,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let error_vid = self.regioncx.region_from_element(longer_fr, &error_element); // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. - let (_, cause) = self.regioncx.find_outlives_blame_span( - longer_fr, - NllRegionVariableOrigin::Placeholder(placeholder), - error_vid, - ); + let cause = self + .regioncx + .best_blame_constraint( + longer_fr, + NllRegionVariableOrigin::Placeholder(placeholder), + error_vid, + ) + .0 + .cause; let universe = placeholder.universe; let universe_info = self.regioncx.universe_info(universe); @@ -429,9 +433,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) { debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); - let (blame_constraint, path) = self.regioncx.best_blame_constraint(fr, fr_origin, |r| { - self.regioncx.provides_universal_region(r, fr, outlived_fr) - }); + let (blame_constraint, path) = + self.regioncx.best_blame_constraint(fr, fr_origin, outlived_fr); let BlameConstraint { category, cause, variance_info, .. } = blame_constraint; debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info); diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs index 4661906fbeb..b97d43a642b 100644 --- a/compiler/rustc_borrowck/src/handle_placeholders.rs +++ b/compiler/rustc_borrowck/src/handle_placeholders.rs @@ -1,6 +1,7 @@ //! Logic for lowering higher-kinded outlives constraints //! (with placeholders and universes) and turn them into regular //! outlives constraints. +use core::cmp; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::FxIndexMap; @@ -10,7 +11,7 @@ use rustc_index::IndexVec; use rustc_infer::infer::RegionVariableOrigin; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::{RegionVid, UniverseIndex}; -use tracing::debug; +use tracing::{debug, trace}; use crate::constraints::{ConstraintSccIndex, OutlivesConstraintSet}; use crate::consumers::OutlivesConstraint; @@ -62,18 +63,71 @@ impl scc::Annotations for SccAnnotations<'_, '_, RegionTracker> { type SccIdx = ConstraintSccIndex; } +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +enum PlaceholderReachability { + /// This SCC reaches no placeholders. + NoPlaceholders, + /// This SCC reaches at least one placeholder. + Placeholders { + /// The largest-universed placeholder we can reach + max_universe: (UniverseIndex, RegionVid), + + /// The placeholder with the smallest ID + min_placeholder: RegionVid, + + /// The placeholder with the largest ID + max_placeholder: RegionVid, + }, +} + +impl PlaceholderReachability { + /// Merge the reachable placeholders of two graph components. + fn merge(self, other: PlaceholderReachability) -> PlaceholderReachability { + use PlaceholderReachability::*; + match (self, other) { + (NoPlaceholders, NoPlaceholders) => NoPlaceholders, + (NoPlaceholders, p @ Placeholders { .. }) + | (p @ Placeholders { .. }, NoPlaceholders) => p, + ( + Placeholders { + min_placeholder: min_pl, + max_placeholder: max_pl, + max_universe: max_u, + }, + Placeholders { min_placeholder, max_placeholder, max_universe }, + ) => Placeholders { + min_placeholder: cmp::min(min_pl, min_placeholder), + max_placeholder: cmp::max(max_pl, max_placeholder), + max_universe: cmp::max(max_u, max_universe), + }, + } + } + + fn max_universe(&self) -> Option<(UniverseIndex, RegionVid)> { + match self { + Self::NoPlaceholders => None, + Self::Placeholders { max_universe, .. } => Some(*max_universe), + } + } + + /// If we have reached placeholders, determine if they can + /// be named from this universe. + fn can_be_named_by(&self, from: UniverseIndex) -> bool { + self.max_universe() + .is_none_or(|(max_placeholder_universe, _)| from.can_name(max_placeholder_universe)) + } +} + /// An annotation for region graph SCCs that tracks /// the values of its elements. This annotates a single SCC. #[derive(Copy, Debug, Clone)] pub(crate) struct RegionTracker { - /// The largest universe of a placeholder reached from this SCC. - /// This includes placeholders within this SCC. - max_placeholder_universe_reached: UniverseIndex, + reachable_placeholders: PlaceholderReachability, /// The largest universe nameable from this SCC. /// It is the smallest nameable universes of all - /// existential regions reachable from it. - max_nameable_universe: UniverseIndex, + /// existential regions reachable from it. Small Rvids are preferred. + max_nameable_universe: (UniverseIndex, RegionVid), /// The representative Region Variable Id for this SCC. pub(crate) representative: Representative, @@ -81,65 +135,75 @@ pub(crate) struct RegionTracker { impl RegionTracker { pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self { - let placeholder_universe = + let reachable_placeholders = if matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)) { - definition.universe + PlaceholderReachability::Placeholders { + max_universe: (definition.universe, rvid), + min_placeholder: rvid, + max_placeholder: rvid, + } } else { - UniverseIndex::ROOT + PlaceholderReachability::NoPlaceholders }; Self { - max_placeholder_universe_reached: placeholder_universe, - max_nameable_universe: definition.universe, + reachable_placeholders, + max_nameable_universe: (definition.universe, rvid), representative: Representative::new(rvid, definition), } } /// The largest universe this SCC can name. It's the smallest - /// largest nameable uninverse of any reachable region. + /// largest nameable universe of any reachable region, or + /// `max_nameable(r) = min (max_nameable(r') for r' reachable from r)` pub(crate) fn max_nameable_universe(self) -> UniverseIndex { - self.max_nameable_universe + self.max_nameable_universe.0 } pub(crate) fn max_placeholder_universe_reached(self) -> UniverseIndex { - self.max_placeholder_universe_reached - } - - fn merge_min_max_seen(&mut self, other: &Self) { - self.max_placeholder_universe_reached = std::cmp::max( - self.max_placeholder_universe_reached, - other.max_placeholder_universe_reached, - ); - - self.max_nameable_universe = - std::cmp::min(self.max_nameable_universe, other.max_nameable_universe); - } - - /// Returns `true` if during the annotated SCC reaches a placeholder - /// with a universe larger than the smallest nameable universe of any - /// reachable existential region. - pub(crate) fn has_incompatible_universes(&self) -> bool { - self.max_nameable_universe().cannot_name(self.max_placeholder_universe_reached) + if let Some((universe, _)) = self.reachable_placeholders.max_universe() { + universe + } else { + UniverseIndex::ROOT + } } /// Determine if the tracked universes of the two SCCs are compatible. pub(crate) fn universe_compatible_with(&self, other: Self) -> bool { + // HACK: We first check whether we can name the highest existential universe + // of `other`. This only exists to avoid errors in case that scc already + // depends on a placeholder it cannot name itself. self.max_nameable_universe().can_name(other.max_nameable_universe()) - || self.max_nameable_universe().can_name(other.max_placeholder_universe_reached) + || other.reachable_placeholders.can_be_named_by(self.max_nameable_universe()) + } + + /// If this SCC reaches a placeholder it can't name, return it. + fn unnameable_placeholder(&self) -> Option<(UniverseIndex, RegionVid)> { + self.reachable_placeholders.max_universe().filter(|&(placeholder_universe, _)| { + !self.max_nameable_universe().can_name(placeholder_universe) + }) } } impl scc::Annotation for RegionTracker { - fn merge_scc(mut self, other: Self) -> Self { - self.representative = self.representative.merge_scc(other.representative); - self.merge_min_max_seen(&other); - self + fn merge_scc(self, other: Self) -> Self { + trace!("{:?} << {:?}", self.representative, other.representative); + + Self { + representative: self.representative.merge_scc(other.representative), + ..self.merge_reached(other) + } } - fn merge_reached(mut self, other: Self) -> Self { - // No update to in-component values, only add seen values. - self.merge_min_max_seen(&other); - self + fn merge_reached(self, other: Self) -> Self { + Self { + max_nameable_universe: cmp::min( + self.max_nameable_universe, + other.max_nameable_universe, + ), + reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders), + representative: self.representative, + } } } @@ -310,28 +374,52 @@ fn rewrite_placeholder_outlives<'tcx>( let annotation = annotations[scc]; - // If this SCC participates in a universe violation, - // e.g. if it reaches a region with a universe smaller than - // the largest region reached, add a requirement that it must - // outlive `'static`. - if annotation.has_incompatible_universes() { - // Optimisation opportunity: this will add more constraints than - // needed for correctness, since an SCC upstream of another with - // a universe violation will "infect" its downstream SCCs to also - // outlive static. - let scc_representative_outlives_static = OutlivesConstraint { - sup: annotation.representative.rvid(), - sub: fr_static, - category: ConstraintCategory::IllegalUniverse, - locations: Locations::All(rustc_span::DUMMY_SP), - span: rustc_span::DUMMY_SP, - variance_info: VarianceDiagInfo::None, - from_closure: false, - }; - outlives_constraints.push(scc_representative_outlives_static); - added_constraints = true; - debug!("Added {:?}: 'static!", annotation.representative.rvid()); - } + let Some((max_u, max_u_rvid)) = annotation.unnameable_placeholder() else { + continue; + }; + + debug!( + "Placeholder universe {max_u:?} is too large for its SCC, represented by {:?}", + annotation.representative + ); + + // We only add one `r: 'static` constraint per SCC, where `r` is the SCC representative. + // That constraint is annotated with some placeholder `unnameable` where + // `unnameable` is unnameable from `r` and there is a path in the constraint graph + // between them. + // + // There is one exception; if some other region in this SCC can't name `'r`, then + // we pick the region with the smallest universe in the SCC, so that a path can + // always start in `'r` to find a motivation that isn't cyclic. + let blame_to = if annotation.representative.rvid() == max_u_rvid { + // Assertion: the region that lowered our universe is an existential one and we are a placeholder! + + // The SCC's representative is not nameable from some region + // that ends up in the SCC. + let small_universed_rvid = annotation.max_nameable_universe.1; + debug!( + "{small_universed_rvid:?} lowered our universe to {:?}", + annotation.max_nameable_universe() + ); + small_universed_rvid + } else { + // `max_u_rvid` is not nameable by the SCC's representative. + max_u_rvid + }; + + // FIXME: if we can extract a useful blame span here, future error + // reporting and constraint search can be simplified. + + added_constraints = true; + outlives_constraints.push(OutlivesConstraint { + sup: annotation.representative.rvid(), + sub: fr_static, + category: ConstraintCategory::OutlivesUnnameablePlaceholder(blame_to), + locations: Locations::All(rustc_span::DUMMY_SP), + span: rustc_span::DUMMY_SP, + variance_info: VarianceDiagInfo::None, + from_closure: false, + }); } added_constraints } diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs index b2f67c43125..526e1850c2e 100644 --- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs +++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs @@ -12,9 +12,13 @@ use rustc_middle::ty::UniverseIndex; use super::*; fn render_outlives_constraint(constraint: &OutlivesConstraint<'_>) -> String { - match constraint.locations { - Locations::All(_) => "All(...)".to_string(), - Locations::Single(loc) => format!("{loc:?}"), + if let ConstraintCategory::OutlivesUnnameablePlaceholder(unnameable) = constraint.category { + format!("{unnameable:?} unnameable") + } else { + match constraint.locations { + Locations::All(_) => "All(...)".to_string(), + Locations::Single(loc) => format!("{loc:?}"), + } } } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 3d95eb4663a..f7b838a4638 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1285,11 +1285,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { { debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus); - let blame_span_category = self.find_outlives_blame_span( - longer_fr, - NllRegionVariableOrigin::FreeRegion, - shorter_fr, - ); + let blame_constraint = self + .best_blame_constraint(longer_fr, NllRegionVariableOrigin::FreeRegion, shorter_fr) + .0; // Grow `shorter_fr` until we find some non-local regions. (We // always will.) We'll call them `shorter_fr+` -- they're ever @@ -1302,8 +1300,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject: ClosureOutlivesSubject::Region(fr_minus), outlived_free_region: fr, - blame_span: blame_span_category.1.span, - category: blame_span_category.0, + blame_span: blame_constraint.cause.span, + category: blame_constraint.category, }); } return RegionRelationCheckResult::Propagated; @@ -1342,66 +1340,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - /// We have a constraint `fr1: fr2` that is not satisfied, where - /// `fr2` represents some universal region. Here, `r` is some - /// region where we know that `fr1: r` and this function has the - /// job of determining whether `r` is "to blame" for the fact that - /// `fr1: fr2` is required. - /// - /// This is true under two conditions: - /// - /// - `r == fr2` - /// - `fr2` is `'static` and `r` is some placeholder in a universe - /// that cannot be named by `fr1`; in that case, we will require - /// that `fr1: 'static` because it is the only way to `fr1: r` to - /// be satisfied. (See `add_incompatible_universe`.) - pub(crate) fn provides_universal_region( + pub(crate) fn constraint_path_between_regions( &self, - r: RegionVid, - fr1: RegionVid, - fr2: RegionVid, - ) -> bool { - debug!("provides_universal_region(r={:?}, fr1={:?}, fr2={:?})", r, fr1, fr2); - let result = { - r == fr2 || { - fr2 == self.universal_regions().fr_static && self.cannot_name_placeholder(fr1, r) - } - }; - debug!("provides_universal_region: result = {:?}", result); - result - } - - /// If `r2` represents a placeholder region, then this returns - /// `true` if `r1` cannot name that placeholder in its - /// value; otherwise, returns `false`. - pub(crate) fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool { - match self.definitions[r2].origin { - NllRegionVariableOrigin::Placeholder(placeholder) => { - let r1_universe = self.definitions[r1].universe; - debug!( - "cannot_name_value_of: universe1={r1_universe:?} placeholder={:?}", - placeholder - ); - r1_universe.cannot_name(placeholder.universe) - } - - NllRegionVariableOrigin::FreeRegion | NllRegionVariableOrigin::Existential { .. } => { - false - } + from_region: RegionVid, + to_region: RegionVid, + ) -> Option>> { + if from_region == to_region { + bug!("Tried to find a path between {from_region:?} and itself!"); } - } - - /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`. - pub(crate) fn find_outlives_blame_span( - &self, - fr1: RegionVid, - fr1_origin: NllRegionVariableOrigin, - fr2: RegionVid, - ) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) { - let BlameConstraint { category, cause, .. } = self - .best_blame_constraint(fr1, fr1_origin, |r| self.provides_universal_region(r, fr1, fr2)) - .0; - (category, cause) + self.constraint_path_to(from_region, |to| to == to_region, true).map(|o| o.0) } /// Walks the graph of constraints (where `'a: 'b` is considered @@ -1410,15 +1357,30 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// Returns: a series of constraints as well as the region `R` /// that passed the target test. + /// If `include_static_outlives_all` is `true`, then the synthetic + /// outlives constraints `'static -> a` for every region `a` are + /// considered in the search, otherwise they are ignored. #[instrument(skip(self, target_test), ret)] - pub(crate) fn find_constraint_path_between_regions( + pub(crate) fn constraint_path_to( &self, from_region: RegionVid, target_test: impl Fn(RegionVid) -> bool, + include_placeholder_static: bool, ) -> Option<(Vec>, RegionVid)> { - self.find_constraint_path_between_regions_inner(true, from_region, &target_test).or_else( - || self.find_constraint_path_between_regions_inner(false, from_region, &target_test), + self.find_constraint_path_between_regions_inner( + true, + from_region, + &target_test, + include_placeholder_static, ) + .or_else(|| { + self.find_constraint_path_between_regions_inner( + false, + from_region, + &target_test, + include_placeholder_static, + ) + }) } /// The constraints we get from equating the hidden type of each use of an opaque @@ -1438,6 +1400,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ignore_opaque_type_constraints: bool, from_region: RegionVid, target_test: impl Fn(RegionVid) -> bool, + include_placeholder_static: bool, ) -> Option<(Vec>, RegionVid)> { let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions); context[from_region] = Trace::StartRegion; @@ -1452,7 +1415,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { while let Some(r) = deque.pop_front() { debug!( - "find_constraint_path_between_regions: from_region={:?} r={:?} value={}", + "constraint_path_to: from_region={:?} r={:?} value={}", from_region, r, self.region_value_str(r), @@ -1525,8 +1488,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { // This loop can be hot. for constraint in edges { match constraint.category { - ConstraintCategory::IllegalUniverse => { - debug!("Ignoring illegal universe constraint: {constraint:?}"); + ConstraintCategory::OutlivesUnnameablePlaceholder(_) + if !include_placeholder_static => + { + debug!("Ignoring illegal placeholder constraint: {constraint:?}"); continue; } ConstraintCategory::OpaqueType if ignore_opaque_type_constraints => { @@ -1535,6 +1500,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } _ => {} } + debug_assert_eq!(constraint.sup, r); handle_trace(constraint.sub, Trace::FromGraph(constraint)); } @@ -1549,33 +1515,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, location: Location) -> RegionVid { trace!(scc = ?self.constraint_sccs.scc(fr1)); trace!(universe = ?self.max_nameable_universe(self.constraint_sccs.scc(fr1))); - self.find_constraint_path_between_regions(fr1, |r| { - // First look for some `r` such that `fr1: r` and `r` is live at `location` + self.constraint_path_to(fr1, |r| { trace!(?r, liveness_constraints=?self.liveness_constraints.pretty_print_live_points(r)); self.liveness_constraints.is_live_at(r, location) - }) - .or_else(|| { - // If we fail to find that, we may find some `r` such that - // `fr1: r` and `r` is a placeholder from some universe - // `fr1` cannot name. This would force `fr1` to be - // `'static`. - self.find_constraint_path_between_regions(fr1, |r| self.cannot_name_placeholder(fr1, r)) - }) - .or_else(|| { - // If we fail to find THAT, it may be that `fr1` is a - // placeholder that cannot "fit" into its SCC. In that - // case, there should be some `r` where `fr1: r` and `fr1` is a - // placeholder that `r` cannot name. We can blame that - // edge. - // - // Remember that if `R1: R2`, then the universe of R1 - // must be able to name the universe of R2, because R2 will - // be at least `'empty(Universe(R2))`, and `R1` must be at - // larger than that. - self.find_constraint_path_between_regions(fr1, |r| self.cannot_name_placeholder(r, fr1)) - }) - .map(|(_path, r)| r) - .unwrap() + }, true).unwrap().1 } /// Get the region outlived by `longer_fr` and live at `element`. @@ -1619,22 +1562,38 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// creating a constraint path that forces `R` to outlive /// `from_region`, and then finding the best choices within that /// path to blame. - #[instrument(level = "debug", skip(self, target_test))] + #[instrument(level = "debug", skip(self))] pub(crate) fn best_blame_constraint( &self, from_region: RegionVid, from_region_origin: NllRegionVariableOrigin, - target_test: impl Fn(RegionVid) -> bool, + to_region: RegionVid, ) -> (BlameConstraint<'tcx>, Vec>) { - // Find all paths - let (path, target_region) = self - .find_constraint_path_between_regions(from_region, target_test) - .or_else(|| { - self.find_constraint_path_between_regions(from_region, |r| { - self.cannot_name_placeholder(from_region, r) - }) - }) - .unwrap(); + assert!(from_region != to_region, "Trying to blame a region for itself!"); + + let path = self.constraint_path_between_regions(from_region, to_region).unwrap(); + + // If we are passing through a constraint added because we reached an unnameable placeholder `'unnameable`, + // redirect search towards `'unnameable`. + let due_to_placeholder_outlives = path.iter().find_map(|c| { + if let ConstraintCategory::OutlivesUnnameablePlaceholder(unnameable) = c.category { + Some(unnameable) + } else { + None + } + }); + + // Edge case: it's possible that `'from_region` is an unnameable placeholder. + let path = if let Some(unnameable) = due_to_placeholder_outlives + && unnameable != from_region + { + // We ignore the extra edges due to unnameable placeholders to get + // an explanation that was present in the original constraint graph. + self.constraint_path_to(from_region, |r| r == unnameable, false).unwrap().0 + } else { + path + }; + debug!( "path={:#?}", path.iter() @@ -1742,7 +1701,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ConstraintCategory::Cast { unsize_to: Some(unsize_ty), is_implicit_coercion: true, - } if target_region == self.universal_regions().fr_static + } if to_region == self.universal_regions().fr_static // Mirror the note's condition, to minimize how often this diverts blame. && let ty::Adt(_, args) = unsize_ty.kind() && args.iter().any(|arg| arg.as_type().is_some_and(|ty| ty.is_trait())) @@ -1780,7 +1739,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // specific, and are not used for relations that would make sense to blame. ConstraintCategory::BoringNoLocation => 6, // Do not blame internal constraints. - ConstraintCategory::IllegalUniverse => 7, + ConstraintCategory::OutlivesUnnameablePlaceholder(_) => 7, ConstraintCategory::Internal => 8, }; @@ -1817,6 +1776,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { path[best_choice] }; + assert!( + !matches!( + best_constraint.category, + ConstraintCategory::OutlivesUnnameablePlaceholder(_) + ), + "Illegal placeholder constraint blamed; should have redirected to other region relation" + ); + let blame_constraint = BlameConstraint { category: best_constraint.category, from_closure: best_constraint.from_closure, diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index a8a95c699d8..466b9c7a3c2 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -149,8 +149,15 @@ pub enum ConstraintCategory<'tcx> { /// A constraint that doesn't correspond to anything the user sees. Internal, - /// An internal constraint derived from an illegal universe relation. - IllegalUniverse, + /// An internal constraint added when a region outlives a placeholder + /// it cannot name and therefore has to outlive `'static`. The argument + /// is the unnameable placeholder and the constraint is always between + /// an SCC representative and `'static`. + OutlivesUnnameablePlaceholder( + #[type_foldable(identity)] + #[type_visitable(ignore)] + ty::RegionVid, + ), } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] diff --git a/tests/ui/associated-inherent-types/issue-111404-1.stderr b/tests/ui/associated-inherent-types/issue-111404-1.stderr index ce49126c316..9a5b69497c0 100644 --- a/tests/ui/associated-inherent-types/issue-111404-1.stderr +++ b/tests/ui/associated-inherent-types/issue-111404-1.stderr @@ -32,12 +32,10 @@ LL | fn bar(_: fn(Foo fn(Foo::Assoc)>::Assoc)) {} = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: higher-ranked subtype error - --> $DIR/issue-111404-1.rs:10:1 + --> $DIR/issue-111404-1.rs:10:8 | LL | fn bar(_: fn(Foo fn(Foo::Assoc)>::Assoc)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + | ^ error: aborting due to 5 previous errors diff --git a/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr b/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr index d7add865aa0..2e3fd612334 100644 --- a/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr +++ b/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr @@ -2,7 +2,7 @@ error: implementation of `FnMut` is not general enough --> $DIR/higher-ranked-lifetime-error.rs:12:5 | LL | assert_all::<_, &String>(id); - | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnMut` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnMut` is not general enough | = note: `for<'a> fn(&'a String) -> &'a String {id}` must implement `FnMut<(&String,)>` = note: ...but it actually implements `FnMut<(&'0 String,)>`, for some specific lifetime `'0` diff --git a/tests/ui/higher-ranked/trait-bounds/due-to-where-clause.stderr b/tests/ui/higher-ranked/trait-bounds/due-to-where-clause.stderr index 916854e07af..6c17b1f4874 100644 --- a/tests/ui/higher-ranked/trait-bounds/due-to-where-clause.stderr +++ b/tests/ui/higher-ranked/trait-bounds/due-to-where-clause.stderr @@ -2,7 +2,7 @@ error: implementation of `Foo` is not general enough --> $DIR/due-to-where-clause.rs:2:5 | LL | test::(&mut 42); - | ^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | = note: `FooS<'_>` must implement `Foo<'0>`, for any lifetime `'0`... = note: ...but `FooS<'_>` actually implements `Foo<'1>`, for some specific lifetime `'1` diff --git a/tests/ui/mismatched_types/hr-projection-mismatch.current.stderr b/tests/ui/mismatched_types/hr-projection-mismatch.current.stderr index a2cec972e4a..6bda7840f7b 100644 --- a/tests/ui/mismatched_types/hr-projection-mismatch.current.stderr +++ b/tests/ui/mismatched_types/hr-projection-mismatch.current.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/hr-projection-mismatch.rs:20:5 | LL | wrap::<_, Thing>(); - | ^^^^^^^^^^^^^^^^ one type is more general than the other + | ^^^^^^^^^^^^^^^^^^ one type is more general than the other | = note: expected reference `&'a _` found reference `&_` diff --git a/tests/ui/nll/ice-106874.stderr b/tests/ui/nll/ice-106874.stderr index ead4d490a62..0edbd7b44ef 100644 --- a/tests/ui/nll/ice-106874.stderr +++ b/tests/ui/nll/ice-106874.stderr @@ -17,6 +17,15 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: implementation of `FnOnce` is not general enough + --> $DIR/ice-106874.rs:8:7 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` + error: implementation of `Fn` is not general enough --> $DIR/ice-106874.rs:8:7 | @@ -34,6 +43,7 @@ LL | A(B(C::new(D::new(move |st| f(st))))) | = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Fn` is not general enough --> $DIR/ice-106874.rs:8:7 @@ -46,45 +56,36 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `FnOnce` is not general enough - --> $DIR/ice-106874.rs:8:9 + --> $DIR/ice-106874.rs:8:7 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Fn` is not general enough - --> $DIR/ice-106874.rs:8:9 + --> $DIR/ice-106874.rs:8:7 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough | = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` - -error: implementation of `FnOnce` is not general enough - --> $DIR/ice-106874.rs:8:9 - | -LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: higher-ranked subtype error - --> $DIR/ice-106874.rs:8:41 + --> $DIR/ice-106874.rs:8:7 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: higher-ranked subtype error --> $DIR/ice-106874.rs:8:41 | LL | A(B(C::new(D::new(move |st| f(st))))) | ^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 10 previous errors diff --git a/tests/ui/nll/missing-universe-cause-issue-114907.stderr b/tests/ui/nll/missing-universe-cause-issue-114907.stderr index 26ad1efec05..c2e91edd138 100644 --- a/tests/ui/nll/missing-universe-cause-issue-114907.stderr +++ b/tests/ui/nll/missing-universe-cause-issue-114907.stderr @@ -38,18 +38,16 @@ LL | accept(callback); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: higher-ranked subtype error - --> $DIR/missing-universe-cause-issue-114907.rs:33:21 + --> $DIR/missing-universe-cause-issue-114907.rs:33:5 | LL | accept(callback); - | ^ + | ^^^^^^^^^^^^^^^^ error: higher-ranked subtype error --> $DIR/missing-universe-cause-issue-114907.rs:33:21 | LL | accept(callback); | ^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 6 previous errors -- cgit 1.4.1-3-g733a5 From 698db13cd068b1807780f97344bb764efc87703f Mon Sep 17 00:00:00 2001 From: Karol Zwolak Date: Wed, 20 Aug 2025 20:23:08 +0200 Subject: improve float to_degrees/to_radians rounding comments and impl * revise comments explaining why we are using literal or expression * add unspecified precision comments as we don't guarantee precision * use expression in `f128::to_degrees()` * make `f64::to_degrees()` impl consistent with other functions --- library/core/src/num/f128.rs | 23 ++++++++++++++++++++--- library/core/src/num/f16.rs | 20 ++++++++++++++++++-- library/core/src/num/f32.rs | 20 +++++++++++++++++++- library/core/src/num/f64.rs | 26 ++++++++++++++++++++++---- 4 files changed, 79 insertions(+), 10 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 69e6c100e76..4282b1af9f2 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -630,6 +630,13 @@ impl f128 { /// Converts radians to degrees. /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// /// ``` /// #![feature(f128)] /// # // FIXME(f16_f128): remove when `eqtf2` is available @@ -645,13 +652,22 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_degrees(self) -> Self { - // Use a literal for better precision. - const PIS_IN_180: f128 = 57.2957795130823208767981548141051703324054724665643215491602_f128; + // The division here is correctly rounded with respect to the true value of 180/π. + // Although π is irrational and already rounded, the double rounding happens + // to produce correct result for f128. + const PIS_IN_180: f128 = 180.0 / consts::PI; self * PIS_IN_180 } /// Converts degrees to radians. /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// /// ``` /// #![feature(f128)] /// # // FIXME(f16_f128): remove when `eqtf2` is available @@ -668,7 +684,8 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_radians(self) -> f128 { - // Use a literal for better precision. + // Use a literal to avoid double rounding, consts::PI is already rounded, + // and dividing would round again. const RADS_PER_DEG: f128 = 0.0174532925199432957692369076848861271344287188854172545609719_f128; self * RADS_PER_DEG diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index b66cef03d20..23a8661c14b 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -625,6 +625,13 @@ impl f16 { /// Converts radians to degrees. /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// /// ``` /// #![feature(f16)] /// # // FIXME(f16_f128): extendhfsf2, truncsfhf2, __gnu_h2f_ieee, __gnu_f2h_ieee missing for many platforms @@ -640,13 +647,21 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_degrees(self) -> Self { - // Use a literal for better precision. + // Use a literal to avoid double rounding, consts::PI is already rounded, + // and dividing would round again. const PIS_IN_180: f16 = 57.2957795130823208767981548141051703_f16; self * PIS_IN_180 } /// Converts degrees to radians. /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// /// ``` /// #![feature(f16)] /// # // FIXME(f16_f128): extendhfsf2, truncsfhf2, __gnu_h2f_ieee, __gnu_f2h_ieee missing for many platforms @@ -663,7 +678,8 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_radians(self) -> f16 { - // Use a literal for better precision. + // Use a literal to avoid double rounding, consts::PI is already rounded, + // and dividing would round again. const RADS_PER_DEG: f16 = 0.017453292519943295769236907684886_f16; self * RADS_PER_DEG } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index f8344da79ad..da08bfc5950 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -839,6 +839,13 @@ impl f32 { /// Converts radians to degrees. /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// /// ``` /// let angle = std::f32::consts::PI; /// @@ -852,13 +859,21 @@ impl f32 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn to_degrees(self) -> f32 { - // Use a constant for better precision. + // Use a literal to avoid double rounding, consts::PI is already rounded, + // and dividing would round again. const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; self * PIS_IN_180 } /// Converts degrees to radians. /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// /// ``` /// let angle = 180.0f32; /// @@ -872,6 +887,9 @@ impl f32 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn to_radians(self) -> f32 { + // The division here is correctly rounded with respect to the true value of π/180. + // Although π is irrational and already rounded, the double rounding happens + // to produce correct result for f32. const RADS_PER_DEG: f32 = consts::PI / 180.0; self * RADS_PER_DEG } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 93da63c896e..dc0977cb147 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -856,6 +856,13 @@ impl f64 { /// Converts radians to degrees. /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// /// ``` /// let angle = std::f64::consts::PI; /// @@ -869,14 +876,22 @@ impl f64 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn to_degrees(self) -> f64 { - // The division here is correctly rounded with respect to the true - // value of 180/π. (This differs from f32, where a constant must be - // used to ensure a correctly rounded result.) - self * (180.0f64 / consts::PI) + // The division here is correctly rounded with respect to the true value of 180/π. + // Although π is irrational and already rounded, the double rounding happens + // to produce correct result for f64. + const PIS_IN_180: f64 = 180.0 / consts::PI; + self * PIS_IN_180 } /// Converts degrees to radians. /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// /// ``` /// let angle = 180.0_f64; /// @@ -890,6 +905,9 @@ impl f64 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn to_radians(self) -> f64 { + // The division here is correctly rounded with respect to the true value of π/180. + // Although π is irrational and already rounded, the double rounding happens + // to produce correct result for f64. const RADS_PER_DEG: f64 = consts::PI / 180.0; self * RADS_PER_DEG } -- cgit 1.4.1-3-g733a5 From e42c1b12961385d6a5e9e442344fcaef8678ab58 Mon Sep 17 00:00:00 2001 From: okaneco <47607823+okaneco@users.noreply.github.com> Date: Fri, 22 Aug 2025 11:58:36 -0400 Subject: Stabilize `round_char_boundary` feature --- compiler/rustc_middle/src/lib.rs | 2 +- compiler/rustc_span/src/lib.rs | 2 +- library/alloctests/tests/lib.rs | 1 - library/core/src/str/mod.rs | 8 +++---- library/std/src/lib.rs | 1 - src/librustdoc/lib.rs | 2 +- src/tools/clippy/clippy_lints/src/lib.rs | 2 +- .../tests/ui/char_indices_as_byte_indices.fixed | 1 - .../tests/ui/char_indices_as_byte_indices.rs | 1 - .../tests/ui/char_indices_as_byte_indices.stderr | 28 +++++++++++----------- 10 files changed, 22 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e5cc23c213d..5d0723a0090 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,6 +29,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(round_char_boundary))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(allocator_api)] @@ -51,7 +52,6 @@ #![feature(negative_impls)] #![feature(never_type)] #![feature(ptr_alignment_type)] -#![feature(round_char_boundary)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![feature(sized_hierarchy)] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index d647ec28aae..ae6755f0764 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -17,6 +17,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(round_char_boundary))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] @@ -26,7 +27,6 @@ #![feature(map_try_insert)] #![feature(negative_impls)] #![feature(read_buf)] -#![feature(round_char_boundary)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index fcfc7f8dd29..cb9479abee3 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -23,7 +23,6 @@ #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] -#![feature(round_char_boundary)] #![feature(slice_partition_dedup)] #![feature(string_from_utf8_lossy_owned)] #![feature(string_remove_matches)] diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 1b6e84175b9..89115b254b1 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -396,7 +396,6 @@ impl str { /// # Examples /// /// ``` - /// #![feature(round_char_boundary)] /// let s = "❤️🧡💛💚💙💜"; /// assert_eq!(s.len(), 26); /// assert!(!s.is_char_boundary(13)); @@ -405,7 +404,8 @@ impl str { /// assert_eq!(closest, 10); /// assert_eq!(&s[..closest], "❤️🧡"); /// ``` - #[unstable(feature = "round_char_boundary", issue = "93743")] + #[stable(feature = "round_char_boundary", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "round_char_boundary", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn floor_char_boundary(&self, index: usize) -> usize { if index >= self.len() { @@ -439,7 +439,6 @@ impl str { /// # Examples /// /// ``` - /// #![feature(round_char_boundary)] /// let s = "❤️🧡💛💚💙💜"; /// assert_eq!(s.len(), 26); /// assert!(!s.is_char_boundary(13)); @@ -448,7 +447,8 @@ impl str { /// assert_eq!(closest, 14); /// assert_eq!(&s[..closest], "❤️🧡💛"); /// ``` - #[unstable(feature = "round_char_boundary", issue = "93743")] + #[stable(feature = "round_char_boundary", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "round_char_boundary", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn ceil_char_boundary(&self, index: usize) -> usize { if index >= self.len() { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ab417b6c72f..74ac1230ff5 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -263,7 +263,6 @@ all(target_vendor = "fortanix", target_env = "sgx"), feature(slice_index_methods, coerce_unsized, sgx_platform) )] -#![cfg_attr(any(windows, target_os = "uefi"), feature(round_char_boundary))] #![cfg_attr(target_family = "wasm", feature(stdarch_wasm_atomic_wait))] #![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))] // diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 28dbd8ba7d3..a59272d49c7 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(round_char_boundary))] #![doc( html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/" @@ -12,7 +13,6 @@ #![feature(format_args_nl)] #![feature(if_let_guard)] #![feature(iter_intersperse)] -#![feature(round_char_boundary)] #![feature(rustc_private)] #![feature(test)] #![warn(rustc::internal)] diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 844bc1b0e39..edc91718263 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -7,7 +7,7 @@ #![feature(iter_intersperse)] #![feature(iter_partition_in_place)] #![feature(never_type)] -#![feature(round_char_boundary)] +#![cfg_attr(bootstrap, feature(round_char_boundary))] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] #![feature(unwrap_infallible)] diff --git a/src/tools/clippy/tests/ui/char_indices_as_byte_indices.fixed b/src/tools/clippy/tests/ui/char_indices_as_byte_indices.fixed index 04c8f6782c5..375a101c2e3 100644 --- a/src/tools/clippy/tests/ui/char_indices_as_byte_indices.fixed +++ b/src/tools/clippy/tests/ui/char_indices_as_byte_indices.fixed @@ -1,4 +1,3 @@ -#![feature(round_char_boundary)] #![warn(clippy::char_indices_as_byte_indices)] trait StrExt { diff --git a/src/tools/clippy/tests/ui/char_indices_as_byte_indices.rs b/src/tools/clippy/tests/ui/char_indices_as_byte_indices.rs index 773a4fc65f1..eebc39962a2 100644 --- a/src/tools/clippy/tests/ui/char_indices_as_byte_indices.rs +++ b/src/tools/clippy/tests/ui/char_indices_as_byte_indices.rs @@ -1,4 +1,3 @@ -#![feature(round_char_boundary)] #![warn(clippy::char_indices_as_byte_indices)] trait StrExt { diff --git a/src/tools/clippy/tests/ui/char_indices_as_byte_indices.stderr b/src/tools/clippy/tests/ui/char_indices_as_byte_indices.stderr index e2b4c1db78c..fae81fd772d 100644 --- a/src/tools/clippy/tests/ui/char_indices_as_byte_indices.stderr +++ b/src/tools/clippy/tests/ui/char_indices_as_byte_indices.stderr @@ -1,12 +1,12 @@ error: indexing into a string with a character position where a byte index is expected - --> tests/ui/char_indices_as_byte_indices.rs:13:24 + --> tests/ui/char_indices_as_byte_indices.rs:12:24 | LL | let _ = prim[..idx]; | ^^^ | = note: a character can take up more than one byte, so they are not interchangeable note: position comes from the enumerate iterator - --> tests/ui/char_indices_as_byte_indices.rs:12:10 + --> tests/ui/char_indices_as_byte_indices.rs:11:10 | LL | for (idx, _) in prim.chars().enumerate() { | ^^^ ^^^^^^^^^^^ @@ -19,14 +19,14 @@ LL + for (idx, _) in prim.char_indices() { | error: passing a character position to a method that expects a byte index - --> tests/ui/char_indices_as_byte_indices.rs:15:23 + --> tests/ui/char_indices_as_byte_indices.rs:14:23 | LL | prim.split_at(idx); | ^^^ | = note: a character can take up more than one byte, so they are not interchangeable note: position comes from the enumerate iterator - --> tests/ui/char_indices_as_byte_indices.rs:12:10 + --> tests/ui/char_indices_as_byte_indices.rs:11:10 | LL | for (idx, _) in prim.chars().enumerate() { | ^^^ ^^^^^^^^^^^ @@ -37,14 +37,14 @@ LL + for (idx, _) in prim.char_indices() { | error: passing a character position to a method that expects a byte index - --> tests/ui/char_indices_as_byte_indices.rs:19:49 + --> tests/ui/char_indices_as_byte_indices.rs:18:49 | LL | let _ = prim[..prim.floor_char_boundary(idx)]; | ^^^ | = note: a character can take up more than one byte, so they are not interchangeable note: position comes from the enumerate iterator - --> tests/ui/char_indices_as_byte_indices.rs:12:10 + --> tests/ui/char_indices_as_byte_indices.rs:11:10 | LL | for (idx, _) in prim.chars().enumerate() { | ^^^ ^^^^^^^^^^^ @@ -55,14 +55,14 @@ LL + for (idx, _) in prim.char_indices() { | error: indexing into a string with a character position where a byte index is expected - --> tests/ui/char_indices_as_byte_indices.rs:29:24 + --> tests/ui/char_indices_as_byte_indices.rs:28:24 | LL | let _ = prim[..c.0]; | ^^^ | = note: a character can take up more than one byte, so they are not interchangeable note: position comes from the enumerate iterator - --> tests/ui/char_indices_as_byte_indices.rs:28:9 + --> tests/ui/char_indices_as_byte_indices.rs:27:9 | LL | for c in prim.chars().enumerate() { | ^ ^^^^^^^^^^^ @@ -73,14 +73,14 @@ LL + for c in prim.char_indices() { | error: passing a character position to a method that expects a byte index - --> tests/ui/char_indices_as_byte_indices.rs:31:23 + --> tests/ui/char_indices_as_byte_indices.rs:30:23 | LL | prim.split_at(c.0); | ^^^ | = note: a character can take up more than one byte, so they are not interchangeable note: position comes from the enumerate iterator - --> tests/ui/char_indices_as_byte_indices.rs:28:9 + --> tests/ui/char_indices_as_byte_indices.rs:27:9 | LL | for c in prim.chars().enumerate() { | ^ ^^^^^^^^^^^ @@ -91,14 +91,14 @@ LL + for c in prim.char_indices() { | error: indexing into a string with a character position where a byte index is expected - --> tests/ui/char_indices_as_byte_indices.rs:36:26 + --> tests/ui/char_indices_as_byte_indices.rs:35:26 | LL | let _ = string[..idx]; | ^^^ | = note: a character can take up more than one byte, so they are not interchangeable note: position comes from the enumerate iterator - --> tests/ui/char_indices_as_byte_indices.rs:35:10 + --> tests/ui/char_indices_as_byte_indices.rs:34:10 | LL | for (idx, _) in string.chars().enumerate() { | ^^^ ^^^^^^^^^^^ @@ -109,14 +109,14 @@ LL + for (idx, _) in string.char_indices() { | error: passing a character position to a method that expects a byte index - --> tests/ui/char_indices_as_byte_indices.rs:38:25 + --> tests/ui/char_indices_as_byte_indices.rs:37:25 | LL | string.split_at(idx); | ^^^ | = note: a character can take up more than one byte, so they are not interchangeable note: position comes from the enumerate iterator - --> tests/ui/char_indices_as_byte_indices.rs:35:10 + --> tests/ui/char_indices_as_byte_indices.rs:34:10 | LL | for (idx, _) in string.chars().enumerate() { | ^^^ ^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 6e5a4275f7dca9ba13b4234b3fe821816753d924 Mon Sep 17 00:00:00 2001 From: ivmarkov Date: Fri, 22 Aug 2025 08:02:00 +0000 Subject: Fix STD build failing for target_os = espidf --- library/std/src/sys/fs/mod.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index dbd782f5018..0276bf6e64c 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -117,9 +117,18 @@ pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> { #[cfg(unix)] pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io::Result<()> { use crate::fs::OpenOptions; - use crate::os::unix::fs::OpenOptionsExt; - OpenOptions::new().custom_flags(libc::O_NOFOLLOW).open(path)?.set_permissions(perm) + let mut options = OpenOptions::new(); + + // ESP-IDF and Horizon do not support O_NOFOLLOW, so we skip setting it. + // Their filesystems do not have symbolic links, so no special handling is required. + #[cfg(not(any(target_os = "espidf", target_os = "horizon")))] + { + use crate::os::unix::fs::OpenOptionsExt; + options.custom_flags(libc::O_NOFOLLOW); + } + + options.open(path)?.set_permissions(perm) } #[cfg(not(unix))] -- cgit 1.4.1-3-g733a5 From db4e71683e86e30fda9c2f72c5f4598b230a5a16 Mon Sep 17 00:00:00 2001 From: Havard Eidnes Date: Sat, 23 Aug 2025 18:52:11 +0000 Subject: std library: use execinfo library also on NetBSD. --- library/std/src/sys/pal/unix/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index aef7ab55088..400128acf12 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -382,6 +382,7 @@ cfg_select! { unsafe extern "C" {} } target_os = "netbsd" => { + #[link(name = "execinfo")] #[link(name = "pthread")] #[link(name = "rt")] unsafe extern "C" {} -- cgit 1.4.1-3-g733a5 From ae622bb6af818d8592a143d391d4a7eacfee8f24 Mon Sep 17 00:00:00 2001 From: Amanda Stjerna Date: Sat, 23 Aug 2025 22:25:50 +0200 Subject: Simplify SCC annotations somewhat --- compiler/rustc_borrowck/src/handle_placeholders.rs | 18 +++++++----------- compiler/rustc_borrowck/src/region_infer/mod.rs | 14 +------------- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs index b97d43a642b..94379cdebf7 100644 --- a/compiler/rustc_borrowck/src/handle_placeholders.rs +++ b/compiler/rustc_borrowck/src/handle_placeholders.rs @@ -1,8 +1,6 @@ //! Logic for lowering higher-kinded outlives constraints //! (with placeholders and universes) and turn them into regular //! outlives constraints. -use core::cmp; - use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph::scc; @@ -96,9 +94,9 @@ impl PlaceholderReachability { }, Placeholders { min_placeholder, max_placeholder, max_universe }, ) => Placeholders { - min_placeholder: cmp::min(min_pl, min_placeholder), - max_placeholder: cmp::max(max_pl, max_placeholder), - max_universe: cmp::max(max_u, max_universe), + min_placeholder: min_pl.min(min_placeholder), + max_placeholder: max_pl.max(max_placeholder), + max_universe: max_u.max(max_universe), }, } } @@ -190,17 +188,15 @@ impl scc::Annotation for RegionTracker { trace!("{:?} << {:?}", self.representative, other.representative); Self { - representative: self.representative.merge_scc(other.representative), - ..self.merge_reached(other) + representative: self.representative.min(other.representative), + max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe), + reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders), } } fn merge_reached(self, other: Self) -> Self { Self { - max_nameable_universe: cmp::min( - self.max_nameable_universe, - other.max_nameable_universe, - ), + max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe), reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders), representative: self.representative, } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index f7b838a4638..9990f4cb3f2 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::graph::scc::{self, Sccs}; +use rustc_data_structures::graph::scc::Sccs; use rustc_errors::Diag; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_index::IndexVec; @@ -74,18 +74,6 @@ impl Representative { } } -impl scc::Annotation for Representative { - fn merge_scc(self, other: Self) -> Self { - // Just pick the smallest one. Note that we order by tag first! - std::cmp::min(self, other) - } - - // For reachability, we do nothing since the representative doesn't change. - fn merge_reached(self, _other: Self) -> Self { - self - } -} - pub(crate) type ConstraintSccs = Sccs; pub struct RegionInferenceContext<'tcx> { -- cgit 1.4.1-3-g733a5 From 17c866780e4f60c4b5ce0c0925557949c9c8d8b1 Mon Sep 17 00:00:00 2001 From: Rafael RL Date: Wed, 23 Jul 2025 12:25:20 +0200 Subject: fix(std): Add __my_thread_exit stub for QNX 8 This commit adds an empty stub for the function for QNX 8 targets. This symbol is required by the unwinder but is not present, causing a linking failure when building with the standard library. Address review feedback: use whitelist for QNX versions --- library/std/src/sys/backtrace.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs index 272d0fa4d1a..57682207e07 100644 --- a/library/std/src/sys/backtrace.rs +++ b/library/std/src/sys/backtrace.rs @@ -113,7 +113,7 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: res = bt_fmt.frame().symbol(frame, symbol); } }); - #[cfg(target_os = "nto")] + #[cfg(all(target_os = "nto", any(target_env = "nto70", target_env = "nto71")))] if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { if !hit && print { use crate::backtrace_rs::SymbolName; -- cgit 1.4.1-3-g733a5 From 2e969c720b444420876a2b16cf10402553093a3c Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 25 Aug 2025 10:06:16 -0500 Subject: rustdoc(opt): build_impl: check document_private earlier --- src/librustdoc/clean/inline.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 0d98c64bbde..8461e15c6c3 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -572,30 +572,30 @@ pub(crate) fn build_impl( super::build_deref_target_impls(cx, &trait_items, ret); } - // Return if the trait itself or any types of the generic parameters are doc(hidden). - let mut stack: Vec<&Type> = vec![&for_]; + if !document_hidden { + // Return if the trait itself or any types of the generic parameters are doc(hidden). + let mut stack: Vec<&Type> = vec![&for_]; - if let Some(did) = trait_.as_ref().map(|t| t.def_id()) - && !document_hidden - && tcx.is_doc_hidden(did) - { - return; - } - - if let Some(generics) = trait_.as_ref().and_then(|t| t.generics()) { - stack.extend(generics); - } - - while let Some(ty) = stack.pop() { - if let Some(did) = ty.def_id(&cx.cache) - && !document_hidden + if let Some(did) = trait_.as_ref().map(|t| t.def_id()) && tcx.is_doc_hidden(did) { return; } - if let Some(generics) = ty.generics() { + + if let Some(generics) = trait_.as_ref().and_then(|t| t.generics()) { stack.extend(generics); } + + while let Some(ty) = stack.pop() { + if let Some(did) = ty.def_id(&cx.cache) + && tcx.is_doc_hidden(did) + { + return; + } + if let Some(generics) = ty.generics() { + stack.extend(generics); + } + } } if let Some(did) = trait_.as_ref().map(|t| t.def_id()) { -- cgit 1.4.1-3-g733a5 From f16d1fcb55d0b9c5d2a6c58e20c4352aa4a7c5fd Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 25 Aug 2025 10:26:22 -0500 Subject: use size_hint in attrs_to_doc_fragments --- compiler/rustc_resolve/src/rustdoc.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 6450f63472c..f9f2f84bc50 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -207,8 +207,10 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>( attrs: impl Iterator)>, doc_only: bool, ) -> (Vec, ThinVec) { - let mut doc_fragments = Vec::new(); - let mut other_attrs = ThinVec::::new(); + let (min_size, max_size) = attrs.size_hint(); + let size_hint = max_size.unwrap_or(min_size); + let mut doc_fragments = Vec::with_capacity(size_hint); + let mut other_attrs = ThinVec::::with_capacity(if doc_only { 0 } else { size_hint }); for (attr, item_id) in attrs { if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() { let doc = beautify_doc_string(doc_str, comment_kind); @@ -230,6 +232,9 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>( } } + doc_fragments.shrink_to_fit(); + other_attrs.shrink_to_fit(); + unindent_doc_fragments(&mut doc_fragments); (doc_fragments, other_attrs) -- cgit 1.4.1-3-g733a5 From 904e83c53fece4a34c2e90bb44e362d8868d65f3 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sat, 23 Aug 2025 20:48:44 -0500 Subject: Only consider auto traits empty for the purposes of omitting vptrs from subtrait vtables --- .../rustc_trait_selection/src/traits/vtable.rs | 7 ++- ...trait-with-nonempty-supersupertrait.dump.stderr | 16 +++++++ ...pty-supertrait-with-nonempty-supersupertrait.rs | 49 +++++++++++++++++++++ tests/ui/traits/vtable/multiple-auto.rs | 50 ++++++++++++++++++++++ tests/ui/traits/vtable/multiple-auto.stderr | 46 ++++++++++++++++++++ 5 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.dump.stderr create mode 100644 tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs create mode 100644 tests/ui/traits/vtable/multiple-auto.rs create mode 100644 tests/ui/traits/vtable/multiple-auto.stderr diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 3565c11249a..7e8a41457d4 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -153,7 +153,12 @@ fn prepare_vtable_segments_inner<'tcx, T>( // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level. while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() { - let has_entries = has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id); + // We don't need to emit a vptr for "truly-empty" supertraits, but we *do* need to emit a + // vptr for supertraits that have no methods, but that themselves have supertraits + // with methods, so we check if any transitive supertrait has entries here (this includes + // the trait itself). + let has_entries = ty::elaborate::supertrait_def_ids(tcx, inner_most_trait_ref.def_id) + .any(|def_id| has_own_existential_vtable_entries(tcx, def_id)); segment_visitor(VtblSegment::TraitOwnEntries { trait_ref: inner_most_trait_ref, diff --git a/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.dump.stderr b/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.dump.stderr new file mode 100644 index 00000000000..d90a786498e --- /dev/null +++ b/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.dump.stderr @@ -0,0 +1,16 @@ +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::one - shim(reify)), + Method(::two - shim(reify)), + TraitVPtr(), + TraitVPtr(), + ] + --> $DIR/empty-supertrait-with-nonempty-supersupertrait.rs:40:1 + | +LL | type T = dyn OneTwo; + | ^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs b/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs new file mode 100644 index 00000000000..507cda63868 --- /dev/null +++ b/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs @@ -0,0 +1,49 @@ +//@ revisions: run dump +//@[run] run-pass +//@[dump] check-fail +//! Regression test for #145752 +//! Ensure that `OneTwo` contains a vptr for `TwoAgain` +#![allow(unused)] +#![cfg_attr(dump, feature(rustc_attrs))] + +trait One { + fn one(&self) { + panic!("don't call this"); + } +} +impl One for () {} + +trait Two { + fn two(&self) { + println!("good"); + } +} +impl Two for () {} + +trait TwoAgain: Two {} +impl TwoAgain for T {} + +trait OneTwo: One + TwoAgain {} +impl OneTwo for T {} + +fn main() { + (&()).two(); + (&() as &dyn OneTwo).two(); + (&() as &dyn OneTwo as &dyn Two).two(); + + // these two used to panic because they called `one` due to #145752 + (&() as &dyn OneTwo as &dyn TwoAgain).two(); + (&() as &dyn OneTwo as &dyn TwoAgain as &dyn Two).two(); +} + +#[cfg_attr(dump, rustc_dump_vtable)] +type T = dyn OneTwo; +//[dump]~^ ERROR vtable entries: [ +//[dump]~| ERROR MetadataDropInPlace, +//[dump]~| ERROR MetadataSize, +//[dump]~| ERROR MetadataAlign, +//[dump]~| ERROR Method(::one - shim(reify)), +//[dump]~| ERROR Method(::two - shim(reify)), +//[dump]~| ERROR TraitVPtr(), +//[dump]~| ERROR TraitVPtr(), +//[dump]~| ERROR ] diff --git a/tests/ui/traits/vtable/multiple-auto.rs b/tests/ui/traits/vtable/multiple-auto.rs new file mode 100644 index 00000000000..87ee865868b --- /dev/null +++ b/tests/ui/traits/vtable/multiple-auto.rs @@ -0,0 +1,50 @@ +// Related to +// +// This test makes sure that multiple auto traits can reuse the +// same pointer for upcasting (e.g. `Send`/`Sync`) + +#![crate_type = "lib"] +#![feature(rustc_attrs, auto_traits)] + +// Markers +auto trait M0 {} +auto trait M1 {} +auto trait M2 {} + +// Just a trait with a method +trait T { + fn method(&self) {} +} + +trait A: M0 + M1 + M2 + T {} + +trait B: M0 + M1 + T + M2 {} + +trait C: M0 + T + M1 + M2 {} + +trait D: T + M0 + M1 + M2 {} + +struct S; + +impl M0 for S {} +impl M1 for S {} +impl M2 for S {} +impl T for S {} + +#[rustc_dump_vtable] +impl A for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] +impl B for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] +impl C for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] +impl D for S {} +//~^ ERROR vtable entries + +fn main() {} diff --git a/tests/ui/traits/vtable/multiple-auto.stderr b/tests/ui/traits/vtable/multiple-auto.stderr new file mode 100644 index 00000000000..0a7c3ebd36d --- /dev/null +++ b/tests/ui/traits/vtable/multiple-auto.stderr @@ -0,0 +1,46 @@ +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::method), + ] + --> $DIR/multiple-auto.rs:35:1 + | +LL | impl A for S {} + | ^^^^^^^^^^^^ + +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::method), + ] + --> $DIR/multiple-auto.rs:39:1 + | +LL | impl B for S {} + | ^^^^^^^^^^^^ + +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::method), + ] + --> $DIR/multiple-auto.rs:43:1 + | +LL | impl C for S {} + | ^^^^^^^^^^^^ + +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::method), + ] + --> $DIR/multiple-auto.rs:47:1 + | +LL | impl D for S {} + | ^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From f9c765ed76bcaa9aa2ccc902e61e3de91ec96837 Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Tue, 26 Aug 2025 13:44:00 +0000 Subject: Test `instrument-mcount` --- tests/assembly-llvm/x86_64-mcount.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/assembly-llvm/x86_64-mcount.rs diff --git a/tests/assembly-llvm/x86_64-mcount.rs b/tests/assembly-llvm/x86_64-mcount.rs new file mode 100644 index 00000000000..0428272cfc5 --- /dev/null +++ b/tests/assembly-llvm/x86_64-mcount.rs @@ -0,0 +1,24 @@ +//@ assembly-output: emit-asm +//@ compile-flags: -Zinstrument-mcount=y -Cllvm-args=-x86-asm-syntax=intel + +//@ revisions: x86_64-linux +//@[x86_64-linux] compile-flags: --target=x86_64-unknown-linux-gnu +//@[x86_64-linux] needs-llvm-components: x86 +//@[x86_64-linux] only-x86_64-unknown-linux-gnu + +//@ revisions: x86_64-darwin +//@[x86_64-darwin] compile-flags: --target=x86_64-apple-darwin +//@[x86_64-darwin] needs-llvm-components: x86 +//@[x86_64-darwin] only-x86_64-apple-darwin + +#![crate_type = "lib"] + +// CHECK-LABEL: mcount_func: +#[no_mangle] +pub fn mcount_func() { + // CHECK: call mcount + + std::hint::black_box(()); + + // CHECK: ret +} -- cgit 1.4.1-3-g733a5 From a898f76dc7c5f00761814ab0c74676bb9b35cab5 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Tue, 26 Aug 2025 15:53:06 +0200 Subject: Inherit TCC in debuginfo tests on macOS --- src/tools/compiletest/src/runtest/debuginfo.rs | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 6114afdc9df..24fdbab3aec 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -395,6 +395,35 @@ impl TestCx<'_> { // We don't want to hang when calling `quit` while the process is still running let mut script_str = String::from("settings set auto-confirm true\n"); + // macOS has a system for restricting access to files and peripherals + // called Transparency, Consent, and Control (TCC), which can be + // configured using the "Security & Privacy" tab in your settings. + // + // This system is provenance-based: if Terminal.app is given access to + // your Desktop, and you launch a binary within Terminal.app, the new + // binary also has access to the files on your Desktop. + // + // By default though, LLDB launches binaries in very isolated + // contexts. This includes resetting any TCC grants that might + // otherwise have been inherited. + // + // In effect, this means that if the developer has placed the rust + // repository under one of the system-protected folders, they will get + // a pop-up _for each binary_ asking for permissions to access the + // folder - quite annoying. + // + // To avoid this, we tell LLDB to spawn processes with TCC grants + // inherited from the parent process. + // + // Setting this also avoids unnecessary overhead from XprotectService + // when running with the Developer Tool grant. + // + // TIP: If you want to allow launching `lldb ~/Desktop/my_binary` + // without being prompted, you can put this in your `~/.lldbinit` too. + if self.config.host.contains("darwin") { + script_str.push_str("settings set target.inherit-tcc true\n"); + } + // Make LLDB emit its version, so we have it documented in the test output script_str.push_str("version\n"); -- cgit 1.4.1-3-g733a5 From c3ab409b4fa3b1fb18f34877d9811bb502ed507f Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 26 Aug 2025 11:13:03 +0200 Subject: Use captures(address) instead of captures(none) for indirect args While provenance cannot be captured through these arguments, the address / object identity can. --- compiler/rustc_codegen_llvm/src/abi.rs | 8 +++++--- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 15 +++++---------- compiler/rustc_target/src/callconv/mod.rs | 8 ++++---- tests/codegen-llvm/addr-of-mutate.rs | 6 +++--- tests/codegen-llvm/function-arguments.rs | 4 ++-- tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs | 4 ++-- tests/ui/abi/c-zst.powerpc-linux.stderr | 2 +- tests/ui/abi/c-zst.s390x-linux.stderr | 2 +- tests/ui/abi/c-zst.sparc64-linux.stderr | 2 +- tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr | 2 +- tests/ui/abi/debug.generic.stderr | 4 ++-- tests/ui/abi/debug.loongarch64.stderr | 4 ++-- tests/ui/abi/debug.riscv64.stderr | 4 ++-- tests/ui/codegen/indirect-nocapture.rs | 15 +++++++++++++++ 15 files changed, 47 insertions(+), 35 deletions(-) create mode 100644 tests/ui/codegen/indirect-nocapture.rs diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 399f8b6e762..ac7583f5666 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -44,7 +44,7 @@ const ABI_AFFECTING_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 1] = const OPTIMIZATION_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 6] = [ (ArgAttribute::NoAlias, llvm::AttributeKind::NoAlias), - (ArgAttribute::NoCapture, llvm::AttributeKind::NoCapture), + (ArgAttribute::CapturesAddress, llvm::AttributeKind::CapturesAddress), (ArgAttribute::NonNull, llvm::AttributeKind::NonNull), (ArgAttribute::ReadOnly, llvm::AttributeKind::ReadOnly), (ArgAttribute::NoUndef, llvm::AttributeKind::NoUndef), @@ -84,8 +84,10 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&' } for (attr, llattr) in OPTIMIZATION_ATTRIBUTES { if regular.contains(attr) { - // captures(address, read_provenance) is only available since LLVM 21. - if attr == ArgAttribute::CapturesReadOnly && llvm_util::get_version() < (21, 0, 0) { + // captures(...) is only available since LLVM 21. + if (attr == ArgAttribute::CapturesReadOnly || attr == ArgAttribute::CapturesAddress) + && llvm_util::get_version() < (21, 0, 0) + { continue; } attrs.push(llattr.create_attr(cx.llcx)); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index fa2802a891f..21e6bbb118e 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -263,7 +263,7 @@ pub(crate) enum AttributeKind { MinSize = 4, Naked = 5, NoAlias = 6, - NoCapture = 7, + CapturesAddress = 7, NoInline = 8, NonNull = 9, NoRedZone = 10, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index e699e4b9c13..2652acb1ec4 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -242,7 +242,7 @@ enum class LLVMRustAttributeKind { MinSize = 4, Naked = 5, NoAlias = 6, - NoCapture = 7, + CapturesAddress = 7, NoInline = 8, NonNull = 9, NoRedZone = 10, @@ -297,12 +297,6 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) { return Attribute::Naked; case LLVMRustAttributeKind::NoAlias: return Attribute::NoAlias; - case LLVMRustAttributeKind::NoCapture: -#if LLVM_VERSION_GE(21, 0) - report_fatal_error("NoCapture doesn't exist in LLVM 21"); -#else - return Attribute::NoCapture; -#endif case LLVMRustAttributeKind::NoCfCheck: return Attribute::NoCfCheck; case LLVMRustAttributeKind::NoInline: @@ -377,6 +371,7 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) { #else report_fatal_error("DeadOnReturn attribute requires LLVM 21 or later"); #endif + case LLVMRustAttributeKind::CapturesAddress: case LLVMRustAttributeKind::CapturesReadOnly: report_fatal_error("Should be handled separately"); } @@ -429,9 +424,9 @@ extern "C" void LLVMRustEraseInstFromParent(LLVMValueRef Instr) { extern "C" LLVMAttributeRef LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) { #if LLVM_VERSION_GE(21, 0) - // LLVM 21 replaced the NoCapture attribute with Captures(none). - if (RustAttr == LLVMRustAttributeKind::NoCapture) { - return wrap(Attribute::getWithCaptureInfo(*unwrap(C), CaptureInfo::none())); + if (RustAttr == LLVMRustAttributeKind::CapturesAddress) { + return wrap(Attribute::getWithCaptureInfo( + *unwrap(C), CaptureInfo(CaptureComponents::Address))); } if (RustAttr == LLVMRustAttributeKind::CapturesReadOnly) { return wrap(Attribute::getWithCaptureInfo( diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 5f2a6f7ba38..7a7c63c475b 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -114,7 +114,7 @@ mod attr_impl { bitflags::bitflags! { impl ArgAttribute: u8 { const NoAlias = 1 << 1; - const NoCapture = 1 << 2; + const CapturesAddress = 1 << 2; const NonNull = 1 << 3; const ReadOnly = 1 << 4; const InReg = 1 << 5; @@ -400,11 +400,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> { let mut attrs = ArgAttributes::new(); // For non-immediate arguments the callee gets its own copy of - // the value on the stack, so there are no aliases. It's also - // program-invisible so can't possibly capture + // the value on the stack, so there are no aliases. The function + // can capture the address of the argument, but not the provenance. attrs .set(ArgAttribute::NoAlias) - .set(ArgAttribute::NoCapture) + .set(ArgAttribute::CapturesAddress) .set(ArgAttribute::NonNull) .set(ArgAttribute::NoUndef); attrs.pointee_size = layout.size; diff --git a/tests/codegen-llvm/addr-of-mutate.rs b/tests/codegen-llvm/addr-of-mutate.rs index 71669065289..36d6bf555d1 100644 --- a/tests/codegen-llvm/addr-of-mutate.rs +++ b/tests/codegen-llvm/addr-of-mutate.rs @@ -5,7 +5,7 @@ // Test for the absence of `readonly` on the argument when it is mutated via `&raw const`. // See . -// CHECK: i8 @foo(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align 1{{( captures\(none\))?}} dereferenceable(128) %x) +// CHECK: i8 @foo(ptr{{( dead_on_return)?}} noalias noundef align 1{{( captures\(address\))?}} dereferenceable(128) %x) #[no_mangle] pub fn foo(x: [u8; 128]) -> u8 { let ptr = core::ptr::addr_of!(x).cast_mut(); @@ -15,7 +15,7 @@ pub fn foo(x: [u8; 128]) -> u8 { x[0] } -// CHECK: i1 @second(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) +// CHECK: i1 @second(ptr{{( dead_on_return)?}} noalias noundef align {{[0-9]+}}{{( captures\(address\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) #[no_mangle] pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut(); @@ -24,7 +24,7 @@ pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { } // If going through a deref (and there are no other mutating accesses), then `readonly` is fine. -// CHECK: i1 @third(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) +// CHECK: i1 @third(ptr{{( dead_on_return)?}} noalias noundef readonly align {{[0-9]+}}{{( captures\(address\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) #[no_mangle] pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut(); diff --git a/tests/codegen-llvm/function-arguments.rs b/tests/codegen-llvm/function-arguments.rs index db508682862..a0744e44c61 100644 --- a/tests/codegen-llvm/function-arguments.rs +++ b/tests/codegen-llvm/function-arguments.rs @@ -134,7 +134,7 @@ pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {} #[no_mangle] pub fn notunpin_borrow(_: &NotUnpin) {} -// CHECK: @indirect_struct(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1) +// CHECK: @indirect_struct(ptr{{( dead_on_return)?}} noalias noundef readonly align 4{{( captures\(address\))?}} dereferenceable(32) %_1) #[no_mangle] pub fn indirect_struct(_: S) {} @@ -197,7 +197,7 @@ pub fn notunpin_box(x: Box) -> Box { x } -// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(none\))?}} dereferenceable(32){{( %_0)?}}) +// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias noundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(address\))?}} dereferenceable(32){{( %_0)?}}) #[no_mangle] pub fn struct_return() -> S { S { _field: [0, 0, 0, 0, 0, 0, 0, 0] } diff --git a/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs b/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs index 4666342a16a..7ea08a1a8f7 100644 --- a/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs +++ b/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs @@ -256,11 +256,11 @@ pub struct IntDoubleInt { c: i32, } -// CHECK: define void @f_int_double_int_s_arg(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align 8{{( captures\(none\))?}} dereferenceable(24) %a) +// CHECK: define void @f_int_double_int_s_arg(ptr{{( dead_on_return)?}} noalias noundef align 8{{( captures\(address\))?}} dereferenceable(24) %a) #[no_mangle] pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} -// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([24 x i8]) align 8{{( captures\(none\))?}} dereferenceable(24) %_0) +// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias noundef{{( writable)?}} sret([24 x i8]) align 8{{( captures\(address\))?}} dereferenceable(24) %_0) #[no_mangle] pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt { IntDoubleInt { a: 1, b: 2., c: 3 } diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr index b8d6c632b97..ec6b9b8f027 100644 --- a/tests/ui/abi/c-zst.powerpc-linux.stderr +++ b/tests/ui/abi/c-zst.powerpc-linux.stderr @@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, mode: Indirect { attrs: ArgAttributes { - regular: NoAlias | NoCapture | NonNull | NoUndef, + regular: NoAlias | CapturesAddress | NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some( diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr index b8d6c632b97..ec6b9b8f027 100644 --- a/tests/ui/abi/c-zst.s390x-linux.stderr +++ b/tests/ui/abi/c-zst.s390x-linux.stderr @@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, mode: Indirect { attrs: ArgAttributes { - regular: NoAlias | NoCapture | NonNull | NoUndef, + regular: NoAlias | CapturesAddress | NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some( diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr index b8d6c632b97..ec6b9b8f027 100644 --- a/tests/ui/abi/c-zst.sparc64-linux.stderr +++ b/tests/ui/abi/c-zst.sparc64-linux.stderr @@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, mode: Indirect { attrs: ArgAttributes { - regular: NoAlias | NoCapture | NonNull | NoUndef, + regular: NoAlias | CapturesAddress | NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some( diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr index b8d6c632b97..ec6b9b8f027 100644 --- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr +++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr @@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, mode: Indirect { attrs: ArgAttributes { - regular: NoAlias | NoCapture | NonNull | NoUndef, + regular: NoAlias | CapturesAddress | NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some( diff --git a/tests/ui/abi/debug.generic.stderr b/tests/ui/abi/debug.generic.stderr index 0fec35dabdd..47341da221f 100644 --- a/tests/ui/abi/debug.generic.stderr +++ b/tests/ui/abi/debug.generic.stderr @@ -454,7 +454,7 @@ error: ABIs are not compatible }, mode: Indirect { attrs: ArgAttributes { - regular: NoAlias | NoCapture | NonNull | NoUndef, + regular: NoAlias | CapturesAddress | NonNull | NoUndef, arg_ext: None, pointee_size: Size(32 bytes), pointee_align: Some( @@ -527,7 +527,7 @@ error: ABIs are not compatible }, mode: Indirect { attrs: ArgAttributes { - regular: NoAlias | NoCapture | NonNull | NoUndef, + regular: NoAlias | CapturesAddress | NonNull | NoUndef, arg_ext: None, pointee_size: Size(128 bytes), pointee_align: Some( diff --git a/tests/ui/abi/debug.loongarch64.stderr b/tests/ui/abi/debug.loongarch64.stderr index ce8bd41f045..94a01a80873 100644 --- a/tests/ui/abi/debug.loongarch64.stderr +++ b/tests/ui/abi/debug.loongarch64.stderr @@ -454,7 +454,7 @@ error: ABIs are not compatible }, mode: Indirect { attrs: ArgAttributes { - regular: NoAlias | NoCapture | NonNull | NoUndef, + regular: NoAlias | CapturesAddress | NonNull | NoUndef, arg_ext: None, pointee_size: Size(32 bytes), pointee_align: Some( @@ -527,7 +527,7 @@ error: ABIs are not compatible }, mode: Indirect { attrs: ArgAttributes { - regular: NoAlias | NoCapture | NonNull | NoUndef, + regular: NoAlias | CapturesAddress | NonNull | NoUndef, arg_ext: None, pointee_size: Size(128 bytes), pointee_align: Some( diff --git a/tests/ui/abi/debug.riscv64.stderr b/tests/ui/abi/debug.riscv64.stderr index ce8bd41f045..94a01a80873 100644 --- a/tests/ui/abi/debug.riscv64.stderr +++ b/tests/ui/abi/debug.riscv64.stderr @@ -454,7 +454,7 @@ error: ABIs are not compatible }, mode: Indirect { attrs: ArgAttributes { - regular: NoAlias | NoCapture | NonNull | NoUndef, + regular: NoAlias | CapturesAddress | NonNull | NoUndef, arg_ext: None, pointee_size: Size(32 bytes), pointee_align: Some( @@ -527,7 +527,7 @@ error: ABIs are not compatible }, mode: Indirect { attrs: ArgAttributes { - regular: NoAlias | NoCapture | NonNull | NoUndef, + regular: NoAlias | CapturesAddress | NonNull | NoUndef, arg_ext: None, pointee_size: Size(128 bytes), pointee_align: Some( diff --git a/tests/ui/codegen/indirect-nocapture.rs b/tests/ui/codegen/indirect-nocapture.rs new file mode 100644 index 00000000000..78024a94c0d --- /dev/null +++ b/tests/ui/codegen/indirect-nocapture.rs @@ -0,0 +1,15 @@ +// Regression test for issue #137668 where an indirect argument have been marked as nocapture +// despite the fact that callee did in fact capture the address. +// +//@ run-pass +//@ compile-flags: -Copt-level=2 + +#[inline(never)] +pub fn f(a: [u32; 64], b: [u32; 64]) -> bool { + &a as *const _ as usize != &b as *const _ as usize +} + +fn main() { + static S: [u32; 64] = [0; 64]; + assert!(f(S, S)); +} -- cgit 1.4.1-3-g733a5 From 1d2cc80a4ef79efec9dcc9d870cbafd58f369643 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 26 Aug 2025 17:15:13 +0200 Subject: Update to LLVM 21.1.0 --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 9a1f898064f..19f0a49c5c3 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 9a1f898064f52269bc94675dcbd620b46d45d173 +Subproject commit 19f0a49c5c3f4ba88b5e7ac620b9a0d8574c09cb -- cgit 1.4.1-3-g733a5 From 82cc0eeec1a000b8f2b87a070ea807bdd41f44bf Mon Sep 17 00:00:00 2001 From: Daria Sukhonina Date: Tue, 26 Aug 2025 18:55:41 +0300 Subject: Ensure the coordinator thread terminates first --- compiler/rustc_codegen_ssa/src/back/write.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 9f22859ba81..0d766d2704b 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1957,10 +1957,10 @@ impl Drop for Coordinator { pub struct OngoingCodegen { pub backend: B, pub crate_info: CrateInfo, - pub codegen_worker_receive: Receiver, - pub shared_emitter_main: SharedEmitterMain, pub output_filenames: Arc, pub coordinator: Coordinator, + pub codegen_worker_receive: Receiver, + pub shared_emitter_main: SharedEmitterMain, } impl OngoingCodegen { -- cgit 1.4.1-3-g733a5 From dd07459096beddf523b86a7ef03e4703390a7319 Mon Sep 17 00:00:00 2001 From: Daria Sukhonina Date: Tue, 26 Aug 2025 19:18:39 +0300 Subject: Comment on intentional field order --- compiler/rustc_codegen_ssa/src/back/write.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 0d766d2704b..8586615f7c7 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1958,6 +1958,9 @@ pub struct OngoingCodegen { pub backend: B, pub crate_info: CrateInfo, pub output_filenames: Arc, + // Field order below is intended to terminate the coordinator thread before two fields below + // drop and prematurely close channels used by coordinator thread. See `Coordinator`'s + // `Drop` implementation for more info. pub coordinator: Coordinator, pub codegen_worker_receive: Receiver, pub shared_emitter_main: SharedEmitterMain, -- cgit 1.4.1-3-g733a5 From adddae65368c28d36c4202458aa9bf387c5a6d06 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 27 Aug 2025 06:06:11 +0900 Subject: stop returning errors when format foreign has trailing dollar --- compiler/rustc_builtin_macros/src/format_foreign.rs | 2 +- tests/ui/macros/format-foreign-dollar-without-spec.rs | 4 ++++ .../ui/macros/format-foreign-dollar-without-spec.stderr | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 tests/ui/macros/format-foreign-dollar-without-spec.rs create mode 100644 tests/ui/macros/format-foreign-dollar-without-spec.stderr diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index 3e5a26c0556..cf563a53973 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -416,7 +416,7 @@ pub(crate) mod printf { // Yes, this *is* the parameter. Some(('$', end2)) => { state = Flags; - parameter = Some(at.slice_between(end).unwrap().parse().unwrap()); + parameter = at.slice_between(end).unwrap().parse().ok(); move_to!(end2); } // Wait, no, actually, it's the width. diff --git a/tests/ui/macros/format-foreign-dollar-without-spec.rs b/tests/ui/macros/format-foreign-dollar-without-spec.rs new file mode 100644 index 00000000000..3e6a833e24a --- /dev/null +++ b/tests/ui/macros/format-foreign-dollar-without-spec.rs @@ -0,0 +1,4 @@ +fn main() { + println!("%65536$", 1); + //~^ ERROR never used +} diff --git a/tests/ui/macros/format-foreign-dollar-without-spec.stderr b/tests/ui/macros/format-foreign-dollar-without-spec.stderr new file mode 100644 index 00000000000..a20c34a1f85 --- /dev/null +++ b/tests/ui/macros/format-foreign-dollar-without-spec.stderr @@ -0,0 +1,16 @@ +error: argument never used + --> $DIR/format-foreign-dollar-without-spec.rs:2:25 + | +LL | println!("%65536$", 1); + | ^ argument never used + | +note: format specifiers use curly braces, and the conversion specifier ` + ` is unknown or unsupported + --> $DIR/format-foreign-dollar-without-spec.rs:2:15 + | +LL | println!("%65536$", 1); + | ^^^^^^^^ + = note: printf formatting is not supported; see the documentation for `std::fmt` + +error: aborting due to 1 previous error + -- cgit 1.4.1-3-g733a5 From 8835ea854e9339ae83a35461c064a1b919872ca5 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 22 Jul 2025 05:14:37 -0600 Subject: fix: Don't add an end column separator after a file with no source --- compiler/rustc_errors/src/emitter.rs | 25 +++++++++++++++++----- tests/ui/c-variadic/issue-86053-1.stderr | 1 - tests/ui/closures/issue-78720.stderr | 1 - ...-to-be-a-closure-or-coroutine-ice-113776.stderr | 1 - .../ui/imports/suggest-remove-issue-121315.stderr | 1 - tests/ui/issues/issue-17546.stderr | 2 -- .../use-redundant/use-redundant-issue-71450.stderr | 1 - .../use-redundant-prelude-rust-2015.stderr | 1 - .../use-redundant-prelude-rust-2021.stderr | 1 - tests/ui/macros/missing-writer-issue-139830.stderr | 1 - tests/ui/privacy/suggest-box-new.stderr | 1 - tests/ui/suggestions/enum-method-probe.stderr | 1 - tests/ui/suggestions/multi-suggestion.ascii.stderr | 1 - .../ui/suggestions/multi-suggestion.unicode.stderr | 1 - .../assoc_type_bound_with_struct.stderr | 4 ---- 15 files changed, 20 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 749bba5de12..18ac03aa72f 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1462,7 +1462,7 @@ impl HumanEmitter { max_line_num_len: usize, is_secondary: bool, is_cont: bool, - ) -> io::Result<()> { + ) -> io::Result { let mut buffer = StyledBuffer::new(); if !msp.has_primary_spans() && !msp.has_span_labels() && is_secondary && !self.short_message @@ -1575,12 +1575,14 @@ impl HumanEmitter { } let mut annotated_files = FileWithAnnotatedLines::collect_annotations(self, args, msp); trace!("{annotated_files:#?}"); + let mut code_window_status = CodeWindowStatus::Open; // Make sure our primary file comes first let primary_span = msp.primary_span().unwrap_or_default(); let (Some(sm), false) = (self.sm.as_ref(), primary_span.is_dummy()) else { // If we don't have span information, emit and exit - return emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message); + return emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message) + .map(|_| code_window_status); }; let primary_lo = sm.lookup_char_pos(primary_span.lo()); if let Ok(pos) = @@ -1639,6 +1641,13 @@ impl HumanEmitter { } line_idx += 1; } + if is_cont + && file_idx == annotated_files_len - 1 + && annotation_id == annotated_file.lines.len() - 1 + && !labels.is_empty() + { + code_window_status = CodeWindowStatus::Closed; + } for (label, is_primary) in labels.into_iter() { let style = if is_primary { Style::LabelPrimary @@ -1976,7 +1985,7 @@ impl HumanEmitter { // final step: take our styled buffer, render it, then output it emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; - Ok(()) + Ok(code_window_status) } fn column_width(&self, code_offset: usize) -> usize { @@ -2491,7 +2500,7 @@ impl HumanEmitter { !children.is_empty() || suggestions.iter().any(|s| s.style != SuggestionStyle::CompletelyHidden), ) { - Ok(()) => { + Ok(code_window_status) => { if !children.is_empty() || suggestions.iter().any(|s| s.style != SuggestionStyle::CompletelyHidden) { @@ -2502,7 +2511,7 @@ impl HumanEmitter { { // We'll continue the vertical bar to point into the next note. self.draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1); - } else { + } else if matches!(code_window_status, CodeWindowStatus::Open) { // We'll close the vertical bar to visually end the code window. self.draw_col_separator_end(&mut buffer, 0, max_line_num_len + 1); } @@ -3050,6 +3059,12 @@ enum DisplaySuggestion { Add, } +#[derive(Clone, Copy, Debug)] +enum CodeWindowStatus { + Closed, + Open, +} + impl FileWithAnnotatedLines { /// Preprocess all the annotations so that they are grouped by file and by line number /// This helps us quickly iterate over the whole message (including secondary file spans) diff --git a/tests/ui/c-variadic/issue-86053-1.stderr b/tests/ui/c-variadic/issue-86053-1.stderr index dc323f9a234..dd9eb7e2373 100644 --- a/tests/ui/c-variadic/issue-86053-1.stderr +++ b/tests/ui/c-variadic/issue-86053-1.stderr @@ -60,7 +60,6 @@ LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize --> $SRC_DIR/core/src/ops/function.rs:LL:COL | = note: similarly named trait `Fn` defined here - | help: a trait with a similar name exists | LL | self , ... , self , self , ... ) where Fn : FnOnce ( & 'a & 'b usize ) { diff --git a/tests/ui/closures/issue-78720.stderr b/tests/ui/closures/issue-78720.stderr index 3e95fab441a..c80c6f20ccc 100644 --- a/tests/ui/closures/issue-78720.stderr +++ b/tests/ui/closures/issue-78720.stderr @@ -12,7 +12,6 @@ LL | _func: F, --> $SRC_DIR/core/src/ops/function.rs:LL:COL | = note: similarly named trait `Fn` defined here - | help: a trait with a similar name exists | LL | _func: Fn, diff --git a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr index b9db7461699..e1f2538bcb3 100644 --- a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr +++ b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr @@ -6,7 +6,6 @@ LL | let f: F = async { 1 }; --> $SRC_DIR/core/src/ops/function.rs:LL:COL | = note: similarly named trait `Fn` defined here - | help: a trait with a similar name exists | LL | let f: Fn = async { 1 }; diff --git a/tests/ui/imports/suggest-remove-issue-121315.stderr b/tests/ui/imports/suggest-remove-issue-121315.stderr index 5d0bf9bea6a..f294e4b6892 100644 --- a/tests/ui/imports/suggest-remove-issue-121315.stderr +++ b/tests/ui/imports/suggest-remove-issue-121315.stderr @@ -6,7 +6,6 @@ LL | use std::convert::TryFrom; --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `TryFrom` is already defined here - | note: the lint level is defined here --> $DIR/suggest-remove-issue-121315.rs:2:25 | diff --git a/tests/ui/issues/issue-17546.stderr b/tests/ui/issues/issue-17546.stderr index 25a94dd9723..ec5a643b656 100644 --- a/tests/ui/issues/issue-17546.stderr +++ b/tests/ui/issues/issue-17546.stderr @@ -6,7 +6,6 @@ LL | fn new() -> NoResult { --> $SRC_DIR/core/src/result.rs:LL:COL | = note: similarly named enum `Result` defined here - | help: try using the variant's enum | LL - fn new() -> NoResult { @@ -60,7 +59,6 @@ LL | fn newer() -> NoResult { --> $SRC_DIR/core/src/result.rs:LL:COL | = note: similarly named enum `Result` defined here - | help: try using the variant's enum | LL - fn newer() -> NoResult { diff --git a/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr b/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr index c14ab9e11e0..427644d6c73 100644 --- a/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr +++ b/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr @@ -6,7 +6,6 @@ LL | use std::string::String; --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `String` is already defined here - | note: the lint level is defined here --> $DIR/use-redundant-issue-71450.rs:3:9 | diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr index 48d5c275055..a2d03b2fd70 100644 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr @@ -6,7 +6,6 @@ LL | use std::option::Option::Some; --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `Some` is already defined here - | note: the lint level is defined here --> $DIR/use-redundant-prelude-rust-2015.rs:3:9 | diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr index 526771c597a..3de74bd26f3 100644 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr @@ -6,7 +6,6 @@ LL | use std::convert::TryFrom; --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `TryFrom` is already defined here - | note: the lint level is defined here --> $DIR/use-redundant-prelude-rust-2021.rs:3:9 | diff --git a/tests/ui/macros/missing-writer-issue-139830.stderr b/tests/ui/macros/missing-writer-issue-139830.stderr index 34dd61328e0..587cd90e944 100644 --- a/tests/ui/macros/missing-writer-issue-139830.stderr +++ b/tests/ui/macros/missing-writer-issue-139830.stderr @@ -6,7 +6,6 @@ LL | let _ = write!(buf, "foo"); --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL | = note: the method is available for `String` here - | note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method --> $DIR/missing-writer-issue-139830.rs:7:20 | diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr index 6c47b52c9de..e0c3b683a24 100644 --- a/tests/ui/privacy/suggest-box-new.stderr +++ b/tests/ui/privacy/suggest-box-new.stderr @@ -6,7 +6,6 @@ LL | let _ = std::collections::HashMap(); --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL | = note: `std::collections::HashMap` defined here - | help: you might have meant to use an associated function to build this type | LL | let _ = std::collections::HashMap::new(); diff --git a/tests/ui/suggestions/enum-method-probe.stderr b/tests/ui/suggestions/enum-method-probe.stderr index 5aa0fc44c7b..87180e80e8b 100644 --- a/tests/ui/suggestions/enum-method-probe.stderr +++ b/tests/ui/suggestions/enum-method-probe.stderr @@ -102,7 +102,6 @@ LL | res.len(); --> $SRC_DIR/core/src/option.rs:LL:COL | = note: private method defined here - | note: the method `len` exists on the type `Vec<{integer}>` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL help: consider using `Option::expect` to unwrap the `Vec<{integer}>` value, panicking if the value is an `Option::None` diff --git a/tests/ui/suggestions/multi-suggestion.ascii.stderr b/tests/ui/suggestions/multi-suggestion.ascii.stderr index f2a146fbd52..ab60c681988 100644 --- a/tests/ui/suggestions/multi-suggestion.ascii.stderr +++ b/tests/ui/suggestions/multi-suggestion.ascii.stderr @@ -6,7 +6,6 @@ LL | let _ = std::collections::HashMap(); --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL | = note: `std::collections::HashMap` defined here - | help: you might have meant to use an associated function to build this type | LL | let _ = std::collections::HashMap::new(); diff --git a/tests/ui/suggestions/multi-suggestion.unicode.stderr b/tests/ui/suggestions/multi-suggestion.unicode.stderr index 69df481579b..d0558d5ac55 100644 --- a/tests/ui/suggestions/multi-suggestion.unicode.stderr +++ b/tests/ui/suggestions/multi-suggestion.unicode.stderr @@ -6,7 +6,6 @@ LL │ let _ = std::collections::HashMap(); ╭▸ $SRC_DIR/std/src/collections/hash/map.rs:LL:COL │ ╰ note: `std::collections::HashMap` defined here - ╰╴ help: you might have meant to use an associated function to build this type ╭╴ LL │ let _ = std::collections::HashMap::new(); diff --git a/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr b/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr index 2288bd1129c..2dc4d699e7d 100644 --- a/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr +++ b/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr @@ -6,7 +6,6 @@ LL | struct Foo where T: Bar, ::Baz: String { --> $SRC_DIR/alloc/src/string.rs:LL:COL | = note: similarly named trait `ToString` defined here - | help: constrain the associated type to `String` | LL - struct Foo where T: Bar, ::Baz: String { @@ -25,7 +24,6 @@ LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String { --> $SRC_DIR/alloc/src/string.rs:LL:COL | = note: similarly named trait `ToString` defined here - | help: constrain the associated type to `String` | LL - struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String { @@ -44,7 +42,6 @@ LL | fn foo(_: T) where ::Baz: String { --> $SRC_DIR/alloc/src/string.rs:LL:COL | = note: similarly named trait `ToString` defined here - | help: constrain the associated type to `String` | LL - fn foo(_: T) where ::Baz: String { @@ -63,7 +60,6 @@ LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String { --> $SRC_DIR/alloc/src/string.rs:LL:COL | = note: similarly named trait `ToString` defined here - | help: constrain the associated type to `String` | LL - fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String { -- cgit 1.4.1-3-g733a5 From 93d16c510066db062700e783a53461d45e5dbe4b Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 3 Jul 2025 15:47:15 -0600 Subject: fix: Add col separator before secondary messages with no source --- compiler/rustc_errors/src/emitter.rs | 25 ++++++++++++++++++++++ ...dont-project-to-specializable-projection.stderr | 1 + tests/ui/c-variadic/issue-86053-1.stderr | 1 + tests/ui/closures/issue-78720.stderr | 1 + tests/ui/closures/issue-90871.stderr | 1 + ...-to-be-a-closure-or-coroutine-ice-113776.stderr | 1 + tests/ui/consts/issue-89088.stderr | 1 + .../ui/derives/deriving-meta-unknown-trait.stderr | 2 ++ tests/ui/did_you_mean/println-typo.stderr | 1 + .../call_method_without_import.no_import.stderr | 1 + tests/ui/impl-trait/impl-generic-mismatch.stderr | 1 + .../ui/imports/suggest-remove-issue-121315.stderr | 4 ++++ tests/ui/issues/issue-17546.stderr | 2 ++ tests/ui/issues/issue-27033.stderr | 1 + .../use-redundant/use-redundant-issue-71450.stderr | 1 + .../use-redundant-prelude-rust-2015.stderr | 4 ++++ .../use-redundant-prelude-rust-2021.stderr | 2 ++ tests/ui/macros/macro-name-typo.stderr | 1 + tests/ui/macros/macro-path-prelude-fail-3.stderr | 1 + tests/ui/macros/missing-writer-issue-139830.stderr | 1 + .../method-call-lifetime-args-unresolved.stderr | 1 + tests/ui/parser/misspelled-keywords/ref.stderr | 1 + tests/ui/parser/recover/recover-pat-exprs.stderr | 1 + .../deref-patterns/implicit-const-deref.stderr | 1 + tests/ui/pattern/issue-115599.stderr | 1 + tests/ui/privacy/suggest-box-new.stderr | 1 + tests/ui/proc-macro/parent-source-spans.stderr | 3 +++ tests/ui/proc-macro/resolve-error.stderr | 2 ++ tests/ui/resolve/levenshtein.stderr | 1 + tests/ui/suggestions/attribute-typos.stderr | 1 + ...tempt-to-add-suggestions-with-no-changes.stderr | 1 + tests/ui/suggestions/enum-method-probe.stderr | 1 + .../import-trait-for-method-call.stderr | 1 + tests/ui/suggestions/multi-suggestion.ascii.stderr | 1 + .../ui/suggestions/multi-suggestion.unicode.stderr | 1 + .../suggest-tryinto-edition-change.stderr | 1 + .../assoc_type_bound_with_struct.stderr | 5 +++++ tests/ui/type/issue-7607-1.stderr | 1 + tests/ui/typeck/issue-83693.stderr | 1 + tests/ui/ufcs/ufcs-partially-resolved.stderr | 8 +++++++ 40 files changed, 87 insertions(+) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 18ac03aa72f..bd3b81bca0c 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1591,6 +1591,9 @@ impl HumanEmitter { annotated_files.swap(0, pos); } + // An end column separator should be emitted when a file with with a + // source, is followed by one without a source + let mut col_sep_before_no_show_source = false; let annotated_files_len = annotated_files.len(); // Print out the annotate source lines that correspond with the error for (file_idx, annotated_file) in annotated_files.into_iter().enumerate() { @@ -1601,6 +1604,26 @@ impl HumanEmitter { &annotated_file.file, ) { if !self.short_message { + // Add an end column separator when a file without a source + // comes after one with a source + // ╭▸ $DIR/deriving-meta-unknown-trait.rs:1:10 + // │ + // LL │ #[derive(Eqr)] + // │ ━━━ + // ╰╴ (<- It prints *this* line) + // ╭▸ $SRC_DIR/core/src/cmp.rs:356:0 + // │ + // ╰╴note: similarly named derive macro `Eq` defined here + if col_sep_before_no_show_source { + let buffer_msg_line_offset = buffer.num_lines(); + self.draw_col_separator_end( + &mut buffer, + buffer_msg_line_offset, + max_line_num_len + 1, + ); + } + col_sep_before_no_show_source = false; + // We'll just print an unannotated message. for (annotation_id, line) in annotated_file.lines.iter().enumerate() { let mut annotations = line.annotations.clone(); @@ -1671,6 +1694,8 @@ impl HumanEmitter { } } continue; + } else { + col_sep_before_no_show_source = true; } // print out the span location and spacer before we print the annotated source diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr index 3d82f572a1a..823d8d5b92f 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr @@ -25,6 +25,7 @@ error[E0599]: no method named `poll` found for struct `Pin<&mut impl Future>` + | --> $SRC_DIR/core/src/future/future.rs:LL:COL | = note: the method is available for `Pin<&mut impl Future>` here diff --git a/tests/ui/c-variadic/issue-86053-1.stderr b/tests/ui/c-variadic/issue-86053-1.stderr index dd9eb7e2373..3bf8b7ba5d8 100644 --- a/tests/ui/c-variadic/issue-86053-1.stderr +++ b/tests/ui/c-variadic/issue-86053-1.stderr @@ -57,6 +57,7 @@ error[E0412]: cannot find type `F` in this scope | LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) { | ^ + | --> $SRC_DIR/core/src/ops/function.rs:LL:COL | = note: similarly named trait `Fn` defined here diff --git a/tests/ui/closures/issue-78720.stderr b/tests/ui/closures/issue-78720.stderr index c80c6f20ccc..987625d22c9 100644 --- a/tests/ui/closures/issue-78720.stderr +++ b/tests/ui/closures/issue-78720.stderr @@ -9,6 +9,7 @@ error[E0412]: cannot find type `F` in this scope | LL | _func: F, | ^ + | --> $SRC_DIR/core/src/ops/function.rs:LL:COL | = note: similarly named trait `Fn` defined here diff --git a/tests/ui/closures/issue-90871.stderr b/tests/ui/closures/issue-90871.stderr index ef1cb213f73..12020226680 100644 --- a/tests/ui/closures/issue-90871.stderr +++ b/tests/ui/closures/issue-90871.stderr @@ -3,6 +3,7 @@ error[E0412]: cannot find type `n` in this scope | LL | type_ascribe!(2, n([u8; || 1])) | ^ help: a trait with a similar name exists: `Fn` + | --> $SRC_DIR/core/src/ops/function.rs:LL:COL | = note: similarly named trait `Fn` defined here diff --git a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr index e1f2538bcb3..c9c8115660f 100644 --- a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr +++ b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr @@ -3,6 +3,7 @@ error[E0412]: cannot find type `F` in this scope | LL | let f: F = async { 1 }; | ^ + | --> $SRC_DIR/core/src/ops/function.rs:LL:COL | = note: similarly named trait `Fn` defined here diff --git a/tests/ui/consts/issue-89088.stderr b/tests/ui/consts/issue-89088.stderr index 56025e0d9b2..5008a2eada8 100644 --- a/tests/ui/consts/issue-89088.stderr +++ b/tests/ui/consts/issue-89088.stderr @@ -6,6 +6,7 @@ LL | const FOO: &A = &A::Field(Cow::Borrowed("foo")); ... LL | FOO => todo!(), | ^^^ constant of non-structural type + | --> $SRC_DIR/alloc/src/borrow.rs:LL:COL | = note: `Cow<'_, str>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns diff --git a/tests/ui/derives/deriving-meta-unknown-trait.stderr b/tests/ui/derives/deriving-meta-unknown-trait.stderr index 28753b8f9f2..7ee90ae9eb0 100644 --- a/tests/ui/derives/deriving-meta-unknown-trait.stderr +++ b/tests/ui/derives/deriving-meta-unknown-trait.stderr @@ -3,6 +3,7 @@ error: cannot find derive macro `Eqr` in this scope | LL | #[derive(Eqr)] | ^^^ help: a derive macro with a similar name exists: `Eq` + | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named derive macro `Eq` defined here @@ -12,6 +13,7 @@ error: cannot find derive macro `Eqr` in this scope | LL | #[derive(Eqr)] | ^^^ help: a derive macro with a similar name exists: `Eq` + | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named derive macro `Eq` defined here diff --git a/tests/ui/did_you_mean/println-typo.stderr b/tests/ui/did_you_mean/println-typo.stderr index a1e0b1f1ba4..7dd6fbba620 100644 --- a/tests/ui/did_you_mean/println-typo.stderr +++ b/tests/ui/did_you_mean/println-typo.stderr @@ -3,6 +3,7 @@ error: cannot find macro `prinltn` in this scope | LL | prinltn!(); | ^^^^^^^ help: a macro with a similar name exists: `println` + | --> $SRC_DIR/std/src/macros.rs:LL:COL | = note: similarly named macro `println` defined here diff --git a/tests/ui/impl-trait/call_method_without_import.no_import.stderr b/tests/ui/impl-trait/call_method_without_import.no_import.stderr index dbac74b2247..2ca79aa7c10 100644 --- a/tests/ui/impl-trait/call_method_without_import.no_import.stderr +++ b/tests/ui/impl-trait/call_method_without_import.no_import.stderr @@ -3,6 +3,7 @@ error[E0599]: no method named `fmt` found for opaque type `impl Debug` in the cu | LL | x.fmt(f); | ^^^ method not found in `impl Debug` + | --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL | = note: the method is available for `impl Debug` here diff --git a/tests/ui/impl-trait/impl-generic-mismatch.stderr b/tests/ui/impl-trait/impl-generic-mismatch.stderr index 18347bd0f97..d7fff4c445d 100644 --- a/tests/ui/impl-trait/impl-generic-mismatch.stderr +++ b/tests/ui/impl-trait/impl-generic-mismatch.stderr @@ -48,6 +48,7 @@ error[E0643]: method `hash` has incompatible signature for trait | LL | fn hash(&self, hasher: &mut impl Hasher) {} | ^^^^^^^^^^^ expected generic parameter, found `impl Trait` + | --> $SRC_DIR/core/src/hash/mod.rs:LL:COL | = note: declaration in trait here diff --git a/tests/ui/imports/suggest-remove-issue-121315.stderr b/tests/ui/imports/suggest-remove-issue-121315.stderr index f294e4b6892..c91ea8a8793 100644 --- a/tests/ui/imports/suggest-remove-issue-121315.stderr +++ b/tests/ui/imports/suggest-remove-issue-121315.stderr @@ -3,6 +3,7 @@ error: the item `TryFrom` is imported redundantly | LL | use std::convert::TryFrom; | ^^^^^^^^^^^^^^^^^^^^^ + | --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `TryFrom` is already defined here @@ -17,6 +18,7 @@ error: the item `TryFrom` is imported redundantly | LL | use std::convert::{TryFrom, TryInto}; | ^^^^^^^ + | --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `TryFrom` is already defined here @@ -26,6 +28,7 @@ error: the item `TryInto` is imported redundantly | LL | use std::convert::{TryFrom, TryInto}; | ^^^^^^^ + | --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `TryInto` is already defined here @@ -47,6 +50,7 @@ error: the item `Into` is imported redundantly | LL | use std::convert::{AsMut, Into}; | ^^^^ + | --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `Into` is already defined here diff --git a/tests/ui/issues/issue-17546.stderr b/tests/ui/issues/issue-17546.stderr index ec5a643b656..5bae738d3ec 100644 --- a/tests/ui/issues/issue-17546.stderr +++ b/tests/ui/issues/issue-17546.stderr @@ -3,6 +3,7 @@ error[E0573]: expected type, found variant `NoResult` | LL | fn new() -> NoResult { | ^^^^^^^^^^^^^^^^^^^^^^^^ + | --> $SRC_DIR/core/src/result.rs:LL:COL | = note: similarly named enum `Result` defined here @@ -56,6 +57,7 @@ error[E0573]: expected type, found variant `NoResult` | LL | fn newer() -> NoResult { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | --> $SRC_DIR/core/src/result.rs:LL:COL | = note: similarly named enum `Result` defined here diff --git a/tests/ui/issues/issue-27033.stderr b/tests/ui/issues/issue-27033.stderr index 7a0ca888d74..129870f8c40 100644 --- a/tests/ui/issues/issue-27033.stderr +++ b/tests/ui/issues/issue-27033.stderr @@ -3,6 +3,7 @@ error[E0530]: match bindings cannot shadow unit variants | LL | None @ _ => {} | ^^^^ cannot be named the same as a unit variant + | --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the unit variant `None` is defined here diff --git a/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr b/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr index 427644d6c73..8a5c243ddf8 100644 --- a/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr +++ b/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr @@ -3,6 +3,7 @@ warning: the item `String` is imported redundantly | LL | use std::string::String; | ^^^^^^^^^^^^^^^^^^^ + | --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `String` is already defined here diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr index a2d03b2fd70..71bc7d3b371 100644 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr @@ -3,6 +3,7 @@ warning: the item `Some` is imported redundantly | LL | use std::option::Option::Some; | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `Some` is already defined here @@ -17,6 +18,7 @@ warning: the item `None` is imported redundantly | LL | use std::option::Option::None; | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `None` is already defined here @@ -26,6 +28,7 @@ warning: the item `Ok` is imported redundantly | LL | use std::result::Result::Ok; | ^^^^^^^^^^^^^^^^^^^^^^^ + | --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `Ok` is already defined here @@ -35,6 +38,7 @@ warning: the item `Err` is imported redundantly | LL | use std::result::Result::Err; | ^^^^^^^^^^^^^^^^^^^^^^^^ + | --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `Err` is already defined here diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr index 3de74bd26f3..f9b7af2105c 100644 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr @@ -3,6 +3,7 @@ warning: the item `TryFrom` is imported redundantly | LL | use std::convert::TryFrom; | ^^^^^^^^^^^^^^^^^^^^^ + | --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `TryFrom` is already defined here @@ -17,6 +18,7 @@ warning: the item `TryInto` is imported redundantly | LL | use std::convert::TryInto; | ^^^^^^^^^^^^^^^^^^^^^ + | --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | = note: the item `TryInto` is already defined here diff --git a/tests/ui/macros/macro-name-typo.stderr b/tests/ui/macros/macro-name-typo.stderr index 9059b10faaa..1cc7ea6ec1b 100644 --- a/tests/ui/macros/macro-name-typo.stderr +++ b/tests/ui/macros/macro-name-typo.stderr @@ -3,6 +3,7 @@ error: cannot find macro `printlx` in this scope | LL | printlx!("oh noes!"); | ^^^^^^^ help: a macro with a similar name exists: `println` + | --> $SRC_DIR/std/src/macros.rs:LL:COL | = note: similarly named macro `println` defined here diff --git a/tests/ui/macros/macro-path-prelude-fail-3.stderr b/tests/ui/macros/macro-path-prelude-fail-3.stderr index 485d7b7869a..3d0a074deeb 100644 --- a/tests/ui/macros/macro-path-prelude-fail-3.stderr +++ b/tests/ui/macros/macro-path-prelude-fail-3.stderr @@ -3,6 +3,7 @@ error: cannot find macro `inline` in this scope | LL | inline!(); | ^^^^^^ help: a macro with a similar name exists: `line` + | --> $SRC_DIR/core/src/macros/mod.rs:LL:COL | = note: similarly named macro `line` defined here diff --git a/tests/ui/macros/missing-writer-issue-139830.stderr b/tests/ui/macros/missing-writer-issue-139830.stderr index 587cd90e944..0a1c6f6f3ea 100644 --- a/tests/ui/macros/missing-writer-issue-139830.stderr +++ b/tests/ui/macros/missing-writer-issue-139830.stderr @@ -3,6 +3,7 @@ error[E0599]: cannot write into `String` | LL | let _ = write!(buf, "foo"); | ^^^ + | --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL | = note: the method is available for `String` here diff --git a/tests/ui/methods/method-call-lifetime-args-unresolved.stderr b/tests/ui/methods/method-call-lifetime-args-unresolved.stderr index a87c47a9f12..cc8bd18449a 100644 --- a/tests/ui/methods/method-call-lifetime-args-unresolved.stderr +++ b/tests/ui/methods/method-call-lifetime-args-unresolved.stderr @@ -14,6 +14,7 @@ warning: cannot specify lifetime arguments explicitly if late bound lifetime par | LL | 0.clone::<'a>(); | ^^ + | --> $SRC_DIR/core/src/clone.rs:LL:COL | = note: the late bound lifetime parameter is introduced here diff --git a/tests/ui/parser/misspelled-keywords/ref.stderr b/tests/ui/parser/misspelled-keywords/ref.stderr index 21b99d6e663..dd33fdb21ba 100644 --- a/tests/ui/parser/misspelled-keywords/ref.stderr +++ b/tests/ui/parser/misspelled-keywords/ref.stderr @@ -15,6 +15,7 @@ error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has | LL | Some(refe list) => println!("{list:?}"), | ^^^^ ^^^^ expected 1 field, found 2 + | --> $SRC_DIR/core/src/option.rs:LL:COL | = note: tuple variant has 1 field diff --git a/tests/ui/parser/recover/recover-pat-exprs.stderr b/tests/ui/parser/recover/recover-pat-exprs.stderr index 33000022b8f..a99f7e16fca 100644 --- a/tests/ui/parser/recover/recover-pat-exprs.stderr +++ b/tests/ui/parser/recover/recover-pat-exprs.stderr @@ -690,6 +690,7 @@ error: expected one of `)`, `,`, `@`, `if`, or `|`, found `*` | LL | let b = matches!(x, (x * x | x.f()) | x[0]); | ^ expected one of `)`, `,`, `@`, `if`, or `|` + | --> $SRC_DIR/core/src/macros/mod.rs:LL:COL | = note: while parsing argument for this `pat` macro fragment diff --git a/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr b/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr index 21d09ec44c4..6d430184628 100644 --- a/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr +++ b/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr @@ -6,6 +6,7 @@ LL | const EMPTY: Vec<()> = Vec::new(); ... LL | EMPTY => {} | ^^^^^ constant of non-structural type + | --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL | = note: `Vec<()>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns diff --git a/tests/ui/pattern/issue-115599.stderr b/tests/ui/pattern/issue-115599.stderr index 69d10728ccd..ed465ea0bba 100644 --- a/tests/ui/pattern/issue-115599.stderr +++ b/tests/ui/pattern/issue-115599.stderr @@ -6,6 +6,7 @@ LL | const CONST_STRING: String = String::new(); ... LL | if let CONST_STRING = empty_str {} | ^^^^^^^^^^^^ constant of non-structural type + | --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL | = note: `Vec` must be annotated with `#[derive(PartialEq)]` to be usable in patterns diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr index e0c3b683a24..2b48e9046bf 100644 --- a/tests/ui/privacy/suggest-box-new.stderr +++ b/tests/ui/privacy/suggest-box-new.stderr @@ -3,6 +3,7 @@ error[E0423]: expected function, tuple struct or tuple variant, found struct `st | LL | let _ = std::collections::HashMap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL | = note: `std::collections::HashMap` defined here diff --git a/tests/ui/proc-macro/parent-source-spans.stderr b/tests/ui/proc-macro/parent-source-spans.stderr index a3b27fd7bcc..db1eed5e458 100644 --- a/tests/ui/proc-macro/parent-source-spans.stderr +++ b/tests/ui/proc-macro/parent-source-spans.stderr @@ -144,6 +144,7 @@ LL | parent_source_spans!($($tokens)*); ... LL | one!("hello", "world"); | ---------------------- in this macro invocation + | --> $SRC_DIR/core/src/result.rs:LL:COL | = note: similarly named tuple variant `Ok` defined here @@ -158,6 +159,7 @@ LL | parent_source_spans!($($tokens)*); ... LL | two!("yay", "rust"); | ------------------- in this macro invocation + | --> $SRC_DIR/core/src/result.rs:LL:COL | = note: similarly named tuple variant `Ok` defined here @@ -172,6 +174,7 @@ LL | parent_source_spans!($($tokens)*); ... LL | three!("hip", "hop"); | -------------------- in this macro invocation + | --> $SRC_DIR/core/src/result.rs:LL:COL | = note: similarly named tuple variant `Ok` defined here diff --git a/tests/ui/proc-macro/resolve-error.stderr b/tests/ui/proc-macro/resolve-error.stderr index 963298311ef..45b71a3e7b3 100644 --- a/tests/ui/proc-macro/resolve-error.stderr +++ b/tests/ui/proc-macro/resolve-error.stderr @@ -76,6 +76,7 @@ error: cannot find derive macro `Dlone` in this scope | LL | #[derive(Dlone)] | ^^^^^ help: a derive macro with a similar name exists: `Clone` + | --> $SRC_DIR/core/src/clone.rs:LL:COL | = note: similarly named derive macro `Clone` defined here @@ -85,6 +86,7 @@ error: cannot find derive macro `Dlone` in this scope | LL | #[derive(Dlone)] | ^^^^^ help: a derive macro with a similar name exists: `Clone` + | --> $SRC_DIR/core/src/clone.rs:LL:COL | = note: similarly named derive macro `Clone` defined here diff --git a/tests/ui/resolve/levenshtein.stderr b/tests/ui/resolve/levenshtein.stderr index cf478210132..7fc5710c35e 100644 --- a/tests/ui/resolve/levenshtein.stderr +++ b/tests/ui/resolve/levenshtein.stderr @@ -18,6 +18,7 @@ error[E0412]: cannot find type `Opiton` in this scope | LL | type B = Opiton; // Misspelled type name from the prelude. | ^^^^^^ help: an enum with a similar name exists: `Option` + | --> $SRC_DIR/core/src/option.rs:LL:COL | = note: similarly named enum `Option` defined here diff --git a/tests/ui/suggestions/attribute-typos.stderr b/tests/ui/suggestions/attribute-typos.stderr index a1a01c0abd6..1816a27dcdc 100644 --- a/tests/ui/suggestions/attribute-typos.stderr +++ b/tests/ui/suggestions/attribute-typos.stderr @@ -15,6 +15,7 @@ error: cannot find attribute `tests` in this scope | LL | #[tests] | ^^^^^ help: an attribute macro with a similar name exists: `test` + | --> $SRC_DIR/core/src/macros/mod.rs:LL:COL | = note: similarly named attribute macro `test` defined here diff --git a/tests/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.stderr b/tests/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.stderr index 0cd6267b3b3..c81ac34aaf4 100644 --- a/tests/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.stderr +++ b/tests/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.stderr @@ -3,6 +3,7 @@ error[E0573]: expected type, found module `result` | LL | impl result { | ^^^^^^ help: an enum with a similar name exists: `Result` + | --> $SRC_DIR/core/src/result.rs:LL:COL | = note: similarly named enum `Result` defined here diff --git a/tests/ui/suggestions/enum-method-probe.stderr b/tests/ui/suggestions/enum-method-probe.stderr index 87180e80e8b..7d97495af82 100644 --- a/tests/ui/suggestions/enum-method-probe.stderr +++ b/tests/ui/suggestions/enum-method-probe.stderr @@ -99,6 +99,7 @@ error[E0624]: method `len` is private | LL | res.len(); | ^^^ private method + | --> $SRC_DIR/core/src/option.rs:LL:COL | = note: private method defined here diff --git a/tests/ui/suggestions/import-trait-for-method-call.stderr b/tests/ui/suggestions/import-trait-for-method-call.stderr index 58b07fe7a42..177ab76cd1f 100644 --- a/tests/ui/suggestions/import-trait-for-method-call.stderr +++ b/tests/ui/suggestions/import-trait-for-method-call.stderr @@ -3,6 +3,7 @@ error[E0599]: no method named `finish` found for struct `DefaultHasher` in the c | LL | h.finish() | ^^^^^^ method not found in `DefaultHasher` + | --> $SRC_DIR/core/src/hash/mod.rs:LL:COL | = note: the method is available for `DefaultHasher` here diff --git a/tests/ui/suggestions/multi-suggestion.ascii.stderr b/tests/ui/suggestions/multi-suggestion.ascii.stderr index ab60c681988..1744162e6ce 100644 --- a/tests/ui/suggestions/multi-suggestion.ascii.stderr +++ b/tests/ui/suggestions/multi-suggestion.ascii.stderr @@ -3,6 +3,7 @@ error[E0423]: expected function, tuple struct or tuple variant, found struct `st | LL | let _ = std::collections::HashMap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL | = note: `std::collections::HashMap` defined here diff --git a/tests/ui/suggestions/multi-suggestion.unicode.stderr b/tests/ui/suggestions/multi-suggestion.unicode.stderr index d0558d5ac55..3d3f3268c08 100644 --- a/tests/ui/suggestions/multi-suggestion.unicode.stderr +++ b/tests/ui/suggestions/multi-suggestion.unicode.stderr @@ -3,6 +3,7 @@ error[E0423]: expected function, tuple struct or tuple variant, found struct `st │ LL │ let _ = std::collections::HashMap(); │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ╰╴ ╭▸ $SRC_DIR/std/src/collections/hash/map.rs:LL:COL │ ╰ note: `std::collections::HashMap` defined here diff --git a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr index 0008b4fb5ed..8ab8a1716b1 100644 --- a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr +++ b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr @@ -44,6 +44,7 @@ error[E0599]: no method named `try_into` found for type `i32` in the current sco | LL | let _i: i16 = 0_i32.try_into().unwrap(); | ^^^^^^^^ + | --> $SRC_DIR/core/src/convert/mod.rs:LL:COL | = note: the method is available for `i32` here diff --git a/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr b/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr index 2dc4d699e7d..40936ce1ec3 100644 --- a/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr +++ b/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr @@ -3,6 +3,7 @@ error[E0404]: expected trait, found struct `String` | LL | struct Foo where T: Bar, ::Baz: String { | ^^^^^^ not a trait + | --> $SRC_DIR/alloc/src/string.rs:LL:COL | = note: similarly named trait `ToString` defined here @@ -21,6 +22,7 @@ error[E0404]: expected trait, found struct `String` | LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String { | ^^^^^^ not a trait + | --> $SRC_DIR/alloc/src/string.rs:LL:COL | = note: similarly named trait `ToString` defined here @@ -39,6 +41,7 @@ error[E0404]: expected trait, found struct `String` | LL | fn foo(_: T) where ::Baz: String { | ^^^^^^ not a trait + | --> $SRC_DIR/alloc/src/string.rs:LL:COL | = note: similarly named trait `ToString` defined here @@ -57,6 +60,7 @@ error[E0404]: expected trait, found struct `String` | LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String { | ^^^^^^ not a trait + | --> $SRC_DIR/alloc/src/string.rs:LL:COL | = note: similarly named trait `ToString` defined here @@ -81,6 +85,7 @@ error[E0404]: expected trait, found struct `String` | LL | fn issue_95327() where ::Assoc: String {} | ^^^^^^ help: a trait with a similar name exists: `ToString` + | --> $SRC_DIR/alloc/src/string.rs:LL:COL | = note: similarly named trait `ToString` defined here diff --git a/tests/ui/type/issue-7607-1.stderr b/tests/ui/type/issue-7607-1.stderr index db4c8f25dbc..69b6d62e987 100644 --- a/tests/ui/type/issue-7607-1.stderr +++ b/tests/ui/type/issue-7607-1.stderr @@ -3,6 +3,7 @@ error[E0412]: cannot find type `Fo` in this scope | LL | impl Fo { | ^^ help: a trait with a similar name exists: `Fn` + | --> $SRC_DIR/core/src/ops/function.rs:LL:COL | = note: similarly named trait `Fn` defined here diff --git a/tests/ui/typeck/issue-83693.stderr b/tests/ui/typeck/issue-83693.stderr index 34bca426116..0359b8af93a 100644 --- a/tests/ui/typeck/issue-83693.stderr +++ b/tests/ui/typeck/issue-83693.stderr @@ -3,6 +3,7 @@ error[E0412]: cannot find type `F` in this scope | LL | impl F { | ^ help: a trait with a similar name exists: `Fn` + | --> $SRC_DIR/core/src/ops/function.rs:LL:COL | = note: similarly named trait `Fn` defined here diff --git a/tests/ui/ufcs/ufcs-partially-resolved.stderr b/tests/ui/ufcs/ufcs-partially-resolved.stderr index 69d6bd74a73..a854ecb0622 100644 --- a/tests/ui/ufcs/ufcs-partially-resolved.stderr +++ b/tests/ui/ufcs/ufcs-partially-resolved.stderr @@ -12,6 +12,7 @@ error[E0404]: expected trait, found enum `E` | LL | let _: ::N; | ^ help: a trait with a similar name exists: `Eq` + | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here @@ -42,6 +43,7 @@ error[E0404]: expected trait, found enum `E` | LL | ::N; | ^ help: a trait with a similar name exists: `Eq` + | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here @@ -63,6 +65,7 @@ error[E0404]: expected trait, found enum `E` | LL | let _: ::Y; | ^ help: a trait with a similar name exists: `Eq` + | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here @@ -72,6 +75,7 @@ error[E0404]: expected trait, found enum `E` | LL | ::Y; | ^ help: a trait with a similar name exists: `Eq` + | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here @@ -90,6 +94,7 @@ error[E0404]: expected trait, found enum `E` | LL | let _: ::N::NN; | ^ help: a trait with a similar name exists: `Eq` + | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here @@ -120,6 +125,7 @@ error[E0404]: expected trait, found enum `E` | LL | ::N::NN; | ^ help: a trait with a similar name exists: `Eq` + | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here @@ -141,6 +147,7 @@ error[E0404]: expected trait, found enum `E` | LL | let _: ::Y::NN; | ^ help: a trait with a similar name exists: `Eq` + | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here @@ -150,6 +157,7 @@ error[E0404]: expected trait, found enum `E` | LL | ::Y::NN; | ^ help: a trait with a similar name exists: `Eq` + | --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: similarly named trait `Eq` defined here -- cgit 1.4.1-3-g733a5 From 2bd47d264628dc227ed317a6c0d0f03891dd8c5c Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 22 Jul 2025 05:14:37 -0600 Subject: fix: Render continuation between no source labels --- compiler/rustc_errors/src/emitter.rs | 39 +++++++++++----------- .../ui/suggestions/multi-suggestion.unicode.stderr | 2 +- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index bd3b81bca0c..b94370e8e9b 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1671,23 +1671,27 @@ impl HumanEmitter { { code_window_status = CodeWindowStatus::Closed; } - for (label, is_primary) in labels.into_iter() { + let labels_len = labels.len(); + for (label_idx, (label, is_primary)) in labels.into_iter().enumerate() { let style = if is_primary { Style::LabelPrimary } else { Style::LabelSecondary }; - let pipe = self.col_separator(); - buffer.prepend(line_idx, &format!(" {pipe}"), Style::LineNumber); - for _ in 0..max_line_num_len { - buffer.prepend(line_idx, " ", Style::NoStyle); - } + self.draw_col_separator_no_space( + &mut buffer, + line_idx, + max_line_num_len + 1, + ); line_idx += 1; - let chr = self.note_separator(); - buffer.append(line_idx, &format!(" {chr} note: "), style); - for _ in 0..max_line_num_len { - buffer.prepend(line_idx, " ", Style::NoStyle); - } + self.draw_note_separator( + &mut buffer, + line_idx, + max_line_num_len + 1, + label_idx != labels_len - 1, + ); + buffer.append(line_idx, "note", Style::MainHeaderMsg); + buffer.append(line_idx, ": ", Style::NoStyle); buffer.append(line_idx, label, style); line_idx += 1; } @@ -2863,10 +2867,11 @@ impl HumanEmitter { } } - fn note_separator(&self) -> char { + fn note_separator(&self, is_cont: bool) -> &'static str { match self.theme { - OutputTheme::Ascii => '=', - OutputTheme::Unicode => '╰', + OutputTheme::Ascii => "= ", + OutputTheme::Unicode if is_cont => "├ ", + OutputTheme::Unicode => "╰ ", } } @@ -2979,11 +2984,7 @@ impl HumanEmitter { col: usize, is_cont: bool, ) { - let chr = match self.theme { - OutputTheme::Ascii => "= ", - OutputTheme::Unicode if is_cont => "├ ", - OutputTheme::Unicode => "╰ ", - }; + let chr = self.note_separator(is_cont); buffer.puts(line, col, chr, Style::LineNumber); } diff --git a/tests/ui/suggestions/multi-suggestion.unicode.stderr b/tests/ui/suggestions/multi-suggestion.unicode.stderr index 3d3f3268c08..4835c263f19 100644 --- a/tests/ui/suggestions/multi-suggestion.unicode.stderr +++ b/tests/ui/suggestions/multi-suggestion.unicode.stderr @@ -34,7 +34,7 @@ LL │ wtf: Some(Box(U { note: constructor is not visible here due to private fields ╭▸ $SRC_DIR/alloc/src/boxed.rs:LL:COL │ - ╰ note: private field + ├ note: private field │ ╰ note: private field help: you might have meant to use an associated function to build this type -- cgit 1.4.1-3-g733a5 From f27e0c10aeb12a798020dc644db39091279c8e5b Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Tue, 26 Aug 2025 23:21:01 +0200 Subject: Move `riscv64-gc-unknown-linux-musl` from Tier 2 with Host tools to Tier 2 It is not shipped with host tools, so it was located in the wrong group. --- src/doc/rustc/src/platform-support.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 22d32a29b36..059a43c20d7 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -103,7 +103,6 @@ target | notes [`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10+, glibc 2.17) [`powerpc64le-unknown-linux-musl`](platform-support/powerpc64le-unknown-linux-musl.md) | PPC64LE Linux (kernel 4.19+, musl 1.2.3) [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20+, glibc 2.29) -[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20+, musl 1.2.3) [`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2+, glibc 2.17) [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+) [`x86_64-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | 64-bit x86 MinGW (Windows 10+), LLVM ABI @@ -183,6 +182,7 @@ target | std | notes [`riscv32imac-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAC ISA) [`riscv32imafc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAFC ISA) [`riscv32imc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA) +[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20+, musl 1.2.3) `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA) `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4+, glibc 2.23) -- cgit 1.4.1-3-g733a5 From cf8753e4f9c3597f04cd5d3aa261e4561d5378a6 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Tue, 10 Jun 2025 23:37:05 +0000 Subject: Make `lto` and `linker-plugin-lto` work the same for `compiler_builtins` Fix #142284 by ensuring that `#![no_builtins]` crates can still emit bitcode when proper (i.e., non-rustc) LTO (i.e., -Clinker-plugin-lto) is used. --- compiler/rustc_codegen_ssa/src/back/write.rs | 13 +------------ tests/ui/sanitizer/cfi/no_builtins.rs | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 tests/ui/sanitizer/cfi/no_builtins.rs diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index aa29afb7f5b..f460c900c08 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -143,23 +143,12 @@ impl ModuleConfig { let emit_obj = if !should_emit_obj { EmitObj::None - } else if sess.target.obj_is_bitcode - || (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins) - { + } else if sess.target.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled() { // This case is selected if the target uses objects as bitcode, or // if linker plugin LTO is enabled. In the linker plugin LTO case // the assumption is that the final link-step will read the bitcode // and convert it to object code. This may be done by either the // native linker or rustc itself. - // - // Note, however, that the linker-plugin-lto requested here is - // explicitly ignored for `#![no_builtins]` crates. These crates are - // specifically ignored by rustc's LTO passes and wouldn't work if - // loaded into the linker. These crates define symbols that LLVM - // lowers intrinsics to, and these symbol dependencies aren't known - // until after codegen. As a result any crate marked - // `#![no_builtins]` is assumed to not participate in LTO and - // instead goes on to generate object code. EmitObj::Bitcode } else if need_bitcode_in_object(tcx) { EmitObj::ObjectCode(BitcodeSection::Full) diff --git a/tests/ui/sanitizer/cfi/no_builtins.rs b/tests/ui/sanitizer/cfi/no_builtins.rs new file mode 100644 index 00000000000..949057689ab --- /dev/null +++ b/tests/ui/sanitizer/cfi/no_builtins.rs @@ -0,0 +1,22 @@ +// Verifies that `#![no_builtins]` crates can be built with linker-plugin-lto and CFI. +// See Issue #142284 +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static +//@ compile-flags: --crate-type rlib +//@ build-pass + +#![no_builtins] +#![no_std] + +pub static FUNC: fn() = initializer; + +pub fn initializer() { + call(fma_with_fma); +} + +pub fn call(fn_ptr: fn()) { + fn_ptr(); +} + +pub fn fma_with_fma() {} -- cgit 1.4.1-3-g733a5 From 346e195c74b341d6a6550b070df3d84b223d26cb Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 26 Aug 2025 21:00:10 -0400 Subject: Update cargo submodule --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 623d536836b..a6c58d43051 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 623d536836b4cde09ce38609232a024d5b25da81 +Subproject commit a6c58d43051d01d83f55a3e61ef5f5b2b0dd6bd9 -- cgit 1.4.1-3-g733a5 From 22cdf214bb3095536aaafcfe4012d71bb93a5b13 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 8 Jun 2025 16:49:45 -0400 Subject: Use -Zmir-opt-level=0 in tests for MIR building --- tests/mir-opt/building/async_await.rs | 2 +- tests/mir-opt/building/dump_mir_cycle.rs | 2 + tests/mir-opt/building/enum_cast.rs | 1 + tests/mir-opt/building/eq_never_type.rs | 1 + tests/mir-opt/building/index_array_and_slice.rs | 47 +++++++++++++--------- .../building/issue_101867.main.built.after.mir | 4 +- tests/mir-opt/building/issue_101867.rs | 1 + tests/mir-opt/building/issue_110508.rs | 1 + .../issue_110508.{impl#0}-BAR.built.after.mir | 4 +- .../issue_110508.{impl#0}-SELF_BAR.built.after.mir | 4 +- tests/mir-opt/building/issue_49232.rs | 1 + .../mir-opt/building/logical_or_in_conditional.rs | 2 +- .../receiver_ptr_mutability.main.built.after.mir | 8 ++-- tests/mir-opt/building/receiver_ptr_mutability.rs | 1 + tests/mir-opt/building/shifts.rs | 2 +- .../building/storage_live_dead_in_statics.rs | 1 + tests/mir-opt/building/uniform_array_move_out.rs | 1 + .../user_type_annotations.let_else.built.after.mir | 4 +- ...e_annotations.let_else_bindless.built.after.mir | 4 +- .../user_type_annotations.let_init.built.after.mir | 4 +- ...e_annotations.let_init_bindless.built.after.mir | 4 +- ...ser_type_annotations.let_uninit.built.after.mir | 2 +- ...annotations.let_uninit_bindless.built.after.mir | 2 +- ...e_annotations.match_assoc_const.built.after.mir | 4 +- ...tations.match_assoc_const_range.built.after.mir | 8 ++-- tests/mir-opt/building/user_type_annotations.rs | 1 + 26 files changed, 69 insertions(+), 47 deletions(-) diff --git a/tests/mir-opt/building/async_await.rs b/tests/mir-opt/building/async_await.rs index 6c44570d109..2d14a1fb0c6 100644 --- a/tests/mir-opt/building/async_await.rs +++ b/tests/mir-opt/building/async_await.rs @@ -4,7 +4,7 @@ // related to `yield` are `&mut Context`, and its return type is `Poll`. //@ edition:2018 -//@ compile-flags: -C panic=abort +//@ compile-flags: -Zmir-opt-level=0 -C panic=abort #![crate_type = "lib"] diff --git a/tests/mir-opt/building/dump_mir_cycle.rs b/tests/mir-opt/building/dump_mir_cycle.rs index 8e13420aed7..ab0f2ea6db8 100644 --- a/tests/mir-opt/building/dump_mir_cycle.rs +++ b/tests/mir-opt/building/dump_mir_cycle.rs @@ -1,3 +1,5 @@ +//@ compile-flags: -Zmir-opt-level=0 + #[derive(Debug)] pub struct Thing { pub next: &'static Thing, diff --git a/tests/mir-opt/building/enum_cast.rs b/tests/mir-opt/building/enum_cast.rs index eaf5537e0ab..07025f572ab 100644 --- a/tests/mir-opt/building/enum_cast.rs +++ b/tests/mir-opt/building/enum_cast.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zmir-opt-level=0 // skip-filecheck // EMIT_MIR enum_cast.foo.built.after.mir // EMIT_MIR enum_cast.bar.built.after.mir diff --git a/tests/mir-opt/building/eq_never_type.rs b/tests/mir-opt/building/eq_never_type.rs index 90e2e697535..486e2f9fb8d 100644 --- a/tests/mir-opt/building/eq_never_type.rs +++ b/tests/mir-opt/building/eq_never_type.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zmir-opt-level=0 // skip-filecheck #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/mir-opt/building/index_array_and_slice.rs b/tests/mir-opt/building/index_array_and_slice.rs index 42ede66d92b..47d8255ef57 100644 --- a/tests/mir-opt/building/index_array_and_slice.rs +++ b/tests/mir-opt/building/index_array_and_slice.rs @@ -1,36 +1,42 @@ -//@ compile-flags: -C opt-level=0 +//@ compile-flags: -Zmir-opt-level=0 -C opt-level=0 // EMIT_MIR index_array_and_slice.index_array.built.after.mir fn index_array(array: &[i32; 7], index: usize) -> &i32 { // CHECK: bb0: - // CHECK: [[LT:_.+]] = Lt(copy _2, const 7_usize); - // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", const 7_usize, copy _2) -> [success: bb1, unwind + // CHECK: _3 = copy _2; + // CHECK: [[LT:_.+]] = Lt(copy _3, const 7_usize); + // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", const 7_usize, copy _3) -> [success: bb1, unwind // CHECK: bb1: - // CHECK: _0 = &(*_1)[_2]; + // CHECK: _5 = &(*_1)[_3]; + // CHECK: _0 = &(*_5); &array[index] } // EMIT_MIR index_array_and_slice.index_const_generic_array.built.after.mir fn index_const_generic_array(array: &[i32; N], index: usize) -> &i32 { // CHECK: bb0: - // CHECK: [[LT:_.+]] = Lt(copy _2, const N); - // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", const N, copy _2) -> [success: bb1, unwind + // CHECK: _3 = copy _2; + // CHECK: [[LT:_.+]] = Lt(copy _3, const N); + // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", const N, copy _3) -> [success: bb1, unwind // CHECK: bb1: - // CHECK: _0 = &(*_1)[_2]; + // CHECK: _5 = &(*_1)[_3]; + // CHECK: _0 = &(*_5); &array[index] } // EMIT_MIR index_array_and_slice.index_slice.built.after.mir fn index_slice(slice: &[i32], index: usize) -> &i32 { // CHECK: bb0: + // CHECK: _3 = copy _2; // CHECK: [[LEN:_.+]] = PtrMetadata(copy _1); - // CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]); - // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1, + // CHECK: [[LT:_.+]] = Lt(copy _3, copy [[LEN]]); + // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _3) -> [success: bb1, // CHECK: bb1: - // CHECK: _0 = &(*_1)[_2]; + // CHECK: _6 = &(*_1)[_3]; + // CHECK: _0 = &(*_6); &slice[index] } @@ -40,12 +46,15 @@ fn index_mut_slice(slice: &mut [i32], index: usize) -> &i32 { // This cannot `copy _1` in the *built* MIR, only in the *runtime* MIR. // CHECK: bb0: - // CHECK: [[LEN:_.+]] = PtrMetadata(copy _1); - // CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]); - // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1, + // CHECK: _3 = copy _2; + // CHECK: _4 = &raw const (fake) (*_1); + // CHECK: [[LEN:_.+]] = PtrMetadata(move _4); + // CHECK: [[LT:_.+]] = Lt(copy _3, copy [[LEN]]); + // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _3) -> [success: bb1, // CHECK: bb1: - // CHECK: _0 = &(*_1)[_2]; + // CHECK: _7 = &(*_1)[_3]; + // CHECK: _0 = &(*_7); &slice[index] } @@ -54,13 +63,15 @@ struct WithSliceTail(f64, [i32]); // EMIT_MIR index_array_and_slice.index_custom.built.after.mir fn index_custom(custom: &WithSliceTail, index: usize) -> &i32 { // CHECK: bb0: + // CHECK: _3 = copy _2; // CHECK: [[PTR:_.+]] = &raw const (fake) ((*_1).1: [i32]); - // CHECK: [[LEN:_.+]] = PtrMetadata(copy [[PTR]]); - // CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]); - // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1, + // CHECK: [[LEN:_.+]] = PtrMetadata(move [[PTR]]); + // CHECK: [[LT:_.+]] = Lt(copy _3, copy [[LEN]]); + // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _3) -> [success: bb1, // CHECK: bb1: - // CHECK: _0 = &((*_1).1: [i32])[_2]; + // CHECK: _7 = &((*_1).1: [i32])[_3]; + // CHECK: _0 = &(*_7); &custom.1[index] } diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir index 8a36c901eed..fa35658a16d 100644 --- a/tests/mir-opt/building/issue_101867.main.built.after.mir +++ b/tests/mir-opt/building/issue_101867.main.built.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option -| 1: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option +| 0: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:5:12: 5:22, inferred_ty: std::option::Option +| 1: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:5:12: 5:22, inferred_ty: std::option::Option | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/issue_101867.rs b/tests/mir-opt/building/issue_101867.rs index f8a531e8982..a00bc13b3fe 100644 --- a/tests/mir-opt/building/issue_101867.rs +++ b/tests/mir-opt/building/issue_101867.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zmir-opt-level=0 // skip-filecheck // EMIT_MIR issue_101867.main.built.after.mir fn main() { diff --git a/tests/mir-opt/building/issue_110508.rs b/tests/mir-opt/building/issue_110508.rs index e597cd5d06b..aa8a7b1d08f 100644 --- a/tests/mir-opt/building/issue_110508.rs +++ b/tests/mir-opt/building/issue_110508.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zmir-opt-level=0 // skip-filecheck // EMIT_MIR issue_110508.{impl#0}-BAR.built.after.mir // EMIT_MIR issue_110508.{impl#0}-SELF_BAR.built.after.mir diff --git a/tests/mir-opt/building/issue_110508.{impl#0}-BAR.built.after.mir b/tests/mir-opt/building/issue_110508.{impl#0}-BAR.built.after.mir index c3d28fae518..0cefb9c8fd1 100644 --- a/tests/mir-opt/building/issue_110508.{impl#0}-BAR.built.after.mir +++ b/tests/mir-opt/building/issue_110508.{impl#0}-BAR.built.after.mir @@ -1,6 +1,6 @@ -// MIR for `::BAR` after built +// MIR for `::BAR` after built -const ::BAR: Foo = { +const ::BAR: Foo = { let mut _0: Foo; let mut _1: (); diff --git a/tests/mir-opt/building/issue_110508.{impl#0}-SELF_BAR.built.after.mir b/tests/mir-opt/building/issue_110508.{impl#0}-SELF_BAR.built.after.mir index 177518c30af..0e0e9149385 100644 --- a/tests/mir-opt/building/issue_110508.{impl#0}-SELF_BAR.built.after.mir +++ b/tests/mir-opt/building/issue_110508.{impl#0}-SELF_BAR.built.after.mir @@ -1,6 +1,6 @@ -// MIR for `::SELF_BAR` after built +// MIR for `::SELF_BAR` after built -const ::SELF_BAR: Foo = { +const ::SELF_BAR: Foo = { let mut _0: Foo; let mut _1: (); diff --git a/tests/mir-opt/building/issue_49232.rs b/tests/mir-opt/building/issue_49232.rs index ac06e02778f..f17e3e955a4 100644 --- a/tests/mir-opt/building/issue_49232.rs +++ b/tests/mir-opt/building/issue_49232.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zmir-opt-level=0 // skip-filecheck // We must mark a variable whose initialization fails due to an // abort statement as StorageDead. diff --git a/tests/mir-opt/building/logical_or_in_conditional.rs b/tests/mir-opt/building/logical_or_in_conditional.rs index 249ccf72804..d1c1ea2896a 100644 --- a/tests/mir-opt/building/logical_or_in_conditional.rs +++ b/tests/mir-opt/building/logical_or_in_conditional.rs @@ -1,5 +1,5 @@ // skip-filecheck -//@ compile-flags: -Z validate-mir +//@ compile-flags: -Zmir-opt-level=0 -Z validate-mir //@ edition: 2024 struct Droppy(u8); impl Drop for Droppy { diff --git a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir index 744553c7cd2..5cf182c21c3 100644 --- a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir +++ b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir @@ -1,10 +1,10 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test -| 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test -| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test -| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test +| 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:16:14: 16:23, inferred_ty: *mut Test +| 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:16:14: 16:23, inferred_ty: *mut Test +| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:20:18: 20:31, inferred_ty: &&&&*mut Test +| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:20:18: 20:31, inferred_ty: &&&&*mut Test | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/receiver_ptr_mutability.rs b/tests/mir-opt/building/receiver_ptr_mutability.rs index 1ddb8b71a5a..37b142f1d8a 100644 --- a/tests/mir-opt/building/receiver_ptr_mutability.rs +++ b/tests/mir-opt/building/receiver_ptr_mutability.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zmir-opt-level=0 // skip-filecheck // EMIT_MIR receiver_ptr_mutability.main.built.after.mir diff --git a/tests/mir-opt/building/shifts.rs b/tests/mir-opt/building/shifts.rs index d7747bb2f78..165b388bc18 100644 --- a/tests/mir-opt/building/shifts.rs +++ b/tests/mir-opt/building/shifts.rs @@ -1,5 +1,5 @@ // skip-filecheck -//@ compile-flags: -C debug-assertions=yes +//@ compile-flags: -Zmir-opt-level=0 -C debug-assertions=yes // EMIT_MIR shifts.shift_signed.built.after.mir fn shift_signed(small: i8, big: u128, a: i8, b: i32, c: i128) -> ([i8; 3], [u128; 3]) { diff --git a/tests/mir-opt/building/storage_live_dead_in_statics.rs b/tests/mir-opt/building/storage_live_dead_in_statics.rs index 7cb74acbf06..868f4a8f559 100644 --- a/tests/mir-opt/building/storage_live_dead_in_statics.rs +++ b/tests/mir-opt/building/storage_live_dead_in_statics.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zmir-opt-level=0 // skip-filecheck // Check that when we compile the static `XXX` into MIR, we do not // generate `StorageStart` or `StorageEnd` statements. diff --git a/tests/mir-opt/building/uniform_array_move_out.rs b/tests/mir-opt/building/uniform_array_move_out.rs index aff5996d0b6..36245273fe1 100644 --- a/tests/mir-opt/building/uniform_array_move_out.rs +++ b/tests/mir-opt/building/uniform_array_move_out.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zmir-opt-level=0 // skip-filecheck #![feature(liballoc_internals, rustc_attrs)] diff --git a/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir index 3d26fe24ac9..bbf504d311f 100644 --- a/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir @@ -1,8 +1,8 @@ // MIR for `let_else` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:35:20: 35:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:35:20: 35:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:36:20: 36:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:36:20: 36:45, inferred_ty: (u32, u64, &char) | fn let_else() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir index b2a06ae53a8..7bf2551e99f 100644 --- a/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir @@ -1,8 +1,8 @@ // MIR for `let_else_bindless` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:40:20: 40:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:40:20: 40:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:41:20: 41:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:41:20: 41:45, inferred_ty: (u32, u64, &char) | fn let_else_bindless() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir index d1b8f823e9b..0cf681d8ab2 100644 --- a/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir @@ -1,8 +1,8 @@ // MIR for `let_init` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:25:20: 25:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:25:20: 25:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:26:20: 26:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:26:20: 26:45, inferred_ty: (u32, u64, &char) | fn let_init() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir index 6702f930060..968813c826e 100644 --- a/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir @@ -1,8 +1,8 @@ // MIR for `let_init_bindless` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:30:20: 30:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:30:20: 30:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:31:20: 31:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:31:20: 31:45, inferred_ty: (u32, u64, &char) | fn let_init_bindless() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir index 76b5938b87d..b6fdc4ff46d 100644 --- a/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir @@ -1,7 +1,7 @@ // MIR for `let_uninit` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:15:20: 15:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:16:20: 16:45, inferred_ty: (u32, u64, &char) | fn let_uninit() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir index 0cd12558771..472dbfb6304 100644 --- a/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir @@ -1,7 +1,7 @@ // MIR for `let_uninit_bindless` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:20:20: 20:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:21:20: 21:45, inferred_ty: (u32, u64, &char) | fn let_uninit_bindless() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir b/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir index c0ce6f1d06b..ff4b0bf7600 100644 --- a/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir @@ -1,8 +1,8 @@ // MIR for `match_assoc_const` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:54:9: 54:44, inferred_ty: u32 -| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:54:9: 54:44, inferred_ty: u32 +| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:55:9: 55:44, inferred_ty: u32 +| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:55:9: 55:44, inferred_ty: u32 | fn match_assoc_const() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir b/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir index 3a6aa5b7c2c..4cc433f475f 100644 --- a/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir @@ -1,10 +1,10 @@ // MIR for `match_assoc_const_range` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:62:11: 62:46, inferred_ty: u32 -| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:62:11: 62:46, inferred_ty: u32 -| 2: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:63:9: 63:44, inferred_ty: u32 -| 3: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:63:9: 63:44, inferred_ty: u32 +| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:63:11: 63:46, inferred_ty: u32 +| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:63:11: 63:46, inferred_ty: u32 +| 2: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:64:9: 64:44, inferred_ty: u32 +| 3: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:64:9: 64:44, inferred_ty: u32 | fn match_assoc_const_range() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.rs b/tests/mir-opt/building/user_type_annotations.rs index d55c678d5ae..527bf62f7dc 100644 --- a/tests/mir-opt/building/user_type_annotations.rs +++ b/tests/mir-opt/building/user_type_annotations.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Zmir-opt-level=0 //@ edition: 2024 // skip-filecheck -- cgit 1.4.1-3-g733a5 From 777e2d6a2aa92be8f966c147b0d5c96930873807 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 22 Aug 2025 07:04:59 +1000 Subject: Add `thin-vec` to newly added `[workspace.dependencies]`. --- Cargo.toml | 5 +++++ compiler/rustc_ast/Cargo.toml | 2 +- compiler/rustc_ast_lowering/Cargo.toml | 2 +- compiler/rustc_ast_passes/Cargo.toml | 2 +- compiler/rustc_ast_pretty/Cargo.toml | 2 +- compiler/rustc_attr_parsing/Cargo.toml | 2 +- compiler/rustc_builtin_macros/Cargo.toml | 2 +- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_expand/Cargo.toml | 2 +- compiler/rustc_hir/Cargo.toml | 2 +- compiler/rustc_incremental/Cargo.toml | 2 +- compiler/rustc_infer/Cargo.toml | 2 +- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_parse/Cargo.toml | 2 +- compiler/rustc_resolve/Cargo.toml | 2 +- compiler/rustc_serialize/Cargo.toml | 2 +- compiler/rustc_trait_selection/Cargo.toml | 2 +- compiler/rustc_type_ir/Cargo.toml | 2 +- 19 files changed, 23 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 67c7a9d67ed..58c02a80906 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,6 +59,11 @@ exclude = [ "obj", ] +[workspace.dependencies] +# tidy-alphabetical-start +thin-vec = "0.2.14" +# tidy-alphabetical-end + [profile.release.package.rustc_thread_pool] # The rustc fork of Rayon has deadlock detection code which intermittently # causes overflows in the CI (see https://github.com/rust-lang/rust/issues/90227) diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 155e14a3796..b964e378b1e 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -15,6 +15,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.12" +thin-vec.workspace = true tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 6ac258155fe..f34c1a6d364 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -24,6 +24,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.12" +thin-vec.workspace = true tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 3e04f8b11ec..0e82f34034f 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -18,5 +18,5 @@ rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -thin-vec = "0.2.12" +thin-vec.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index b704040be96..d52477be9df 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -13,5 +13,5 @@ rustc_span = { path = "../rustc_span" } [dev-dependencies] # tidy-alphabetical-start -thin-vec = "0.2.12" +thin-vec.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index fd8f7ffb2ed..ba95b630b8c 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -17,5 +17,5 @@ rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -thin-vec = "0.2.12" +thin-vec.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index e56b9e641a1..3c3accad374 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -30,6 +30,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.12" +thin-vec.workspace = true tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 6a8971de746..9081875141a 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -40,7 +40,7 @@ rustc_trait_selection = { path = "../rustc_trait_selection" } serde_json = "1.0.59" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tempfile = "3.2" -thin-vec = "0.2.12" +thin-vec.workspace = true thorin-dwp = "0.9" tracing = "0.1" wasm-encoder = "0.219" diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 17204883fb0..1ed9c7d7ddc 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -25,7 +25,7 @@ rustc_thread_pool = { path = "../rustc_thread_pool" } smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] } stacker = "0.1.17" tempfile = "3.2" -thin-vec = "0.2.12" +thin-vec.workspace = true tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index f897833d85c..fc8b57f716b 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -29,6 +29,6 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.12" +thin-vec.workspace = true tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index 1008a3e787d..bf206973809 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -21,6 +21,6 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.12" +thin-vec.workspace = true tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml index db0a5841887..4b4c10334a4 100644 --- a/compiler/rustc_incremental/Cargo.toml +++ b/compiler/rustc_incremental/Cargo.toml @@ -19,6 +19,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -thin-vec = "0.2.12" +thin-vec.workspace = true tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 08c03614884..ad89c6d1b94 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -18,6 +18,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.12" +thin-vec.workspace = true tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index fbcce16cedc..352d9ca514a 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -34,7 +34,7 @@ rustc_target = { path = "../rustc_target" } rustc_thread_pool = { path = "../rustc_thread_pool" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.12" +thin-vec.workspace = true tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 6d738a10371..c205c7a63ed 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -18,7 +18,7 @@ rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -thin-vec = "0.2.12" +thin-vec.workspace = true tracing = "0.1" unicode-normalization = "0.1.11" unicode-width = "0.2.0" diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index eb98a6e85c0..760aae9050f 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -27,6 +27,6 @@ rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.12" +thin-vec.workspace = true tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index 948242352e7..e9959735f9f 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -8,7 +8,7 @@ edition = "2024" indexmap = "2.0.0" rustc_hashes = { path = "../rustc_hashes" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.12" +thin-vec.workspace = true # tidy-alphabetical-end [dev-dependencies] diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 1071105522d..84296fcfa3e 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -21,6 +21,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2" +thin-vec.workspace = true tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index d55e9b3b1be..fd655c7da02 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -19,7 +19,7 @@ rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_span = { path = "../rustc_span", optional = true } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } smallvec = { version = "1.8.1", default-features = false, features = ["const_generics"] } -thin-vec = "0.2.12" +thin-vec.workspace = true tracing = "0.1" # tidy-alphabetical-end -- cgit 1.4.1-3-g733a5 From 82c4b9c51b0257e2ad33903bc730cd4a6a69217b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 22 Aug 2025 07:11:24 +1000 Subject: Add `bitflags` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_abi/Cargo.toml | 2 +- compiler/rustc_ast/Cargo.toml | 2 +- compiler/rustc_codegen_llvm/Cargo.toml | 2 +- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_hir/Cargo.toml | 2 +- compiler/rustc_metadata/Cargo.toml | 2 +- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_parse/Cargo.toml | 2 +- compiler/rustc_resolve/Cargo.toml | 2 +- compiler/rustc_sanitizers/Cargo.toml | 2 +- compiler/rustc_session/Cargo.toml | 2 +- compiler/rustc_target/Cargo.toml | 2 +- compiler/rustc_type_ir/Cargo.toml | 2 +- 15 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 58c02a80906..f0c35bc4fc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,6 +61,7 @@ exclude = [ [workspace.dependencies] # tidy-alphabetical-start +bitflags = "2.9.3" thin-vec = "0.2.14" # tidy-alphabetical-end diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index 83d96d8d04d..85a71ea8f87 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" +bitflags.workspace = true rand = { version = "0.9.0", default-features = false, optional = true } rand_xoshiro = { version = "0.7.0", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index b964e378b1e..08c8d539752 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" +bitflags.workspace = true memchr = "2.7.4" rustc-literal-escaper = "0.0.5" rustc_ast_ir = { path = "../rustc_ast_ir" } diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 2d11628250c..e7660cc2c29 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -8,7 +8,7 @@ test = false [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" +bitflags.workspace = true # To avoid duplicate dependencies, this should match the version of gimli used # by `rustc_codegen_ssa` via its `thorin-dwp` dependency. gimli = "0.31" diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 9081875141a..974be3f9534 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start ar_archive_writer = "0.4.2" -bitflags = "2.4.1" +bitflags.workspace = true bstr = "1.11.3" # `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version # per crate", so if you change this, you need to also change it in `rustc_llvm`. diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 1ed9c7d7ddc..f8040e516ed 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start arrayvec = { version = "0.7", default-features = false } -bitflags = "2.4.1" +bitflags.workspace = true either = "1.0" elsa = "1.11.0" ena = "0.14.3" diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index bf206973809..f1420c34a6d 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.9.1" +bitflags.workspace = true odht = { version = "0.3.1", features = ["nightly"] } rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 1b40d9f684e..860b92c6a95 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" +bitflags.workspace = true libloading = "0.8.0" odht = { version = "0.3.1", features = ["nightly"] } rustc_abi = { path = "../rustc_abi" } diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 352d9ca514a..a42819bbb99 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" +bitflags.workspace = true either = "1.5.0" gsgdt = "0.1.2" polonius-engine = "0.13.0" diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index c205c7a63ed..189ee6cccf7 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" +bitflags.workspace = true rustc-literal-escaper = "0.0.5" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 760aae9050f..41f2512fcec 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" +bitflags.workspace = true indexmap = "2.4.0" itertools = "0.12" pulldown-cmark = { version = "0.11", features = ["html"], default-features = false } diff --git a/compiler/rustc_sanitizers/Cargo.toml b/compiler/rustc_sanitizers/Cargo.toml index 9069d2c233d..bf16ef3d7be 100644 --- a/compiler/rustc_sanitizers/Cargo.toml +++ b/compiler/rustc_sanitizers/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.5.0" +bitflags.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 60d56b1b808..9624eecc3f8 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" +bitflags.workspace = true getopts = "0.2" rand = "0.9.0" rustc_abi = { path = "../rustc_abi" } diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index 57c90a703f1..0f19683a473 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" +bitflags.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_messages = { path = "../rustc_error_messages" } diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index fd655c7da02..6583ec33e40 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" +bitflags.workspace = true derive-where = "1.2.7" ena = "0.14.3" indexmap = "2.0.0" -- cgit 1.4.1-3-g733a5 From dfa748e910b7b1cda37bfe709cd026da66a63e4c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 22 Aug 2025 07:26:26 +1000 Subject: Add `memchr` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_ast/Cargo.toml | 2 +- compiler/rustc_lexer/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f0c35bc4fc5..eef3ed43715 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ exclude = [ [workspace.dependencies] # tidy-alphabetical-start bitflags = "2.9.3" +memchr = "2.7.5" thin-vec = "0.2.14" # tidy-alphabetical-end diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 08c8d539752..5eddc6e29e4 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags.workspace = true -memchr = "2.7.4" +memchr.workspace = true rustc-literal-escaper = "0.0.5" rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml index 448a50faf45..b46f395a132 100644 --- a/compiler/rustc_lexer/Cargo.toml +++ b/compiler/rustc_lexer/Cargo.toml @@ -14,7 +14,7 @@ Rust lexer used by rustc. No stability guarantees are provided. # Note that this crate purposefully does not depend on other rustc crates [dependencies] -memchr = "2.7.4" +memchr.workspace = true unicode-xid = "0.2.0" [dependencies.unicode-properties] -- cgit 1.4.1-3-g733a5 From 32b0fff8fe750ee61b77481d0db1fe2c5cb5e63b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 22 Aug 2025 07:30:50 +1000 Subject: Add `rustc-literal-escaper` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_ast/Cargo.toml | 2 +- compiler/rustc_parse/Cargo.toml | 2 +- compiler/rustc_parse_format/Cargo.toml | 2 +- compiler/rustc_proc_macro/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index eef3ed43715..17ba5014ede 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,6 +63,7 @@ exclude = [ # tidy-alphabetical-start bitflags = "2.9.3" memchr = "2.7.5" +rustc-literal-escaper = "0.0.5" thin-vec = "0.2.14" # tidy-alphabetical-end diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 5eddc6e29e4..0b8ab7c391c 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start bitflags.workspace = true memchr.workspace = true -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper.workspace = true rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 189ee6cccf7..ca0a57248b0 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags.workspace = true -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper.workspace = true rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index d178fcda1fb..645e34b6e32 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper.workspace = true rustc_lexer = { path = "../rustc_lexer" } # tidy-alphabetical-end diff --git a/compiler/rustc_proc_macro/Cargo.toml b/compiler/rustc_proc_macro/Cargo.toml index beb95aa3b52..99e7fc7abc6 100644 --- a/compiler/rustc_proc_macro/Cargo.toml +++ b/compiler/rustc_proc_macro/Cargo.toml @@ -16,7 +16,7 @@ doctest = false [dependencies] # tidy-alphabetical-start -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper.workspace = true # tidy-alphabetical-end [features] -- cgit 1.4.1-3-g733a5 From c50d2cc8078280a0dfdd562c7688e81b664e5880 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 22 Aug 2025 10:39:58 +1000 Subject: Add `tracing` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_abi/Cargo.toml | 2 +- compiler/rustc_ast_lowering/Cargo.toml | 2 +- compiler/rustc_borrowck/Cargo.toml | 2 +- compiler/rustc_builtin_macros/Cargo.toml | 2 +- compiler/rustc_codegen_llvm/Cargo.toml | 2 +- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- compiler/rustc_const_eval/Cargo.toml | 2 +- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_driver_impl/Cargo.toml | 2 +- compiler/rustc_error_messages/Cargo.toml | 2 +- compiler/rustc_errors/Cargo.toml | 2 +- compiler/rustc_expand/Cargo.toml | 2 +- compiler/rustc_hir/Cargo.toml | 2 +- compiler/rustc_hir_analysis/Cargo.toml | 2 +- compiler/rustc_hir_typeck/Cargo.toml | 2 +- compiler/rustc_incremental/Cargo.toml | 2 +- compiler/rustc_infer/Cargo.toml | 2 +- compiler/rustc_interface/Cargo.toml | 2 +- compiler/rustc_lint/Cargo.toml | 2 +- compiler/rustc_log/Cargo.toml | 2 +- compiler/rustc_metadata/Cargo.toml | 2 +- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_mir_build/Cargo.toml | 2 +- compiler/rustc_mir_dataflow/Cargo.toml | 2 +- compiler/rustc_mir_transform/Cargo.toml | 2 +- compiler/rustc_monomorphize/Cargo.toml | 2 +- compiler/rustc_next_trait_solver/Cargo.toml | 2 +- compiler/rustc_parse/Cargo.toml | 2 +- compiler/rustc_passes/Cargo.toml | 2 +- compiler/rustc_pattern_analysis/Cargo.toml | 2 +- compiler/rustc_privacy/Cargo.toml | 2 +- compiler/rustc_public/Cargo.toml | 2 +- compiler/rustc_query_impl/Cargo.toml | 2 +- compiler/rustc_query_system/Cargo.toml | 2 +- compiler/rustc_resolve/Cargo.toml | 2 +- compiler/rustc_sanitizers/Cargo.toml | 2 +- compiler/rustc_session/Cargo.toml | 2 +- compiler/rustc_span/Cargo.toml | 2 +- compiler/rustc_symbol_mangling/Cargo.toml | 2 +- compiler/rustc_target/Cargo.toml | 2 +- compiler/rustc_trait_selection/Cargo.toml | 2 +- compiler/rustc_traits/Cargo.toml | 2 +- compiler/rustc_transmute/Cargo.toml | 2 +- compiler/rustc_ty_utils/Cargo.toml | 2 +- compiler/rustc_type_ir/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 2 +- src/tools/compiletest/Cargo.toml | 2 +- src/tools/llvm-bitcode-linker/Cargo.toml | 4 ++-- 49 files changed, 50 insertions(+), 49 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 17ba5014ede..7bb0ec2b92f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,7 @@ bitflags = "2.9.3" memchr = "2.7.5" rustc-literal-escaper = "0.0.5" thin-vec = "0.2.14" +tracing = "0.1.37" # tidy-alphabetical-end [profile.release.package.rustc_thread_pool] diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index 85a71ea8f87..3de6d186b8a 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -15,7 +15,7 @@ rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_span = { path = "../rustc_span", optional = true } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [features] diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index f34c1a6d364..317742a3bb8 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -25,5 +25,5 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec.workspace = true -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index 9e7d55180a2..255f71c65b6 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -25,5 +25,5 @@ rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_traits = { path = "../rustc_traits" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index 3c3accad374..9ca44d67150 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -31,5 +31,5 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec.workspace = true -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index e7660cc2c29..11c3ecc5cb7 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -40,7 +40,7 @@ rustc_target = { path = "../rustc_target" } serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [features] diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 974be3f9534..75b5261393b 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -42,7 +42,7 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tempfile = "3.2" thin-vec.workspace = true thorin-dwp = "0.9" -tracing = "0.1" +tracing.workspace = true wasm-encoder = "0.219" # tidy-alphabetical-end diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index 51dcee8d882..88dfc83f7fc 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -22,5 +22,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index f8040e516ed..aa964806a87 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -26,7 +26,7 @@ smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dang stacker = "0.1.17" tempfile = "3.2" thin-vec.workspace = true -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [dependencies.hashbrown] diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index ae1dbd2cf51..7e9af054aff 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -51,7 +51,7 @@ rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } serde_json = "1.0.59" shlex = "1.0" -tracing = { version = "0.1.35" } +tracing.workspace = true # tidy-alphabetical-end [target.'cfg(all(unix, any(target_env = "gnu", target_os = "macos")))'.dependencies] diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml index 552ad672752..ce5106aae0a 100644 --- a/compiler/rustc_error_messages/Cargo.toml +++ b/compiler/rustc_error_messages/Cargo.toml @@ -18,6 +18,6 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } -tracing = "0.1" +tracing.workspace = true unic-langid = { version = "0.9.0", features = ["macros"] } # tidy-alphabetical-end diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 7912b8e6098..f5853855673 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -24,7 +24,7 @@ serde = { version = "1.0.125", features = ["derive"] } serde_json = "1.0.59" termcolor = "1.2.0" termize = "0.2" -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index fc8b57f716b..9bb7143af51 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -30,5 +30,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec.workspace = true -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index f1420c34a6d..ea72ed68c5e 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -22,5 +22,5 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec.workspace = true -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index e5017794d8f..910c26e4427 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -29,5 +29,5 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index f00125c3e09..e5a0ad8076b 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -25,5 +25,5 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml index 4b4c10334a4..8d7f2eb8414 100644 --- a/compiler/rustc_incremental/Cargo.toml +++ b/compiler/rustc_incremental/Cargo.toml @@ -20,5 +20,5 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } thin-vec.workspace = true -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index ad89c6d1b94..6d97fa6af1f 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -19,5 +19,5 @@ rustc_span = { path = "../rustc_span" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec.workspace = true -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 473ac5e0cea..40152e78f8a 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -46,7 +46,7 @@ rustc_thread_pool = { path = "../rustc_thread_pool" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_traits = { path = "../rustc_traits" } rustc_ty_utils = { path = "../rustc_ty_utils" } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [dev-dependencies] diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index 7718f16984d..7900e4b9ab2 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -24,6 +24,6 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing = "0.1" +tracing.workspace = true unicode-security = "0.1.0" # tidy-alphabetical-end diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml index c673d51a1d4..e9d7b4723f8 100644 --- a/compiler/rustc_log/Cargo.toml +++ b/compiler/rustc_log/Cargo.toml @@ -5,10 +5,10 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -tracing = "0.1.28" tracing-core = "=0.1.30" # FIXME(Nilstrieb) tracing has a deadlock: https://github.com/tokio-rs/tracing/issues/2635 tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } tracing-tree = "0.3.1" +tracing.workspace = true # tidy-alphabetical-end [features] diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 860b92c6a95..4bb9e49ccce 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -31,7 +31,7 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } tempfile = "3.7.1" -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [target.'cfg(target_os = "aix")'.dependencies] diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index a42819bbb99..782066981c9 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -35,7 +35,7 @@ rustc_thread_pool = { path = "../rustc_thread_pool" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec.workspace = true -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [features] diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index f756f0a19ee..7729b14512a 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -23,5 +23,5 @@ rustc_pattern_analysis = { path = "../rustc_pattern_analysis" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml index 9621f9f20bd..e422f69c7ca 100644 --- a/compiler/rustc_mir_dataflow/Cargo.toml +++ b/compiler/rustc_mir_dataflow/Cargo.toml @@ -18,5 +18,5 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index 08c43a4648c..2ad5da0ff00 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -26,5 +26,5 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 09a55f0b5f8..b11084cf169 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -17,5 +17,5 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } serde = "1" serde_json = "1" -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 05bcabad02f..8b66f30cf0e 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -11,7 +11,7 @@ rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_type_ir = { path = "../rustc_type_ir", default-features = false } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [features] diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index ca0a57248b0..7cb4ae7ff5f 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -19,7 +19,7 @@ rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } thin-vec.workspace = true -tracing = "0.1" +tracing.workspace = true unicode-normalization = "0.1.11" unicode-width = "0.2.0" # tidy-alphabetical-end diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index ba81ef3103b..c74608a6146 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -24,5 +24,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index a59f7bbeb9e..39f660c8771 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -19,7 +19,7 @@ rustc_middle = { path = "../rustc_middle", optional = true } rustc_session = { path = "../rustc_session", optional = true } rustc_span = { path = "../rustc_span", optional = true } smallvec = { version = "1.8.1", features = ["union"] } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [dev-dependencies] diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml index c8bfdb91304..7de58132e13 100644 --- a/compiler/rustc_privacy/Cargo.toml +++ b/compiler/rustc_privacy/Cargo.toml @@ -15,5 +15,5 @@ rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_ty_utils = { path = "../rustc_ty_utils" } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_public/Cargo.toml b/compiler/rustc_public/Cargo.toml index 70af30c1a5f..71d339b5792 100644 --- a/compiler/rustc_public/Cargo.toml +++ b/compiler/rustc_public/Cargo.toml @@ -14,7 +14,7 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } scoped-tls = "1.0" serde = { version = "1.0.125", features = [ "derive" ] } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [features] diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index e5cceacf15d..2005b8b9eca 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -15,5 +15,5 @@ rustc_query_system = { path = "../rustc_query_system" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 7480ba03474..0df933bc81c 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -21,7 +21,7 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_thread_pool = { path = "../rustc_thread_pool" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [dependencies.hashbrown] diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 41f2512fcec..356669704f1 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -28,5 +28,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec.workspace = true -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_sanitizers/Cargo.toml b/compiler/rustc_sanitizers/Cargo.toml index bf16ef3d7be..3dbeaa435f3 100644 --- a/compiler/rustc_sanitizers/Cargo.toml +++ b/compiler/rustc_sanitizers/Cargo.toml @@ -13,6 +13,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing = "0.1" +tracing.workspace = true twox-hash = "1.6.3" # tidy-alphabetical-end diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 9624eecc3f8..97789b198a4 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -23,7 +23,7 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } termize = "0.2" -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 43a2d692577..2e45177e3b7 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -19,6 +19,6 @@ rustc_serialize = { path = "../rustc_serialize" } scoped-tls = "1.0" sha1 = "0.10.0" sha2 = "0.10.1" -tracing = "0.1" +tracing.workspace = true unicode-width = "0.2.0" # tidy-alphabetical-end diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 0df9c7682bf..48e02dabdde 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -15,5 +15,5 @@ rustc_hir = { path = "../rustc_hir" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index 0f19683a473..7ad2a332761 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -17,7 +17,7 @@ serde = "1.0.219" serde_derive = "1.0.219" serde_json = "1.0.59" serde_path_to_error = "0.1.17" -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [dependencies.object] diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 84296fcfa3e..91a6484f865 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -22,5 +22,5 @@ rustc_span = { path = "../rustc_span" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec.workspace = true -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 9f40f4d5c23..24360a94cc7 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -10,5 +10,5 @@ rustc_infer = { path = "../rustc_infer" } rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index e61717e5e9c..d9df43f9edf 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -11,7 +11,7 @@ rustc_hir = { path = "../rustc_hir", optional = true } rustc_middle = { path = "../rustc_middle", optional = true } rustc_span = { path = "../rustc_span", optional = true } smallvec = "1.8.1" -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [dev-dependencies] diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index ce08b300cc8..3a58ec21933 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -20,5 +20,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 6583ec33e40..1dba7fe4269 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -20,7 +20,7 @@ rustc_span = { path = "../rustc_span", optional = true } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } smallvec = { version = "1.8.1", default-features = false, features = ["const_generics"] } thin-vec.workspace = true -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [features] diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 5d36ffc2d3a..60958633bed 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -24,8 +24,8 @@ smallvec = "1.8.1" stringdex = { version = "0.0.1-alpha4" } tempfile = "3" threadpool = "1.8.1" -tracing = "0.1" tracing-tree = "0.3.0" +tracing.workspace = true unicode-segmentation = "1.9" # tidy-alphabetical-end diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index cdada5a2230..220c29cec49 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -28,8 +28,8 @@ rustfix = "0.8.1" semver = { version = "1.0.23", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -tracing = "0.1" tracing-subscriber = { version = "0.3.3", default-features = false, features = ["ansi", "env-filter", "fmt", "parking_lot", "smallvec"] } +tracing.workspace = true unified-diff = "0.2.1" walkdir = "2" # tidy-alphabetical-end diff --git a/src/tools/llvm-bitcode-linker/Cargo.toml b/src/tools/llvm-bitcode-linker/Cargo.toml index a9210b562f3..f78f8b618d3 100644 --- a/src/tools/llvm-bitcode-linker/Cargo.toml +++ b/src/tools/llvm-bitcode-linker/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] anyhow = "1.0" -tracing = "0.1" -tracing-subscriber = {version = "0.3.0", features = ["std"] } +tracing.workspace = true +tracing-subscriber = { version = "0.3.0", features = ["std"] } clap = { version = "4.3", features = ["derive"] } thiserror = "1.0.24" -- cgit 1.4.1-3-g733a5 From 200f56d605e4e6cfad4ee4ef461a26c9c6a90f3d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 22 Aug 2025 13:07:23 +1000 Subject: Add `itertools` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_ast_passes/Cargo.toml | 2 +- compiler/rustc_ast_pretty/Cargo.toml | 2 +- compiler/rustc_borrowck/Cargo.toml | 2 +- compiler/rustc_codegen_llvm/Cargo.toml | 2 +- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- compiler/rustc_hir_analysis/Cargo.toml | 2 +- compiler/rustc_hir_typeck/Cargo.toml | 2 +- compiler/rustc_mir_build/Cargo.toml | 2 +- compiler/rustc_mir_transform/Cargo.toml | 2 +- compiler/rustc_resolve/Cargo.toml | 2 +- compiler/rustc_trait_selection/Cargo.toml | 2 +- compiler/rustc_transmute/Cargo.toml | 2 +- compiler/rustc_ty_utils/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 2 +- src/tools/coverage-dump/Cargo.toml | 2 +- 16 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7bb0ec2b92f..5003e107cc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ exclude = [ [workspace.dependencies] # tidy-alphabetical-start bitflags = "2.9.3" +itertools = "0.12.1" memchr = "2.7.5" rustc-literal-escaper = "0.0.5" thin-vec = "0.2.14" diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 0e82f34034f..6d2bcbed22b 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index d52477be9df..0c7e55305b4 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools.workspace = true rustc_ast = { path = "../rustc_ast" } rustc_lexer = { path = "../rustc_lexer" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index 255f71c65b6..3162e9da1ba 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start either = "1.5.0" -itertools = "0.12" +itertools.workspace = true polonius-engine = "0.13.0" rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 11c3ecc5cb7..26d20acbe28 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -12,7 +12,7 @@ bitflags.workspace = true # To avoid duplicate dependencies, this should match the version of gimli used # by `rustc_codegen_ssa` via its `thorin-dwp` dependency. gimli = "0.31" -itertools = "0.12" +itertools.workspace = true libc = "0.2" measureme = "12.0.1" object = { version = "0.37.0", default-features = false, features = ["std", "read"] } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 75b5261393b..6b989a96488 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -11,7 +11,7 @@ bstr = "1.11.3" # `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version # per crate", so if you change this, you need to also change it in `rustc_llvm`. cc = "=1.2.16" -itertools = "0.12" +itertools.workspace = true pathdiff = "0.2.0" regex = "1.4" rustc_abi = { path = "../rustc_abi" } diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index 910c26e4427..bb86beb2251 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -9,7 +9,7 @@ doctest = false [dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index e5a0ad8076b..5af0c6134ca 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index 7729b14512a..c3f7fdfcb00 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index 2ad5da0ff00..16acec15e92 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start either = "1" -itertools = "0.12" +itertools.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 356669704f1..7c5332c1662 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start bitflags.workspace = true indexmap = "2.4.0" -itertools = "0.12" +itertools.workspace = true pulldown-cmark = { version = "0.11", features = ["html"], default-features = false } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 91a6484f865..6b79b98d1bf 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index d9df43f9edf..2ac2b46cc58 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -16,7 +16,7 @@ tracing.workspace = true [dev-dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools.workspace = true # tidy-alphabetical-end [features] diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index 3a58ec21933..394cde5a323 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 60958633bed..02a3a4e0de4 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -13,7 +13,7 @@ arrayvec = { version = "0.7", default-features = false } askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] } base64 = "0.21.7" indexmap = "2" -itertools = "0.12" +itertools.workspace = true minifier = { version = "0.3.5", default-features = false } pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] } regex = "1" diff --git a/src/tools/coverage-dump/Cargo.toml b/src/tools/coverage-dump/Cargo.toml index 36a66f16030..2f703537b59 100644 --- a/src/tools/coverage-dump/Cargo.toml +++ b/src/tools/coverage-dump/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] anyhow = "1.0.71" -itertools = "0.12" +itertools.workspace = true leb128 = "0.2.5" md5 = { package = "md-5" , version = "0.10.5" } miniz_oxide = "0.8.8" -- cgit 1.4.1-3-g733a5 From 2e659f58940a31fa625e88f75f78111ed773f32d Mon Sep 17 00:00:00 2001 From: Oneirical Date: Wed, 20 Aug 2025 14:02:39 -0400 Subject: Add test batch 1 --- ...ld-generic-type-binary-assignment-error-6738.rs | 11 +++++ ...eneric-type-binary-assignment-error-6738.stderr | 16 +++++++ tests/ui/borrowck/auxiliary/aux-5518.rs | 4 ++ .../ui/borrowck/borrowed-pointer-in-struct-5884.rs | 18 +++++++ .../incorrect-loan-error-on-local-update-5550.rs | 9 ++++ .../struct-with-reference-to-trait-5708.rs | 54 +++++++++++++++++++++ .../trait-method-lifetime-substitution-5518.rs | 7 +++ tests/ui/box/box-patterns-feature-usage-6557.rs | 9 ++++ tests/ui/cast/owned-struct-to-trait-cast-6318.rs | 20 ++++++++ tests/ui/closures/closure-mut-argument-6153.rs | 13 +++++ tests/ui/codegen/static-array-comparison-7012.rs | 23 +++++++++ tests/ui/enum/enum-referred-by-submodule-5900.rs | 15 ++++++ tests/ui/enum/enum-with-generic-parameter-5997.rs | 16 +++++++ tests/ui/enum/match-either-enum-variants-6117.rs | 12 +++++ ...definition-with-outer-generic-parameter-5997.rs | 11 +++++ ...nition-with-outer-generic-parameter-5997.stderr | 13 +++++ tests/ui/issues/auxiliary/iss.rs | 12 ----- tests/ui/issues/auxiliary/issue-5518.rs | 4 -- tests/ui/issues/auxiliary/issue-5844-aux.rs | 3 -- tests/ui/issues/issue-5358-1.rs | 13 ----- tests/ui/issues/issue-5358-1.stderr | 22 --------- tests/ui/issues/issue-5439.rs | 19 -------- tests/ui/issues/issue-5439.stderr | 11 ----- tests/ui/issues/issue-5518.rs | 7 --- tests/ui/issues/issue-5550.rs | 8 ---- tests/ui/issues/issue-5554.rs | 27 ----------- tests/ui/issues/issue-5572.rs | 6 --- tests/ui/issues/issue-5666.rs | 26 ---------- tests/ui/issues/issue-5688.rs | 20 -------- tests/ui/issues/issue-5708.rs | 55 ---------------------- tests/ui/issues/issue-5718.rs | 23 --------- tests/ui/issues/issue-5741.rs | 8 ---- tests/ui/issues/issue-5844.rs | 7 --- tests/ui/issues/issue-5844.stderr | 11 ----- tests/ui/issues/issue-5883.rs | 13 ----- tests/ui/issues/issue-5883.stderr | 35 -------------- tests/ui/issues/issue-5884.rs | 17 ------- tests/ui/issues/issue-5900.rs | 14 ------ tests/ui/issues/issue-5917.rs | 9 ---- tests/ui/issues/issue-5950.rs | 8 ---- tests/ui/issues/issue-5988.rs | 23 --------- .../issue-5997-enum.rs | 10 ---- .../issue-5997-enum.stderr | 13 ----- .../issue-5997-struct.rs | 10 ---- .../issue-5997-struct.stderr | 13 ----- .../issue-5997.rs | 15 ------ tests/ui/issues/issue-6117.rs | 11 ----- tests/ui/issues/issue-6130.rs | 10 ---- tests/ui/issues/issue-6153.rs | 13 ----- tests/ui/issues/issue-6318.rs | 19 -------- tests/ui/issues/issue-6344-let.rs | 15 ------ tests/ui/issues/issue-6344-match.rs | 18 ------- tests/ui/issues/issue-6557.rs | 8 ---- tests/ui/issues/issue-6738.rs | 10 ---- tests/ui/issues/issue-6738.stderr | 16 ------- tests/ui/issues/issue-6898.rs | 32 ------------- tests/ui/issues/issue-6919.rs | 10 ---- tests/ui/issues/issue-6936.rs | 34 ------------- tests/ui/issues/issue-6936.stderr | 43 ----------------- tests/ui/issues/issue-7012.rs | 22 --------- tests/ui/loops/unreachable-while-loop-5741.rs | 9 ++++ .../macro-variable-declaration-with-bounds-5554.rs | 27 +++++++++++ .../macros/macro-variable-unused-reporting-5718.rs | 24 ++++++++++ tests/ui/match/mismatched-types-in-match-5358.rs | 18 +++++++ .../ui/match/mismatched-types-in-match-5358.stderr | 23 +++++++++ tests/ui/modules/pub-use-module-alias-5950.rs | 8 ++++ tests/ui/numeric/type-limit-comparisons-6130.rs | 11 +++++ tests/ui/parser/partial-eq-trait-bound-5572.rs | 7 +++ tests/ui/privacy/auxiliary/iss-6919.rs | 12 +++++ .../ui/privacy/deref-separate-compile-unit-6919.rs | 10 ++++ tests/ui/resolve/duplicate-name-in-module-6936.rs | 34 +++++++++++++ .../resolve/duplicate-name-in-module-6936.stderr | 43 +++++++++++++++++ tests/ui/static/static-list-initialization-5917.rs | 10 ++++ .../ui/static/static-struct-initialization-5688.rs | 21 +++++++++ .../structs/destructuring-struct-with-dtor-6344.rs | 16 +++++++ .../structs/nonexistent-struct-field-error-5439.rs | 20 ++++++++ .../nonexistent-struct-field-error-5439.stderr | 11 +++++ .../traits/dynamic-dispatch-trait-objects-5666.rs | 26 ++++++++++ tests/ui/traits/opaque-trait-size-error-5883.rs | 14 ++++++ .../ui/traits/opaque-trait-size-error-5883.stderr | 35 ++++++++++++++ .../trait-implementation-generic-access-6898.rs | 33 +++++++++++++ .../trait-implementation-restriction-5988.rs | 24 ++++++++++ tests/ui/unsafe/auxiliary/aux-5844.rs | 3 ++ .../unsafe/extern-function-requires-unsafe-5844.rs | 8 ++++ .../extern-function-requires-unsafe-5844.stderr | 11 +++++ 85 files changed, 709 insertions(+), 723 deletions(-) create mode 100644 tests/ui/binop/struct-field-generic-type-binary-assignment-error-6738.rs create mode 100644 tests/ui/binop/struct-field-generic-type-binary-assignment-error-6738.stderr create mode 100644 tests/ui/borrowck/auxiliary/aux-5518.rs create mode 100644 tests/ui/borrowck/borrowed-pointer-in-struct-5884.rs create mode 100644 tests/ui/borrowck/incorrect-loan-error-on-local-update-5550.rs create mode 100644 tests/ui/borrowck/struct-with-reference-to-trait-5708.rs create mode 100644 tests/ui/borrowck/trait-method-lifetime-substitution-5518.rs create mode 100644 tests/ui/box/box-patterns-feature-usage-6557.rs create mode 100644 tests/ui/cast/owned-struct-to-trait-cast-6318.rs create mode 100644 tests/ui/closures/closure-mut-argument-6153.rs create mode 100644 tests/ui/codegen/static-array-comparison-7012.rs create mode 100644 tests/ui/enum/enum-referred-by-submodule-5900.rs create mode 100644 tests/ui/enum/enum-with-generic-parameter-5997.rs create mode 100644 tests/ui/enum/match-either-enum-variants-6117.rs create mode 100644 tests/ui/generics/enum-definition-with-outer-generic-parameter-5997.rs create mode 100644 tests/ui/generics/enum-definition-with-outer-generic-parameter-5997.stderr delete mode 100644 tests/ui/issues/auxiliary/iss.rs delete mode 100644 tests/ui/issues/auxiliary/issue-5518.rs delete mode 100644 tests/ui/issues/auxiliary/issue-5844-aux.rs delete mode 100644 tests/ui/issues/issue-5358-1.rs delete mode 100644 tests/ui/issues/issue-5358-1.stderr delete mode 100644 tests/ui/issues/issue-5439.rs delete mode 100644 tests/ui/issues/issue-5439.stderr delete mode 100644 tests/ui/issues/issue-5518.rs delete mode 100644 tests/ui/issues/issue-5550.rs delete mode 100644 tests/ui/issues/issue-5554.rs delete mode 100644 tests/ui/issues/issue-5572.rs delete mode 100644 tests/ui/issues/issue-5666.rs delete mode 100644 tests/ui/issues/issue-5688.rs delete mode 100644 tests/ui/issues/issue-5708.rs delete mode 100644 tests/ui/issues/issue-5718.rs delete mode 100644 tests/ui/issues/issue-5741.rs delete mode 100644 tests/ui/issues/issue-5844.rs delete mode 100644 tests/ui/issues/issue-5844.stderr delete mode 100644 tests/ui/issues/issue-5883.rs delete mode 100644 tests/ui/issues/issue-5883.stderr delete mode 100644 tests/ui/issues/issue-5884.rs delete mode 100644 tests/ui/issues/issue-5900.rs delete mode 100644 tests/ui/issues/issue-5917.rs delete mode 100644 tests/ui/issues/issue-5950.rs delete mode 100644 tests/ui/issues/issue-5988.rs delete mode 100644 tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.rs delete mode 100644 tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.stderr delete mode 100644 tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.rs delete mode 100644 tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.stderr delete mode 100644 tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997.rs delete mode 100644 tests/ui/issues/issue-6117.rs delete mode 100644 tests/ui/issues/issue-6130.rs delete mode 100644 tests/ui/issues/issue-6153.rs delete mode 100644 tests/ui/issues/issue-6318.rs delete mode 100644 tests/ui/issues/issue-6344-let.rs delete mode 100644 tests/ui/issues/issue-6344-match.rs delete mode 100644 tests/ui/issues/issue-6557.rs delete mode 100644 tests/ui/issues/issue-6738.rs delete mode 100644 tests/ui/issues/issue-6738.stderr delete mode 100644 tests/ui/issues/issue-6898.rs delete mode 100644 tests/ui/issues/issue-6919.rs delete mode 100644 tests/ui/issues/issue-6936.rs delete mode 100644 tests/ui/issues/issue-6936.stderr delete mode 100644 tests/ui/issues/issue-7012.rs create mode 100644 tests/ui/loops/unreachable-while-loop-5741.rs create mode 100644 tests/ui/macros/macro-variable-declaration-with-bounds-5554.rs create mode 100644 tests/ui/macros/macro-variable-unused-reporting-5718.rs create mode 100644 tests/ui/match/mismatched-types-in-match-5358.rs create mode 100644 tests/ui/match/mismatched-types-in-match-5358.stderr create mode 100644 tests/ui/modules/pub-use-module-alias-5950.rs create mode 100644 tests/ui/numeric/type-limit-comparisons-6130.rs create mode 100644 tests/ui/parser/partial-eq-trait-bound-5572.rs create mode 100644 tests/ui/privacy/auxiliary/iss-6919.rs create mode 100644 tests/ui/privacy/deref-separate-compile-unit-6919.rs create mode 100644 tests/ui/resolve/duplicate-name-in-module-6936.rs create mode 100644 tests/ui/resolve/duplicate-name-in-module-6936.stderr create mode 100644 tests/ui/static/static-list-initialization-5917.rs create mode 100644 tests/ui/static/static-struct-initialization-5688.rs create mode 100644 tests/ui/structs/destructuring-struct-with-dtor-6344.rs create mode 100644 tests/ui/structs/nonexistent-struct-field-error-5439.rs create mode 100644 tests/ui/structs/nonexistent-struct-field-error-5439.stderr create mode 100644 tests/ui/traits/dynamic-dispatch-trait-objects-5666.rs create mode 100644 tests/ui/traits/opaque-trait-size-error-5883.rs create mode 100644 tests/ui/traits/opaque-trait-size-error-5883.stderr create mode 100644 tests/ui/traits/trait-implementation-generic-access-6898.rs create mode 100644 tests/ui/traits/trait-implementation-restriction-5988.rs create mode 100644 tests/ui/unsafe/auxiliary/aux-5844.rs create mode 100644 tests/ui/unsafe/extern-function-requires-unsafe-5844.rs create mode 100644 tests/ui/unsafe/extern-function-requires-unsafe-5844.stderr diff --git a/tests/ui/binop/struct-field-generic-type-binary-assignment-error-6738.rs b/tests/ui/binop/struct-field-generic-type-binary-assignment-error-6738.rs new file mode 100644 index 00000000000..856caa2b297 --- /dev/null +++ b/tests/ui/binop/struct-field-generic-type-binary-assignment-error-6738.rs @@ -0,0 +1,11 @@ +// https://github.com/rust-lang/rust/issues/6738 +struct Foo { + x: T, +} +impl Foo { + fn add(&mut self, v: Foo){ + self.x += v.x; + //~^ ERROR: binary assignment operation `+=` cannot be applied + } +} +fn main() {} diff --git a/tests/ui/binop/struct-field-generic-type-binary-assignment-error-6738.stderr b/tests/ui/binop/struct-field-generic-type-binary-assignment-error-6738.stderr new file mode 100644 index 00000000000..060d33079d3 --- /dev/null +++ b/tests/ui/binop/struct-field-generic-type-binary-assignment-error-6738.stderr @@ -0,0 +1,16 @@ +error[E0368]: binary assignment operation `+=` cannot be applied to type `T` + --> $DIR/struct-field-generic-type-binary-assignment-error-6738.rs:7:9 + | +LL | self.x += v.x; + | ------^^^^^^^ + | | + | cannot use `+=` on type `T` + | +help: consider restricting type parameter `T` with trait `AddAssign` + | +LL | impl Foo { + | +++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0368`. diff --git a/tests/ui/borrowck/auxiliary/aux-5518.rs b/tests/ui/borrowck/auxiliary/aux-5518.rs new file mode 100644 index 00000000000..bfe96552a5c --- /dev/null +++ b/tests/ui/borrowck/auxiliary/aux-5518.rs @@ -0,0 +1,4 @@ +trait A<'a, T> { + fn f(&mut self) -> &'a mut T; + fn p() -> T; +} diff --git a/tests/ui/borrowck/borrowed-pointer-in-struct-5884.rs b/tests/ui/borrowck/borrowed-pointer-in-struct-5884.rs new file mode 100644 index 00000000000..d2f17cf905d --- /dev/null +++ b/tests/ui/borrowck/borrowed-pointer-in-struct-5884.rs @@ -0,0 +1,18 @@ +// https://github.com/rust-lang/rust/issues/5884 +//@ build-pass +#![allow(dead_code)] + +pub struct Foo { + a: isize, +} + +struct Bar<'a> { + a: Box>, + b: &'a Foo, +} + +fn check(a: Box) { + let _ic = Bar{ b: &*a, a: Box::new(None) }; +} + +pub fn main(){} diff --git a/tests/ui/borrowck/incorrect-loan-error-on-local-update-5550.rs b/tests/ui/borrowck/incorrect-loan-error-on-local-update-5550.rs new file mode 100644 index 00000000000..2258d768657 --- /dev/null +++ b/tests/ui/borrowck/incorrect-loan-error-on-local-update-5550.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust/issues/5550 +//@ run-pass +#![allow(unused_assignments)] + +pub fn main() { + let s: String = "foobar".to_string(); + let mut t: &str = &s; + t = &t[0..3]; // for master: str::view(t, 0, 3) maybe +} diff --git a/tests/ui/borrowck/struct-with-reference-to-trait-5708.rs b/tests/ui/borrowck/struct-with-reference-to-trait-5708.rs new file mode 100644 index 00000000000..5157a3bf36b --- /dev/null +++ b/tests/ui/borrowck/struct-with-reference-to-trait-5708.rs @@ -0,0 +1,54 @@ +// https://github.com/rust-lang/rust/issues/5708 +//@ run-pass +#![allow(unused_variables)] +/* +# ICE when returning struct with reference to trait + +A function which takes a reference to a trait and returns a +struct with that reference results in an ICE. + +This does not occur with concrete types, only with references +to traits. +*/ + +// original +trait Inner { + fn print(&self); +} + +impl Inner for isize { + fn print(&self) { print!("Inner: {}\n", *self); } +} + +struct Outer<'a> { + inner: &'a (dyn Inner+'a) +} + +impl<'a> Outer<'a> { + fn new(inner: &dyn Inner) -> Outer<'_> { + Outer { + inner: inner + } + } +} + +pub fn main() { + let inner: isize = 5; + let outer = Outer::new(&inner as &dyn Inner); + outer.inner.print(); +} + +// minimal +pub trait MyTrait { + fn dummy(&self, t: T) -> T { panic!() } +} + +pub struct MyContainer<'a, T:'a> { + foos: Vec<&'a (dyn MyTrait+'a)> , +} + +impl<'a, T> MyContainer<'a, T> { + pub fn add (&mut self, foo: &'a dyn MyTrait) { + self.foos.push(foo); + } +} diff --git a/tests/ui/borrowck/trait-method-lifetime-substitution-5518.rs b/tests/ui/borrowck/trait-method-lifetime-substitution-5518.rs new file mode 100644 index 00000000000..f254030a011 --- /dev/null +++ b/tests/ui/borrowck/trait-method-lifetime-substitution-5518.rs @@ -0,0 +1,7 @@ +// https://github.com/rust-lang/rust/issues/5518 +//@ run-pass +//@ aux-build:aux-5518.rs + +extern crate aux_5518 as other; + +fn main() {} diff --git a/tests/ui/box/box-patterns-feature-usage-6557.rs b/tests/ui/box/box-patterns-feature-usage-6557.rs new file mode 100644 index 00000000000..e0d9b25c366 --- /dev/null +++ b/tests/ui/box/box-patterns-feature-usage-6557.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust/issues/6557 +//@ check-pass +#![allow(dead_code)] + +#![feature(box_patterns)] + +fn foo(box (_x, _y): Box<(isize, isize)>) {} + +pub fn main() {} diff --git a/tests/ui/cast/owned-struct-to-trait-cast-6318.rs b/tests/ui/cast/owned-struct-to-trait-cast-6318.rs new file mode 100644 index 00000000000..8cfc77c4274 --- /dev/null +++ b/tests/ui/cast/owned-struct-to-trait-cast-6318.rs @@ -0,0 +1,20 @@ +// https://github.com/rust-lang/rust/issues/6318 +//@ run-pass + +pub enum Thing { + A(Box) +} + +pub trait Foo { + fn dummy(&self) { } +} + +pub struct Struct; + +impl Foo for Struct {} + +pub fn main() { + match Thing::A(Box::new(Struct) as Box) { + Thing::A(_a) => 0, + }; +} diff --git a/tests/ui/closures/closure-mut-argument-6153.rs b/tests/ui/closures/closure-mut-argument-6153.rs new file mode 100644 index 00000000000..ac19c2bd15f --- /dev/null +++ b/tests/ui/closures/closure-mut-argument-6153.rs @@ -0,0 +1,13 @@ +// https://github.com/rust-lang/rust/issues/6153 +//@ run-pass + +fn swap(f: F) -> Vec where F: FnOnce(Vec) -> Vec { + let x = vec![1, 2, 3]; + f(x) +} + +pub fn main() { + let v = swap(|mut x| { x.push(4); x }); + let w = swap(|mut x| { x.push(4); x }); + assert_eq!(v, w); +} diff --git a/tests/ui/codegen/static-array-comparison-7012.rs b/tests/ui/codegen/static-array-comparison-7012.rs new file mode 100644 index 00000000000..c08b1c0059b --- /dev/null +++ b/tests/ui/codegen/static-array-comparison-7012.rs @@ -0,0 +1,23 @@ +// https://github.com/rust-lang/rust/issues/7012 +//@ run-pass +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] + +/* +# Comparison of static arrays + +The expected behaviour would be that `test == test1`, therefore 'true' +would be printed, however the below prints false. +*/ + +struct signature<'a> { pattern : &'a [u32] } + +static test1: signature<'static> = signature { + pattern: &[0x243f6a88,0x85a308d3,0x13198a2e,0x03707344,0xa4093822,0x299f31d0] +}; + +pub fn main() { + let test: &[u32] = &[0x243f6a88,0x85a308d3,0x13198a2e, + 0x03707344,0xa4093822,0x299f31d0]; + println!("{}",test==test1.pattern); +} diff --git a/tests/ui/enum/enum-referred-by-submodule-5900.rs b/tests/ui/enum/enum-referred-by-submodule-5900.rs new file mode 100644 index 00000000000..4ed092670a8 --- /dev/null +++ b/tests/ui/enum/enum-referred-by-submodule-5900.rs @@ -0,0 +1,15 @@ +// https://github.com/rust-lang/rust/issues/5900 +//@ check-pass +#![allow(dead_code)] + +pub mod foo { + use super::Bar; + + pub struct FooStruct { bar : Bar } +} + +pub enum Bar { + Bar0 = 0 as isize +} + +pub fn main() {} diff --git a/tests/ui/enum/enum-with-generic-parameter-5997.rs b/tests/ui/enum/enum-with-generic-parameter-5997.rs new file mode 100644 index 00000000000..fab7ebbbbdc --- /dev/null +++ b/tests/ui/enum/enum-with-generic-parameter-5997.rs @@ -0,0 +1,16 @@ +// https://github.com/rust-lang/rust/issues/5997 +//@ run-pass +#![allow(dead_code)] + +fn f() -> bool { + enum E { V(T) } + + struct S(T); + + true +} + +fn main() { + let b = f::(); + assert!(b); +} diff --git a/tests/ui/enum/match-either-enum-variants-6117.rs b/tests/ui/enum/match-either-enum-variants-6117.rs new file mode 100644 index 00000000000..7b395066166 --- /dev/null +++ b/tests/ui/enum/match-either-enum-variants-6117.rs @@ -0,0 +1,12 @@ +// https://github.com/rust-lang/rust/issues/6117 +//@ run-pass +#![allow(dead_code)] + +enum Either { Left(T), Right(U) } + +pub fn main() { + match Either::Left(Box::new(17)) { + Either::Right(()) => {} + _ => {} + } +} diff --git a/tests/ui/generics/enum-definition-with-outer-generic-parameter-5997.rs b/tests/ui/generics/enum-definition-with-outer-generic-parameter-5997.rs new file mode 100644 index 00000000000..00bf66dd4e0 --- /dev/null +++ b/tests/ui/generics/enum-definition-with-outer-generic-parameter-5997.rs @@ -0,0 +1,11 @@ +// https://github.com/rust-lang/rust/issues/5997 +fn f() -> bool { + enum E { V(Z) } + //~^ ERROR can't use generic parameters from outer item + true +} + +fn main() { + let b = f::(); + assert!(b); +} diff --git a/tests/ui/generics/enum-definition-with-outer-generic-parameter-5997.stderr b/tests/ui/generics/enum-definition-with-outer-generic-parameter-5997.stderr new file mode 100644 index 00000000000..aea0f049b07 --- /dev/null +++ b/tests/ui/generics/enum-definition-with-outer-generic-parameter-5997.stderr @@ -0,0 +1,13 @@ +error[E0401]: can't use generic parameters from outer item + --> $DIR/enum-definition-with-outer-generic-parameter-5997.rs:3:16 + | +LL | fn f() -> bool { + | - type parameter from outer item +LL | enum E { V(Z) } + | - ^ use of generic parameter from outer item + | | + | help: try introducing a local generic parameter here: `` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0401`. diff --git a/tests/ui/issues/auxiliary/iss.rs b/tests/ui/issues/auxiliary/iss.rs deleted file mode 100644 index cf32f6c2d5d..00000000000 --- a/tests/ui/issues/auxiliary/iss.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![crate_name="issue6919_3"] - -// part of issue-6919.rs - -pub struct C where K: FnOnce() { - pub k: K, -} - -fn no_op() { } -pub const D : C = C { - k: no_op as fn() -}; diff --git a/tests/ui/issues/auxiliary/issue-5518.rs b/tests/ui/issues/auxiliary/issue-5518.rs deleted file mode 100644 index bfe96552a5c..00000000000 --- a/tests/ui/issues/auxiliary/issue-5518.rs +++ /dev/null @@ -1,4 +0,0 @@ -trait A<'a, T> { - fn f(&mut self) -> &'a mut T; - fn p() -> T; -} diff --git a/tests/ui/issues/auxiliary/issue-5844-aux.rs b/tests/ui/issues/auxiliary/issue-5844-aux.rs deleted file mode 100644 index ea83378cad6..00000000000 --- a/tests/ui/issues/auxiliary/issue-5844-aux.rs +++ /dev/null @@ -1,3 +0,0 @@ -extern "C" { - pub fn rand() -> u32; -} diff --git a/tests/ui/issues/issue-5358-1.rs b/tests/ui/issues/issue-5358-1.rs deleted file mode 100644 index 281f219c039..00000000000 --- a/tests/ui/issues/issue-5358-1.rs +++ /dev/null @@ -1,13 +0,0 @@ -enum Either { Left(T), Right(U) } -struct S(Either); - -fn main() { - match S(Either::Left(5)) { //~ NOTE this expression has type `S` - Either::Right(_) => {} - //~^ ERROR mismatched types - //~| NOTE expected `S`, found `Either<_, _>` - //~| NOTE expected struct `S` - //~| NOTE found enum `Either<_, _>` - _ => {} - } -} diff --git a/tests/ui/issues/issue-5358-1.stderr b/tests/ui/issues/issue-5358-1.stderr deleted file mode 100644 index e68db865dc4..00000000000 --- a/tests/ui/issues/issue-5358-1.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-5358-1.rs:6:9 - | -LL | match S(Either::Left(5)) { - | ------------------ this expression has type `S` -LL | Either::Right(_) => {} - | ^^^^^^^^^^^^^^^^ expected `S`, found `Either<_, _>` - | - = note: expected struct `S` - found enum `Either<_, _>` -help: try wrapping the pattern in `S` - | -LL | S(Either::Right(_)) => {} - | ++ + -help: you might have meant to use field `0` whose type is `Either` - | -LL | match S(Either::Left(5)).0 { - | ++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/issues/issue-5439.rs b/tests/ui/issues/issue-5439.rs deleted file mode 100644 index 852b264dc5d..00000000000 --- a/tests/ui/issues/issue-5439.rs +++ /dev/null @@ -1,19 +0,0 @@ -struct Foo { - foo: isize, -} - -struct Bar { - bar: isize, -} - -impl Bar { - fn make_foo (&self, i: isize) -> Box { - return Box::new(Foo { nonexistent: self, foo: i }); //~ ERROR: no field named - } -} - -fn main () { - let bar = Bar { bar: 1 }; - let foo = bar.make_foo(2); - println!("{}", foo.foo); -} diff --git a/tests/ui/issues/issue-5439.stderr b/tests/ui/issues/issue-5439.stderr deleted file mode 100644 index 6d1d74e3045..00000000000 --- a/tests/ui/issues/issue-5439.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0560]: struct `Foo` has no field named `nonexistent` - --> $DIR/issue-5439.rs:11:31 - | -LL | return Box::new(Foo { nonexistent: self, foo: i }); - | ^^^^^^^^^^^ `Foo` does not have this field - | - = note: all struct fields are already assigned - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0560`. diff --git a/tests/ui/issues/issue-5518.rs b/tests/ui/issues/issue-5518.rs deleted file mode 100644 index 333185c482f..00000000000 --- a/tests/ui/issues/issue-5518.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass -//@ aux-build:issue-5518.rs - - -extern crate issue_5518 as other; - -fn main() {} diff --git a/tests/ui/issues/issue-5550.rs b/tests/ui/issues/issue-5550.rs deleted file mode 100644 index 41de8ee5d32..00000000000 --- a/tests/ui/issues/issue-5550.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass -#![allow(unused_assignments)] - -pub fn main() { - let s: String = "foobar".to_string(); - let mut t: &str = &s; - t = &t[0..3]; // for master: str::view(t, 0, 3) maybe -} diff --git a/tests/ui/issues/issue-5554.rs b/tests/ui/issues/issue-5554.rs deleted file mode 100644 index 7d219a0df70..00000000000 --- a/tests/ui/issues/issue-5554.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - - -pub struct X { - a: T, -} - -// reordering these bounds stops the ICE -// -// nmatsakis: This test used to have the bounds Default + PartialEq + -// Default, but having duplicate bounds became illegal. -impl Default for X { - fn default() -> X { - X { a: Default::default() } - } -} - -macro_rules! constants { - () => { - let _ : X = Default::default(); - } -} - -pub fn main() { - constants!(); -} diff --git a/tests/ui/issues/issue-5572.rs b/tests/ui/issues/issue-5572.rs deleted file mode 100644 index f27744ef0ac..00000000000 --- a/tests/ui/issues/issue-5572.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ check-pass -#![allow(dead_code)] - -fn foo(_t: T) { } - -pub fn main() { } diff --git a/tests/ui/issues/issue-5666.rs b/tests/ui/issues/issue-5666.rs deleted file mode 100644 index 76e2f8229a0..00000000000 --- a/tests/ui/issues/issue-5666.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ run-pass - -struct Dog { - name : String -} - -trait Barks { - fn bark(&self) -> String; -} - -impl Barks for Dog { - fn bark(&self) -> String { - return format!("woof! (I'm {})", self.name); - } -} - - -pub fn main() { - let snoopy = Box::new(Dog{name: "snoopy".to_string()}); - let bubbles = Box::new(Dog{name: "bubbles".to_string()}); - let barker = [snoopy as Box, bubbles as Box]; - - for pup in &barker { - println!("{}", pup.bark()); - } -} diff --git a/tests/ui/issues/issue-5688.rs b/tests/ui/issues/issue-5688.rs deleted file mode 100644 index a7db1dfb15f..00000000000 --- a/tests/ui/issues/issue-5688.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ run-pass -/* -# Corrupted initialization in the static struct - -...should print &[1, 2, 3] but instead prints something like -&[4492532864, 24]. It is pretty evident that the compiler messed up -with the representation of [isize; n] and [isize] somehow, or at least -failed to typecheck correctly. -*/ - -#[derive(Copy, Clone)] -struct X { vec: &'static [isize] } - -static V: &'static [X] = &[X { vec: &[1, 2, 3] }]; - -pub fn main() { - for &v in V { - println!("{:?}", v.vec); - } -} diff --git a/tests/ui/issues/issue-5708.rs b/tests/ui/issues/issue-5708.rs deleted file mode 100644 index 6fa3cfa4724..00000000000 --- a/tests/ui/issues/issue-5708.rs +++ /dev/null @@ -1,55 +0,0 @@ -//@ run-pass -#![allow(unused_variables)] -/* -# ICE when returning struct with reference to trait - -A function which takes a reference to a trait and returns a -struct with that reference results in an ICE. - -This does not occur with concrete types, only with references -to traits. -*/ - - -// original -trait Inner { - fn print(&self); -} - -impl Inner for isize { - fn print(&self) { print!("Inner: {}\n", *self); } -} - -struct Outer<'a> { - inner: &'a (dyn Inner+'a) -} - -impl<'a> Outer<'a> { - fn new(inner: &dyn Inner) -> Outer<'_> { - Outer { - inner: inner - } - } -} - -pub fn main() { - let inner: isize = 5; - let outer = Outer::new(&inner as &dyn Inner); - outer.inner.print(); -} - - -// minimal -pub trait MyTrait { - fn dummy(&self, t: T) -> T { panic!() } -} - -pub struct MyContainer<'a, T:'a> { - foos: Vec<&'a (dyn MyTrait+'a)> , -} - -impl<'a, T> MyContainer<'a, T> { - pub fn add (&mut self, foo: &'a dyn MyTrait) { - self.foos.push(foo); - } -} diff --git a/tests/ui/issues/issue-5718.rs b/tests/ui/issues/issue-5718.rs deleted file mode 100644 index 234fb2e2222..00000000000 --- a/tests/ui/issues/issue-5718.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ run-pass - -struct Element; - -macro_rules! foo { - ($tag: expr, $string: expr) => { - if $tag == $string { - let element: Box<_> = Box::new(Element); - unsafe { - return std::mem::transmute::<_, usize>(element); - } - } - } -} - -fn bar() -> usize { - foo!("a", "b"); - 0 -} - -fn main() { - bar(); -} diff --git a/tests/ui/issues/issue-5741.rs b/tests/ui/issues/issue-5741.rs deleted file mode 100644 index af4702ec22c..00000000000 --- a/tests/ui/issues/issue-5741.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass -#![allow(while_true)] -#![allow(unreachable_code)] - -pub fn main() { - return; - while true {}; -} diff --git a/tests/ui/issues/issue-5844.rs b/tests/ui/issues/issue-5844.rs deleted file mode 100644 index 23021207ae1..00000000000 --- a/tests/ui/issues/issue-5844.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@aux-build:issue-5844-aux.rs - -extern crate issue_5844_aux; - -fn main() { - issue_5844_aux::rand(); //~ ERROR: requires unsafe -} diff --git a/tests/ui/issues/issue-5844.stderr b/tests/ui/issues/issue-5844.stderr deleted file mode 100644 index bae917fa72c..00000000000 --- a/tests/ui/issues/issue-5844.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0133]: call to unsafe function `rand` is unsafe and requires unsafe function or block - --> $DIR/issue-5844.rs:6:5 - | -LL | issue_5844_aux::rand(); - | ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/issues/issue-5883.rs b/tests/ui/issues/issue-5883.rs deleted file mode 100644 index dd4753e0344..00000000000 --- a/tests/ui/issues/issue-5883.rs +++ /dev/null @@ -1,13 +0,0 @@ -trait A {} - -struct Struct { - r: dyn A + 'static -} - -fn new_struct( - r: dyn A + 'static //~ ERROR the size for values of type -) -> Struct { //~ ERROR the size for values of type - Struct { r: r } -} - -fn main() {} diff --git a/tests/ui/issues/issue-5883.stderr b/tests/ui/issues/issue-5883.stderr deleted file mode 100644 index 2ca437b8c47..00000000000 --- a/tests/ui/issues/issue-5883.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time - --> $DIR/issue-5883.rs:9:6 - | -LL | ) -> Struct { - | ^^^^^^ doesn't have a size known at compile-time - | - = help: within `Struct`, the trait `Sized` is not implemented for `(dyn A + 'static)` -note: required because it appears within the type `Struct` - --> $DIR/issue-5883.rs:3:8 - | -LL | struct Struct { - | ^^^^^^ - = note: the return type of a function must have a statically known size - -error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time - --> $DIR/issue-5883.rs:8:8 - | -LL | r: dyn A + 'static - | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `(dyn A + 'static)` - = help: unsized fn params are gated as an unstable feature -help: you can use `impl Trait` as the argument type - | -LL - r: dyn A + 'static -LL + r: impl A + 'static - | -help: function arguments must have a statically known size, borrowed types always have a known size - | -LL | r: &dyn A + 'static - | + - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/issues/issue-5884.rs b/tests/ui/issues/issue-5884.rs deleted file mode 100644 index 559b897395d..00000000000 --- a/tests/ui/issues/issue-5884.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ build-pass -#![allow(dead_code)] - -pub struct Foo { - a: isize, -} - -struct Bar<'a> { - a: Box>, - b: &'a Foo, -} - -fn check(a: Box) { - let _ic = Bar{ b: &*a, a: Box::new(None) }; -} - -pub fn main(){} diff --git a/tests/ui/issues/issue-5900.rs b/tests/ui/issues/issue-5900.rs deleted file mode 100644 index 14b7b8f815a..00000000000 --- a/tests/ui/issues/issue-5900.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ check-pass -#![allow(dead_code)] - -pub mod foo { - use super::Bar; - - pub struct FooStruct { bar : Bar } -} - -pub enum Bar { - Bar0 = 0 as isize -} - -pub fn main() {} diff --git a/tests/ui/issues/issue-5917.rs b/tests/ui/issues/issue-5917.rs deleted file mode 100644 index 8e91b1052a2..00000000000 --- a/tests/ui/issues/issue-5917.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass -#![allow(non_upper_case_globals)] - -struct T (&'static [isize]); -static t : T = T (&[5, 4, 3]); -pub fn main () { - let T(ref v) = t; - assert_eq!(v[0], 5); -} diff --git a/tests/ui/issues/issue-5950.rs b/tests/ui/issues/issue-5950.rs deleted file mode 100644 index 6015560fcf8..00000000000 --- a/tests/ui/issues/issue-5950.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ check-pass - - -pub use local as local_alias; - -pub mod local { } - -pub fn main() {} diff --git a/tests/ui/issues/issue-5988.rs b/tests/ui/issues/issue-5988.rs deleted file mode 100644 index b7527d9bea8..00000000000 --- a/tests/ui/issues/issue-5988.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ run-pass - -trait B { - fn f(&self); -} - -trait T : B { -} - -struct A; - -impl B for U { - fn f(&self) { } -} - -impl T for A { -} - -fn main() { - let a = A; - let br = &a as &dyn B; - br.f(); -} diff --git a/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.rs b/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.rs deleted file mode 100644 index 0b1857ae3df..00000000000 --- a/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.rs +++ /dev/null @@ -1,10 +0,0 @@ -fn f() -> bool { - enum E { V(Z) } - //~^ ERROR can't use generic parameters from outer item - true -} - -fn main() { - let b = f::(); - assert!(b); -} diff --git a/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.stderr b/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.stderr deleted file mode 100644 index c0b3cd6de66..00000000000 --- a/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0401]: can't use generic parameters from outer item - --> $DIR/issue-5997-enum.rs:2:16 - | -LL | fn f() -> bool { - | - type parameter from outer item -LL | enum E { V(Z) } - | - ^ use of generic parameter from outer item - | | - | help: try introducing a local generic parameter here: `` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0401`. diff --git a/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.rs b/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.rs deleted file mode 100644 index 19d994b0dfb..00000000000 --- a/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.rs +++ /dev/null @@ -1,10 +0,0 @@ -fn f() -> bool { - struct S(T); //~ ERROR can't use generic parameters from outer item - - true -} - -fn main() { - let b = f::(); - assert!(b); -} diff --git a/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.stderr b/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.stderr deleted file mode 100644 index 670a54894b5..00000000000 --- a/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0401]: can't use generic parameters from outer item - --> $DIR/issue-5997-struct.rs:2:14 - | -LL | fn f() -> bool { - | - type parameter from outer item -LL | struct S(T); - | -^ use of generic parameter from outer item - | | - | help: try introducing a local generic parameter here: `` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0401`. diff --git a/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997.rs b/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997.rs deleted file mode 100644 index 7ed8819f322..00000000000 --- a/tests/ui/issues/issue-5997-outer-generic-parameter/issue-5997.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -fn f() -> bool { - enum E { V(T) } - - struct S(T); - - true -} - -fn main() { - let b = f::(); - assert!(b); -} diff --git a/tests/ui/issues/issue-6117.rs b/tests/ui/issues/issue-6117.rs deleted file mode 100644 index 3ccf67b0319..00000000000 --- a/tests/ui/issues/issue-6117.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -enum Either { Left(T), Right(U) } - -pub fn main() { - match Either::Left(Box::new(17)) { - Either::Right(()) => {} - _ => {} - } -} diff --git a/tests/ui/issues/issue-6130.rs b/tests/ui/issues/issue-6130.rs deleted file mode 100644 index c675a8a41dd..00000000000 --- a/tests/ui/issues/issue-6130.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass - -pub fn main() { - let i: usize = 0; - assert!(i <= 0xFFFF_FFFF); - - let i: isize = 0; - assert!(i >= -0x8000_0000); - assert!(i <= 0x7FFF_FFFF); -} diff --git a/tests/ui/issues/issue-6153.rs b/tests/ui/issues/issue-6153.rs deleted file mode 100644 index cd78c85d94b..00000000000 --- a/tests/ui/issues/issue-6153.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass - - -fn swap(f: F) -> Vec where F: FnOnce(Vec) -> Vec { - let x = vec![1, 2, 3]; - f(x) -} - -pub fn main() { - let v = swap(|mut x| { x.push(4); x }); - let w = swap(|mut x| { x.push(4); x }); - assert_eq!(v, w); -} diff --git a/tests/ui/issues/issue-6318.rs b/tests/ui/issues/issue-6318.rs deleted file mode 100644 index d3f08285a93..00000000000 --- a/tests/ui/issues/issue-6318.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ run-pass - -pub enum Thing { - A(Box) -} - -pub trait Foo { - fn dummy(&self) { } -} - -pub struct Struct; - -impl Foo for Struct {} - -pub fn main() { - match Thing::A(Box::new(Struct) as Box) { - Thing::A(_a) => 0, - }; -} diff --git a/tests/ui/issues/issue-6344-let.rs b/tests/ui/issues/issue-6344-let.rs deleted file mode 100644 index 1e1bdfa17be..00000000000 --- a/tests/ui/issues/issue-6344-let.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-pass -#![allow(non_shorthand_field_patterns)] - -struct A { x: usize } - -impl Drop for A { - fn drop(&mut self) {} -} - -pub fn main() { - let a = A { x: 0 }; - - let A { x: ref x } = a; - println!("{}", x) -} diff --git a/tests/ui/issues/issue-6344-match.rs b/tests/ui/issues/issue-6344-match.rs deleted file mode 100644 index 9251e274383..00000000000 --- a/tests/ui/issues/issue-6344-match.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ run-pass -#![allow(non_shorthand_field_patterns)] - -struct A { x: usize } - -impl Drop for A { - fn drop(&mut self) {} -} - -pub fn main() { - let a = A { x: 0 }; - - match a { - A { x : ref x } => { - println!("{}", x) - } - } -} diff --git a/tests/ui/issues/issue-6557.rs b/tests/ui/issues/issue-6557.rs deleted file mode 100644 index 64a025a294f..00000000000 --- a/tests/ui/issues/issue-6557.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ check-pass -#![allow(dead_code)] - -#![feature(box_patterns)] - -fn foo(box (_x, _y): Box<(isize, isize)>) {} - -pub fn main() {} diff --git a/tests/ui/issues/issue-6738.rs b/tests/ui/issues/issue-6738.rs deleted file mode 100644 index a2f8dfe9c49..00000000000 --- a/tests/ui/issues/issue-6738.rs +++ /dev/null @@ -1,10 +0,0 @@ -struct Foo { - x: T, -} -impl Foo { - fn add(&mut self, v: Foo){ - self.x += v.x; - //~^ ERROR: binary assignment operation `+=` cannot be applied - } -} -fn main() {} diff --git a/tests/ui/issues/issue-6738.stderr b/tests/ui/issues/issue-6738.stderr deleted file mode 100644 index f22d6a2e468..00000000000 --- a/tests/ui/issues/issue-6738.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0368]: binary assignment operation `+=` cannot be applied to type `T` - --> $DIR/issue-6738.rs:6:9 - | -LL | self.x += v.x; - | ------^^^^^^^ - | | - | cannot use `+=` on type `T` - | -help: consider restricting type parameter `T` with trait `AddAssign` - | -LL | impl Foo { - | +++++++++++++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0368`. diff --git a/tests/ui/issues/issue-6898.rs b/tests/ui/issues/issue-6898.rs deleted file mode 100644 index c810acaf61b..00000000000 --- a/tests/ui/issues/issue-6898.rs +++ /dev/null @@ -1,32 +0,0 @@ -//@ check-pass - -use std::mem; - -/// Returns the size of a type -pub fn size_of() -> usize { - TypeInfo::size_of(None::) -} - -/// Returns the size of the type that `val` points to -pub fn size_of_val(val: &T) -> usize { - val.size_of_val() -} - -pub trait TypeInfo: Sized { - fn size_of(_lame_type_hint: Option) -> usize; - fn size_of_val(&self) -> usize; -} - -impl TypeInfo for T { - /// The size of the type in bytes. - fn size_of(_lame_type_hint: Option) -> usize { - mem::size_of::() - } - - /// Returns the size of the type of `self` in bytes. - fn size_of_val(&self) -> usize { - TypeInfo::size_of(None::) - } -} - -pub fn main() {} diff --git a/tests/ui/issues/issue-6919.rs b/tests/ui/issues/issue-6919.rs deleted file mode 100644 index 7fb8a2f33bc..00000000000 --- a/tests/ui/issues/issue-6919.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -#![allow(unused_attributes)] -//@ aux-build:iss.rs - - -extern crate issue6919_3; - -pub fn main() { - let _ = issue6919_3::D.k; -} diff --git a/tests/ui/issues/issue-6936.rs b/tests/ui/issues/issue-6936.rs deleted file mode 100644 index e9aa80b4eb3..00000000000 --- a/tests/ui/issues/issue-6936.rs +++ /dev/null @@ -1,34 +0,0 @@ -struct T; - -mod t1 { - type Foo = crate::T; - mod Foo {} //~ ERROR the name `Foo` is defined multiple times -} - -mod t2 { - type Foo = crate::T; - struct Foo; //~ ERROR the name `Foo` is defined multiple times -} - -mod t3 { - type Foo = crate::T; - enum Foo {} //~ ERROR the name `Foo` is defined multiple times -} - -mod t4 { - type Foo = crate::T; - fn Foo() {} // ok -} - -mod t5 { - type Bar = T; - mod Bar {} //~ ERROR the name `Bar` is defined multiple times -} - -mod t6 { - type Foo = crate::T; - impl Foo {} // ok -} - - -fn main() {} diff --git a/tests/ui/issues/issue-6936.stderr b/tests/ui/issues/issue-6936.stderr deleted file mode 100644 index 03cc50636b4..00000000000 --- a/tests/ui/issues/issue-6936.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0428]: the name `Foo` is defined multiple times - --> $DIR/issue-6936.rs:5:5 - | -LL | type Foo = crate::T; - | -------------------- previous definition of the type `Foo` here -LL | mod Foo {} - | ^^^^^^^ `Foo` redefined here - | - = note: `Foo` must be defined only once in the type namespace of this module - -error[E0428]: the name `Foo` is defined multiple times - --> $DIR/issue-6936.rs:10:5 - | -LL | type Foo = crate::T; - | -------------------- previous definition of the type `Foo` here -LL | struct Foo; - | ^^^^^^^^^^^ `Foo` redefined here - | - = note: `Foo` must be defined only once in the type namespace of this module - -error[E0428]: the name `Foo` is defined multiple times - --> $DIR/issue-6936.rs:15:5 - | -LL | type Foo = crate::T; - | -------------------- previous definition of the type `Foo` here -LL | enum Foo {} - | ^^^^^^^^ `Foo` redefined here - | - = note: `Foo` must be defined only once in the type namespace of this module - -error[E0428]: the name `Bar` is defined multiple times - --> $DIR/issue-6936.rs:25:5 - | -LL | type Bar = T; - | ---------------- previous definition of the type `Bar` here -LL | mod Bar {} - | ^^^^^^^ `Bar` redefined here - | - = note: `Bar` must be defined only once in the type namespace of this module - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0428`. diff --git a/tests/ui/issues/issue-7012.rs b/tests/ui/issues/issue-7012.rs deleted file mode 100644 index 69b881e2a43..00000000000 --- a/tests/ui/issues/issue-7012.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] -#![allow(non_upper_case_globals)] - -/* -# Comparison of static arrays - -The expected behaviour would be that `test == test1`, therefore 'true' -would be printed, however the below prints false. -*/ - -struct signature<'a> { pattern : &'a [u32] } - -static test1: signature<'static> = signature { - pattern: &[0x243f6a88,0x85a308d3,0x13198a2e,0x03707344,0xa4093822,0x299f31d0] -}; - -pub fn main() { - let test: &[u32] = &[0x243f6a88,0x85a308d3,0x13198a2e, - 0x03707344,0xa4093822,0x299f31d0]; - println!("{}",test==test1.pattern); -} diff --git a/tests/ui/loops/unreachable-while-loop-5741.rs b/tests/ui/loops/unreachable-while-loop-5741.rs new file mode 100644 index 00000000000..bc69df0f675 --- /dev/null +++ b/tests/ui/loops/unreachable-while-loop-5741.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust/issues/5741 +//@ run-pass +#![allow(while_true)] +#![allow(unreachable_code)] + +pub fn main() { + return; + while true {}; +} diff --git a/tests/ui/macros/macro-variable-declaration-with-bounds-5554.rs b/tests/ui/macros/macro-variable-declaration-with-bounds-5554.rs new file mode 100644 index 00000000000..8ccf8e80131 --- /dev/null +++ b/tests/ui/macros/macro-variable-declaration-with-bounds-5554.rs @@ -0,0 +1,27 @@ +// https://github.com/rust-lang/rust/issues/5554 +//@ run-pass +#![allow(dead_code)] + +pub struct X { + a: T, +} + +// reordering these bounds stops the ICE +// +// nmatsakis: This test used to have the bounds Default + PartialEq + +// Default, but having duplicate bounds became illegal. +impl Default for X { + fn default() -> X { + X { a: Default::default() } + } +} + +macro_rules! constants { + () => { + let _ : X = Default::default(); + } +} + +pub fn main() { + constants!(); +} diff --git a/tests/ui/macros/macro-variable-unused-reporting-5718.rs b/tests/ui/macros/macro-variable-unused-reporting-5718.rs new file mode 100644 index 00000000000..55da925461d --- /dev/null +++ b/tests/ui/macros/macro-variable-unused-reporting-5718.rs @@ -0,0 +1,24 @@ +// https://github.com/rust-lang/rust/issues/5718 +//@ run-pass + +struct Element; + +macro_rules! foo { + ($tag: expr, $string: expr) => { + if $tag == $string { + let element: Box<_> = Box::new(Element); + unsafe { + return std::mem::transmute::<_, usize>(element); + } + } + } +} + +fn bar() -> usize { + foo!("a", "b"); + 0 +} + +fn main() { + bar(); +} diff --git a/tests/ui/match/mismatched-types-in-match-5358.rs b/tests/ui/match/mismatched-types-in-match-5358.rs new file mode 100644 index 00000000000..d096bf3a493 --- /dev/null +++ b/tests/ui/match/mismatched-types-in-match-5358.rs @@ -0,0 +1,18 @@ +// https://github.com/rust-lang/rust/issues/5358 +enum Either { + Left(T), + Right(U), +} +struct S(Either); + +fn main() { + match S(Either::Left(5)) { + //~^ NOTE this expression has type `S` + Either::Right(_) => {} + //~^ ERROR mismatched types + //~| NOTE expected `S`, found `Either<_, _>` + //~| NOTE expected struct `S` + //~| NOTE found enum `Either<_, _>` + _ => {} + } +} diff --git a/tests/ui/match/mismatched-types-in-match-5358.stderr b/tests/ui/match/mismatched-types-in-match-5358.stderr new file mode 100644 index 00000000000..6a6cf3ee269 --- /dev/null +++ b/tests/ui/match/mismatched-types-in-match-5358.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/mismatched-types-in-match-5358.rs:11:9 + | +LL | match S(Either::Left(5)) { + | ------------------ this expression has type `S` +LL | +LL | Either::Right(_) => {} + | ^^^^^^^^^^^^^^^^ expected `S`, found `Either<_, _>` + | + = note: expected struct `S` + found enum `Either<_, _>` +help: try wrapping the pattern in `S` + | +LL | S(Either::Right(_)) => {} + | ++ + +help: you might have meant to use field `0` whose type is `Either` + | +LL | match S(Either::Left(5)).0 { + | ++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/modules/pub-use-module-alias-5950.rs b/tests/ui/modules/pub-use-module-alias-5950.rs new file mode 100644 index 00000000000..91d3f9b16ff --- /dev/null +++ b/tests/ui/modules/pub-use-module-alias-5950.rs @@ -0,0 +1,8 @@ +// https://github.com/rust-lang/rust/issues/5950 +//@ check-pass + +pub use local as local_alias; + +pub mod local { } + +pub fn main() {} diff --git a/tests/ui/numeric/type-limit-comparisons-6130.rs b/tests/ui/numeric/type-limit-comparisons-6130.rs new file mode 100644 index 00000000000..54b3f631e67 --- /dev/null +++ b/tests/ui/numeric/type-limit-comparisons-6130.rs @@ -0,0 +1,11 @@ +// https://github.com/rust-lang/rust/issues/6130 +//@ run-pass + +pub fn main() { + let i: usize = 0; + assert!(i <= 0xFFFF_FFFF); + + let i: isize = 0; + assert!(i >= -0x8000_0000); + assert!(i <= 0x7FFF_FFFF); +} diff --git a/tests/ui/parser/partial-eq-trait-bound-5572.rs b/tests/ui/parser/partial-eq-trait-bound-5572.rs new file mode 100644 index 00000000000..7ee0cdc43ee --- /dev/null +++ b/tests/ui/parser/partial-eq-trait-bound-5572.rs @@ -0,0 +1,7 @@ +// https://github.com/rust-lang/rust/issues/5572 +//@ check-pass +#![allow(dead_code)] + +fn foo(_t: T) { } + +pub fn main() { } diff --git a/tests/ui/privacy/auxiliary/iss-6919.rs b/tests/ui/privacy/auxiliary/iss-6919.rs new file mode 100644 index 00000000000..cf32f6c2d5d --- /dev/null +++ b/tests/ui/privacy/auxiliary/iss-6919.rs @@ -0,0 +1,12 @@ +#![crate_name="issue6919_3"] + +// part of issue-6919.rs + +pub struct C where K: FnOnce() { + pub k: K, +} + +fn no_op() { } +pub const D : C = C { + k: no_op as fn() +}; diff --git a/tests/ui/privacy/deref-separate-compile-unit-6919.rs b/tests/ui/privacy/deref-separate-compile-unit-6919.rs new file mode 100644 index 00000000000..5d8934987e5 --- /dev/null +++ b/tests/ui/privacy/deref-separate-compile-unit-6919.rs @@ -0,0 +1,10 @@ +// https://github.com/rust-lang/rust/issues/6919 +//@ run-pass +#![allow(unused_attributes)] +//@ aux-build:iss-6919.rs + +extern crate issue6919_3; + +pub fn main() { + let _ = issue6919_3::D.k; +} diff --git a/tests/ui/resolve/duplicate-name-in-module-6936.rs b/tests/ui/resolve/duplicate-name-in-module-6936.rs new file mode 100644 index 00000000000..ae9282c0c24 --- /dev/null +++ b/tests/ui/resolve/duplicate-name-in-module-6936.rs @@ -0,0 +1,34 @@ +// https://github.com/rust-lang/rust/issues/6936 +struct T; + +mod t1 { + type Foo = crate::T; + mod Foo {} //~ ERROR the name `Foo` is defined multiple times +} + +mod t2 { + type Foo = crate::T; + struct Foo; //~ ERROR the name `Foo` is defined multiple times +} + +mod t3 { + type Foo = crate::T; + enum Foo {} //~ ERROR the name `Foo` is defined multiple times +} + +mod t4 { + type Foo = crate::T; + fn Foo() {} // ok +} + +mod t5 { + type Bar = T; + mod Bar {} //~ ERROR the name `Bar` is defined multiple times +} + +mod t6 { + type Foo = crate::T; + impl Foo {} // ok +} + +fn main() {} diff --git a/tests/ui/resolve/duplicate-name-in-module-6936.stderr b/tests/ui/resolve/duplicate-name-in-module-6936.stderr new file mode 100644 index 00000000000..76bb8f57386 --- /dev/null +++ b/tests/ui/resolve/duplicate-name-in-module-6936.stderr @@ -0,0 +1,43 @@ +error[E0428]: the name `Foo` is defined multiple times + --> $DIR/duplicate-name-in-module-6936.rs:6:5 + | +LL | type Foo = crate::T; + | -------------------- previous definition of the type `Foo` here +LL | mod Foo {} + | ^^^^^^^ `Foo` redefined here + | + = note: `Foo` must be defined only once in the type namespace of this module + +error[E0428]: the name `Foo` is defined multiple times + --> $DIR/duplicate-name-in-module-6936.rs:11:5 + | +LL | type Foo = crate::T; + | -------------------- previous definition of the type `Foo` here +LL | struct Foo; + | ^^^^^^^^^^^ `Foo` redefined here + | + = note: `Foo` must be defined only once in the type namespace of this module + +error[E0428]: the name `Foo` is defined multiple times + --> $DIR/duplicate-name-in-module-6936.rs:16:5 + | +LL | type Foo = crate::T; + | -------------------- previous definition of the type `Foo` here +LL | enum Foo {} + | ^^^^^^^^ `Foo` redefined here + | + = note: `Foo` must be defined only once in the type namespace of this module + +error[E0428]: the name `Bar` is defined multiple times + --> $DIR/duplicate-name-in-module-6936.rs:26:5 + | +LL | type Bar = T; + | ---------------- previous definition of the type `Bar` here +LL | mod Bar {} + | ^^^^^^^ `Bar` redefined here + | + = note: `Bar` must be defined only once in the type namespace of this module + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0428`. diff --git a/tests/ui/static/static-list-initialization-5917.rs b/tests/ui/static/static-list-initialization-5917.rs new file mode 100644 index 00000000000..c6c32f7582e --- /dev/null +++ b/tests/ui/static/static-list-initialization-5917.rs @@ -0,0 +1,10 @@ +// https://github.com/rust-lang/rust/issues/5917 +//@ run-pass +#![allow(non_upper_case_globals)] + +struct T (&'static [isize]); +static t : T = T (&[5, 4, 3]); +pub fn main () { + let T(ref v) = t; + assert_eq!(v[0], 5); +} diff --git a/tests/ui/static/static-struct-initialization-5688.rs b/tests/ui/static/static-struct-initialization-5688.rs new file mode 100644 index 00000000000..6a4c2f45b6b --- /dev/null +++ b/tests/ui/static/static-struct-initialization-5688.rs @@ -0,0 +1,21 @@ +// https://github.com/rust-lang/rust/issues/5688 +//@ run-pass +/* +# Corrupted initialization in the static struct + +...should print &[1, 2, 3] but instead prints something like +&[4492532864, 24]. It is pretty evident that the compiler messed up +with the representation of [isize; n] and [isize] somehow, or at least +failed to typecheck correctly. +*/ + +#[derive(Copy, Clone)] +struct X { vec: &'static [isize] } + +static V: &'static [X] = &[X { vec: &[1, 2, 3] }]; + +pub fn main() { + for &v in V { + println!("{:?}", v.vec); + } +} diff --git a/tests/ui/structs/destructuring-struct-with-dtor-6344.rs b/tests/ui/structs/destructuring-struct-with-dtor-6344.rs new file mode 100644 index 00000000000..b107a99e89f --- /dev/null +++ b/tests/ui/structs/destructuring-struct-with-dtor-6344.rs @@ -0,0 +1,16 @@ +// https://github.com/rust-lang/rust/issues/6344 +//@ run-pass +#![allow(non_shorthand_field_patterns)] + +struct A { x: usize } + +impl Drop for A { + fn drop(&mut self) {} +} + +pub fn main() { + let a = A { x: 0 }; + + let A { x: ref x } = a; + println!("{}", x) +} diff --git a/tests/ui/structs/nonexistent-struct-field-error-5439.rs b/tests/ui/structs/nonexistent-struct-field-error-5439.rs new file mode 100644 index 00000000000..b2b3293ac91 --- /dev/null +++ b/tests/ui/structs/nonexistent-struct-field-error-5439.rs @@ -0,0 +1,20 @@ +// https://github.com/rust-lang/rust/issues/5439 +struct Foo { + foo: isize, +} + +struct Bar { + bar: isize, +} + +impl Bar { + fn make_foo (&self, i: isize) -> Box { + return Box::new(Foo { nonexistent: self, foo: i }); //~ ERROR: no field named + } +} + +fn main () { + let bar = Bar { bar: 1 }; + let foo = bar.make_foo(2); + println!("{}", foo.foo); +} diff --git a/tests/ui/structs/nonexistent-struct-field-error-5439.stderr b/tests/ui/structs/nonexistent-struct-field-error-5439.stderr new file mode 100644 index 00000000000..b560772fbf0 --- /dev/null +++ b/tests/ui/structs/nonexistent-struct-field-error-5439.stderr @@ -0,0 +1,11 @@ +error[E0560]: struct `Foo` has no field named `nonexistent` + --> $DIR/nonexistent-struct-field-error-5439.rs:12:31 + | +LL | return Box::new(Foo { nonexistent: self, foo: i }); + | ^^^^^^^^^^^ `Foo` does not have this field + | + = note: all struct fields are already assigned + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0560`. diff --git a/tests/ui/traits/dynamic-dispatch-trait-objects-5666.rs b/tests/ui/traits/dynamic-dispatch-trait-objects-5666.rs new file mode 100644 index 00000000000..e335949d832 --- /dev/null +++ b/tests/ui/traits/dynamic-dispatch-trait-objects-5666.rs @@ -0,0 +1,26 @@ +// https://github.com/rust-lang/rust/issues/5666 +//@ run-pass + +struct Dog { + name : String +} + +trait Barks { + fn bark(&self) -> String; +} + +impl Barks for Dog { + fn bark(&self) -> String { + return format!("woof! (I'm {})", self.name); + } +} + +pub fn main() { + let snoopy = Box::new(Dog{name: "snoopy".to_string()}); + let bubbles = Box::new(Dog{name: "bubbles".to_string()}); + let barker = [snoopy as Box, bubbles as Box]; + + for pup in &barker { + println!("{}", pup.bark()); + } +} diff --git a/tests/ui/traits/opaque-trait-size-error-5883.rs b/tests/ui/traits/opaque-trait-size-error-5883.rs new file mode 100644 index 00000000000..e39e24e7342 --- /dev/null +++ b/tests/ui/traits/opaque-trait-size-error-5883.rs @@ -0,0 +1,14 @@ +// https://github.com/rust-lang/rust/issues/5883 +trait A {} + +struct Struct { + r: dyn A + 'static +} + +fn new_struct( + r: dyn A + 'static //~ ERROR the size for values of type +) -> Struct { //~ ERROR the size for values of type + Struct { r: r } +} + +fn main() {} diff --git a/tests/ui/traits/opaque-trait-size-error-5883.stderr b/tests/ui/traits/opaque-trait-size-error-5883.stderr new file mode 100644 index 00000000000..78de250b19a --- /dev/null +++ b/tests/ui/traits/opaque-trait-size-error-5883.stderr @@ -0,0 +1,35 @@ +error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time + --> $DIR/opaque-trait-size-error-5883.rs:10:6 + | +LL | ) -> Struct { + | ^^^^^^ doesn't have a size known at compile-time + | + = help: within `Struct`, the trait `Sized` is not implemented for `(dyn A + 'static)` +note: required because it appears within the type `Struct` + --> $DIR/opaque-trait-size-error-5883.rs:4:8 + | +LL | struct Struct { + | ^^^^^^ + = note: the return type of a function must have a statically known size + +error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time + --> $DIR/opaque-trait-size-error-5883.rs:9:8 + | +LL | r: dyn A + 'static + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn A + 'static)` + = help: unsized fn params are gated as an unstable feature +help: you can use `impl Trait` as the argument type + | +LL - r: dyn A + 'static +LL + r: impl A + 'static + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | r: &dyn A + 'static + | + + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/trait-implementation-generic-access-6898.rs b/tests/ui/traits/trait-implementation-generic-access-6898.rs new file mode 100644 index 00000000000..e9437b1c522 --- /dev/null +++ b/tests/ui/traits/trait-implementation-generic-access-6898.rs @@ -0,0 +1,33 @@ +// https://github.com/rust-lang/rust/issues/6898 +//@ check-pass + +use std::mem; + +/// Returns the size of a type +pub fn size_of() -> usize { + TypeInfo::size_of(None::) +} + +/// Returns the size of the type that `val` points to +pub fn size_of_val(val: &T) -> usize { + val.size_of_val() +} + +pub trait TypeInfo: Sized { + fn size_of(_lame_type_hint: Option) -> usize; + fn size_of_val(&self) -> usize; +} + +impl TypeInfo for T { + /// The size of the type in bytes. + fn size_of(_lame_type_hint: Option) -> usize { + mem::size_of::() + } + + /// Returns the size of the type of `self` in bytes. + fn size_of_val(&self) -> usize { + TypeInfo::size_of(None::) + } +} + +pub fn main() {} diff --git a/tests/ui/traits/trait-implementation-restriction-5988.rs b/tests/ui/traits/trait-implementation-restriction-5988.rs new file mode 100644 index 00000000000..d3a5b10569b --- /dev/null +++ b/tests/ui/traits/trait-implementation-restriction-5988.rs @@ -0,0 +1,24 @@ +// https://github.com/rust-lang/rust/issues/5988 +//@ run-pass + +trait B { + fn f(&self); +} + +trait T : B { +} + +struct A; + +impl B for U { + fn f(&self) { } +} + +impl T for A { +} + +fn main() { + let a = A; + let br = &a as &dyn B; + br.f(); +} diff --git a/tests/ui/unsafe/auxiliary/aux-5844.rs b/tests/ui/unsafe/auxiliary/aux-5844.rs new file mode 100644 index 00000000000..ea83378cad6 --- /dev/null +++ b/tests/ui/unsafe/auxiliary/aux-5844.rs @@ -0,0 +1,3 @@ +extern "C" { + pub fn rand() -> u32; +} diff --git a/tests/ui/unsafe/extern-function-requires-unsafe-5844.rs b/tests/ui/unsafe/extern-function-requires-unsafe-5844.rs new file mode 100644 index 00000000000..11863ce647a --- /dev/null +++ b/tests/ui/unsafe/extern-function-requires-unsafe-5844.rs @@ -0,0 +1,8 @@ +// https://github.com/rust-lang/rust/issues/5844 +//@aux-build:aux-5844.rs + +extern crate aux_5844; + +fn main() { + aux_5844::rand(); //~ ERROR: requires unsafe +} diff --git a/tests/ui/unsafe/extern-function-requires-unsafe-5844.stderr b/tests/ui/unsafe/extern-function-requires-unsafe-5844.stderr new file mode 100644 index 00000000000..44dee178991 --- /dev/null +++ b/tests/ui/unsafe/extern-function-requires-unsafe-5844.stderr @@ -0,0 +1,11 @@ +error[E0133]: call to unsafe function `rand` is unsafe and requires unsafe function or block + --> $DIR/extern-function-requires-unsafe-5844.rs:7:5 + | +LL | aux_5844::rand(); + | ^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0133`. -- cgit 1.4.1-3-g733a5 From 0b4f9783f0e11df0a3bed7fdea0628ee4b31a6f3 Mon Sep 17 00:00:00 2001 From: Nathan Collins Date: Tue, 12 Aug 2025 14:37:15 +0800 Subject: Improve std::fs::read_dir docs Call out early that the results returned can differ across calls / aren't deterministic. This was already mentioned at the bottom of examples, but I think it's worth calling out early, since this caused at least one person (me!) great confusion. [ Added a comma to the docs, reflowed commit message - Trevor ] --- library/std/src/fs.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index a220a3f56e9..6001b04d88e 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -3036,6 +3036,9 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// Entries for the current and parent directories (typically `.` and `..`) are /// skipped. /// +/// The order in which `read_dir` returns entries can change between calls. If reproducible +/// ordering is required, the entries should be explicitly sorted. +/// /// # Platform-specific behavior /// /// This function currently corresponds to the `opendir` function on Unix -- cgit 1.4.1-3-g733a5 From 2c361f826756fa9c14e611c01b6f6717ecbd19f2 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 27 Aug 2025 14:39:33 +0900 Subject: remove old crash test --- tests/crashes/137580.rs | 4 ---- tests/ui/macros/format-foreign-dollar-without-spec.rs | 1 + tests/ui/macros/format-foreign-dollar-without-spec.stderr | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) delete mode 100644 tests/crashes/137580.rs diff --git a/tests/crashes/137580.rs b/tests/crashes/137580.rs deleted file mode 100644 index 246c80ef556..00000000000 --- a/tests/crashes/137580.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #137580 -fn main() { - println!("%65536$", 1); -} diff --git a/tests/ui/macros/format-foreign-dollar-without-spec.rs b/tests/ui/macros/format-foreign-dollar-without-spec.rs index 3e6a833e24a..c57c1382c8d 100644 --- a/tests/ui/macros/format-foreign-dollar-without-spec.rs +++ b/tests/ui/macros/format-foreign-dollar-without-spec.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/137580 fn main() { println!("%65536$", 1); //~^ ERROR never used diff --git a/tests/ui/macros/format-foreign-dollar-without-spec.stderr b/tests/ui/macros/format-foreign-dollar-without-spec.stderr index a20c34a1f85..d5a07c50f00 100644 --- a/tests/ui/macros/format-foreign-dollar-without-spec.stderr +++ b/tests/ui/macros/format-foreign-dollar-without-spec.stderr @@ -1,12 +1,12 @@ error: argument never used - --> $DIR/format-foreign-dollar-without-spec.rs:2:25 + --> $DIR/format-foreign-dollar-without-spec.rs:3:25 | LL | println!("%65536$", 1); | ^ argument never used | note: format specifiers use curly braces, and the conversion specifier ` ` is unknown or unsupported - --> $DIR/format-foreign-dollar-without-spec.rs:2:15 + --> $DIR/format-foreign-dollar-without-spec.rs:3:15 | LL | println!("%65536$", 1); | ^^^^^^^^ -- cgit 1.4.1-3-g733a5 From c2e5c212232f615c6ad1e5a5926dddaff150e218 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Tue, 26 Aug 2025 09:57:44 +0200 Subject: Add snapshot test for rustc docs --- src/bootstrap/src/core/builder/tests.rs | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 3c2cb782850..8674af1ded0 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1724,6 +1724,47 @@ mod snapshot { "); } + #[test] + fn dist_rustc_docs() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx + .config("dist") + .path("rustc-docs") + .render_steps(), @r" + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [build] rustc 1 -> rustc 2 + [build] rustdoc 2 + [doc] rustc 2 -> std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + "); + } + #[test] fn check_compiler_no_explicit_stage() { let ctx = TestCtx::new(); -- cgit 1.4.1-3-g733a5 From 31e900b78f6c85b3944bd6644aebe3ba7eff4e8f Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Tue, 26 Aug 2025 10:03:00 +0200 Subject: Add metadata to `dist::JsonDocs` --- src/bootstrap/src/core/build_steps/dist.rs | 7 ++++++- src/bootstrap/src/core/builder/tests.rs | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 778c3beb50f..5287aa07fc1 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -96,6 +96,8 @@ impl Step for Docs { } } +/// Builds the `rust-docs-json` installer component. +/// It contains the documentation of the standard library in JSON format. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct JsonDocs { build_compiler: Compiler, @@ -118,7 +120,6 @@ impl Step for JsonDocs { }); } - /// Builds the `rust-docs-json` installer component. fn run(self, builder: &Builder<'_>) -> Option { let target = self.target; let directory = builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler( @@ -135,6 +136,10 @@ impl Step for JsonDocs { tarball.add_bulk_dir(directory, dest); Some(tarball.generate()) } + + fn metadata(&self) -> Option { + Some(StepMetadata::dist("json-docs", self.target).built_by(self.build_compiler)) + } } /// Builds the `rustc-docs` installer component. diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 8674af1ded0..5c8cec4615d 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1142,6 +1142,7 @@ mod snapshot { [build] rustc 0 -> RustInstaller 1 [dist] docs [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 [dist] mingw [build] rustc 0 -> GenerateCopyright 1 [dist] rustc @@ -1205,6 +1206,7 @@ mod snapshot { [build] rustc 0 -> RustInstaller 1 [dist] docs [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 [dist] mingw [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 [build] rustc 0 -> GenerateCopyright 1 @@ -1291,7 +1293,9 @@ mod snapshot { [dist] docs [dist] docs [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 [dist] mingw [dist] mingw [build] rustc 0 -> GenerateCopyright 1 @@ -1353,6 +1357,7 @@ mod snapshot { [build] rustc 0 -> RustInstaller 1 [dist] docs [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 [dist] mingw [build] rustc 0 -> GenerateCopyright 1 [dist] rustc @@ -1433,7 +1438,9 @@ mod snapshot { [dist] docs [dist] docs [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 [dist] mingw [dist] mingw [build] rustc 0 -> GenerateCopyright 1 @@ -1489,6 +1496,7 @@ mod snapshot { [build] rustc 0 -> RustInstaller 1 [dist] docs [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 [dist] mingw [build] rustc 2 -> std 2 [dist] rustc 2 -> std 2 @@ -1543,6 +1551,7 @@ mod snapshot { [build] rustc 0 -> RustInstaller 1 [dist] docs [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 [dist] mingw [build] rustdoc 2 [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 @@ -1567,6 +1576,7 @@ mod snapshot { [dist] rustc 1 -> miri 2 [build] rustc 1 -> LlvmBitcodeLinker 2 [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 [dist] rustc 1 -> extended 2 [dist] reproducible-artifacts "); @@ -1684,6 +1694,7 @@ mod snapshot { [build] rustc 0 -> RustInstaller 1 [dist] docs [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 [dist] mingw [build] rustc 0 -> GenerateCopyright 1 [dist] rustc -- cgit 1.4.1-3-g733a5 From edcdb80914c9bc32bf3901ca68ff76d122cd2286 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Tue, 26 Aug 2025 10:13:55 +0200 Subject: Add `compiler_for_std` --- src/bootstrap/src/core/build_steps/compile.rs | 2 +- src/bootstrap/src/core/build_steps/dist.rs | 2 +- src/bootstrap/src/core/build_steps/doc.rs | 4 +++- src/bootstrap/src/core/builder/mod.rs | 8 ++++++++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index d30005c8d51..bc978e1c4d0 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -150,7 +150,7 @@ impl Step for Std { trace!(force_recompile); run.builder.ensure(Std { - build_compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), + build_compiler: run.builder.compiler_for_std(run.builder.top_stage, run.target), target: run.target, crates, force_recompile, diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 5287aa07fc1..1320c3f65d5 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -115,7 +115,7 @@ impl Step for JsonDocs { fn make_run(run: RunConfig<'_>) { run.builder.ensure(JsonDocs { - build_compiler: run.builder.compiler(run.builder.top_stage, run.builder.host_target), + build_compiler: run.builder.compiler_for_std(run.builder.top_stage, run.target), target: run.target, }); } diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 8c20c8c479a..379d997e1f2 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -616,7 +616,9 @@ impl Step for Std { return; } run.builder.ensure(Std { - build_compiler: run.builder.compiler(run.builder.top_stage, run.builder.host_target), + build_compiler: run + .builder + .compiler_for_std(run.builder.top_stage, run.builder.host_target), target: run.target, format: if run.builder.config.cmd.json() { DocumentationFormat::Json diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index f794f4e079a..02ca1a33516 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1360,6 +1360,14 @@ impl<'a> Builder<'a> { self.ensure(compile::Assemble { target_compiler: Compiler::new(stage, host) }) } + pub fn compiler_for_std(&self, stage: u32, target: TargetSelection) -> Compiler { + if compile::Std::should_be_uplifted_from_stage_1(self, stage, target) { + self.compiler(1, self.host_target) + } else { + self.compiler(stage, self.host_target) + } + } + /// Similar to `compiler`, except handles the full-bootstrap option to /// silently use the stage1 compiler instead of a stage2 compiler if one is /// requested. -- cgit 1.4.1-3-g733a5 From 41563c7d4a0e54a414502f727df9b9caa737da39 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Tue, 26 Aug 2025 22:42:04 +0200 Subject: Use `compiler_for_std` in `dist::Std` --- src/bootstrap/src/core/build_steps/compile.rs | 4 +- src/bootstrap/src/core/build_steps/dist.rs | 17 +----- src/bootstrap/src/core/builder/mod.rs | 15 +++++ src/bootstrap/src/core/builder/tests.rs | 82 +++++++++++++-------------- 4 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index bc978e1c4d0..72069df4cbd 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -150,7 +150,9 @@ impl Step for Std { trace!(force_recompile); run.builder.ensure(Std { - build_compiler: run.builder.compiler_for_std(run.builder.top_stage, run.target), + // Note: we don't use compiler_for_std here, so that `x build library --stage 2` + // builds a stage2 rustc. + build_compiler: run.builder.compiler(run.builder.top_stage, builder.host_target), target: run.target, crates, force_recompile, diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 1320c3f65d5..a76bef93317 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -769,22 +769,7 @@ pub struct Std { impl Std { pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self { - // This is an important optimization mainly for CI. - // Normally, to build stage N libstd, we need stage N rustc. - // However, if we know that we will uplift libstd from stage 1 anyway, building the stage N - // rustc can be wasteful. - // In particular, if we do a cross-compiling dist stage 2 build from T1 to T2, we need: - // - stage 2 libstd for T2 (uplifted from stage 1, where it was built by T1 rustc) - // - stage 2 rustc for T2 - // However, without this optimization, we would also build stage 2 rustc for **T1**, which - // is completely wasteful. - let build_compiler = - if compile::Std::should_be_uplifted_from_stage_1(builder, builder.top_stage, target) { - builder.compiler(1, builder.host_target) - } else { - builder.compiler(builder.top_stage, builder.host_target) - }; - Std { build_compiler, target } + Std { build_compiler: builder.compiler_for_std(builder.top_stage, target), target } } } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 02ca1a33516..4f37e0edbad 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1360,6 +1360,21 @@ impl<'a> Builder<'a> { self.ensure(compile::Assemble { target_compiler: Compiler::new(stage, host) }) } + /// This function can be used to provide a build compiler for building + /// the standard library, in order to avoid unnecessary rustc builds in case where std uplifting + /// would happen anyway. + /// + /// This is an important optimization mainly for CI. + /// + /// Normally, to build stage N libstd, we need stage N rustc. + /// However, if we know that we will uplift libstd from stage 1 anyway, building the stage N + /// rustc can be wasteful. + /// In particular, if we do a cross-compiling dist stage 2 build from target1 to target2, + /// we need: + /// - stage 2 libstd for target2 (uplifted from stage 1, where it was built by target1 rustc) + /// - stage 2 rustc for target2 + /// However, without this optimization, we would also build stage 2 rustc for **target1**, + /// which is completely wasteful. pub fn compiler_for_std(&self, stage: u32, target: TargetSelection) -> Compiler { if compile::Std::should_be_uplifted_from_stage_1(self, stage, target) { self.compiler(1, self.host_target) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 5c8cec4615d..491df10519a 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1122,9 +1122,8 @@ mod snapshot { [doc] book/2018-edition (book) [build] rustdoc 1 [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> rustc 2 - [build] rustdoc 2 - [doc] rustc 2 -> std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> error-index 2 [doc] rustc 1 -> error-index 2 [doc] nomicon (book) @@ -1141,9 +1140,10 @@ mod snapshot { [doc] rustc 1 -> releases 2 [build] rustc 0 -> RustInstaller 1 [dist] docs - [doc] rustc 2 -> std 2 crates=[] - [dist] rustc 2 -> json-docs 3 + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 [dist] mingw + [build] rustdoc 2 [build] rustc 0 -> GenerateCopyright 1 [dist] rustc [dist] rustc 1 -> std 1 @@ -1183,12 +1183,11 @@ mod snapshot { [doc] book/2018-edition (book) [build] rustdoc 1 [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> rustc 2 [build] rustc 1 -> LldWrapper 2 [build] rustc 1 -> WasmComponentLd 2 [build] rustc 1 -> LlvmBitcodeLinker 2 - [build] rustdoc 2 - [doc] rustc 2 -> std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> error-index 2 [doc] rustc 1 -> error-index 2 [doc] nomicon (book) @@ -1205,9 +1204,10 @@ mod snapshot { [doc] rustc 1 -> releases 2 [build] rustc 0 -> RustInstaller 1 [dist] docs - [doc] rustc 2 -> std 2 crates=[] - [dist] rustc 2 -> json-docs 3 + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 [dist] mingw + [build] rustdoc 2 [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 [build] rustc 0 -> GenerateCopyright 1 [dist] rustc @@ -1228,6 +1228,8 @@ mod snapshot { [build] rustc 1 -> miri 2 [build] rustc 1 -> cargo-miri 2 [dist] rustc 1 -> miri 2 + [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 [dist] rustc 1 -> extended 2 [dist] reproducible-artifacts "); @@ -1261,10 +1263,9 @@ mod snapshot { [doc] book/2018-edition (book) [doc] rustc 1 -> standalone 2 [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> rustc 2 - [build] rustdoc 2 - [doc] rustc 2 -> std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [doc] rustc 2 -> std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> error-index 2 [doc] rustc 1 -> error-index 2 [doc] nomicon (book) @@ -1292,8 +1293,9 @@ mod snapshot { [build] rustc 0 -> RustInstaller 1 [dist] docs [dist] docs - [doc] rustc 2 -> std 2 crates=[] - [dist] rustc 2 -> json-docs 3 + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 + [build] rustdoc 2 [doc] rustc 2 -> std 2 crates=[] [dist] rustc 2 -> json-docs 3 [dist] mingw @@ -1331,9 +1333,8 @@ mod snapshot { [doc] book/2018-edition (book) [build] rustdoc 1 [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> rustc 2 - [build] rustdoc 2 - [doc] rustc 2 -> std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> error-index 2 [doc] rustc 1 -> error-index 2 [build] llvm @@ -1356,9 +1357,10 @@ mod snapshot { [doc] rustc 1 -> releases 2 [build] rustc 0 -> RustInstaller 1 [dist] docs - [doc] rustc 2 -> std 2 crates=[] - [dist] rustc 2 -> json-docs 3 + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 [dist] mingw + [build] rustdoc 2 [build] rustc 0 -> GenerateCopyright 1 [dist] rustc [build] rustdoc 2 @@ -1401,10 +1403,9 @@ mod snapshot { [doc] book/2018-edition (book) [doc] rustc 1 -> standalone 2 [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> rustc 2 - [build] rustdoc 2 - [doc] rustc 2 -> std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [doc] rustc 2 -> std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> error-index 2 [doc] rustc 1 -> error-index 2 [build] llvm @@ -1437,12 +1438,13 @@ mod snapshot { [build] rustc 0 -> RustInstaller 1 [dist] docs [dist] docs - [doc] rustc 2 -> std 2 crates=[] - [dist] rustc 2 -> json-docs 3 - [doc] rustc 2 -> std 2 crates=[] - [dist] rustc 2 -> json-docs 3 + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 [dist] mingw [dist] mingw + [build] rustdoc 2 [build] rustc 0 -> GenerateCopyright 1 [dist] rustc [build] rustdoc 2 @@ -1480,9 +1482,7 @@ mod snapshot { [build] rustdoc 1 [build] rustc 1 -> std 1 [doc] rustc 1 -> standalone 2 - [build] rustc 1 -> rustc 2 - [build] rustdoc 2 - [doc] rustc 2 -> std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [doc] nomicon (book) [doc] rustc 1 -> reference (book) 2 [doc] rustdoc (book) @@ -1495,6 +1495,8 @@ mod snapshot { [doc] rustc 1 -> releases 2 [build] rustc 0 -> RustInstaller 1 [dist] docs + [build] rustc 1 -> rustc 2 + [build] rustdoc 2 [doc] rustc 2 -> std 2 crates=[] [dist] rustc 2 -> json-docs 3 [dist] mingw @@ -1527,10 +1529,7 @@ mod snapshot { [build] rustdoc 1 [build] rustc 1 -> std 1 [doc] rustc 1 -> standalone 2 - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> WasmComponentLd 2 - [build] rustdoc 2 - [doc] rustc 2 -> std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] llvm [build] rustc 1 -> rustc 2 [build] rustc 1 -> WasmComponentLd 2 @@ -1550,8 +1549,8 @@ mod snapshot { [doc] rustc 1 -> releases 2 [build] rustc 0 -> RustInstaller 1 [dist] docs - [doc] rustc 2 -> std 2 crates=[] - [dist] rustc 2 -> json-docs 3 + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 [dist] mingw [build] rustdoc 2 [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 @@ -1583,7 +1582,7 @@ mod snapshot { } /// Simulates e.g. the powerpc64 builder, which is fully cross-compiled from x64, but it does - /// not build docs. Crutically, it shouldn't build host stage 2 rustc. + /// not build docs. Crucially, it shouldn't build host stage 2 rustc. /// /// This is a regression test for /// and . @@ -1673,10 +1672,9 @@ mod snapshot { [doc] book/2018-edition (book) [build] rustdoc 1 [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> rustc 2 [build] rustc 1 -> rustc_codegen_cranelift 2 - [build] rustdoc 2 - [doc] rustc 2 -> std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> error-index 2 [doc] rustc 1 -> error-index 2 [doc] nomicon (book) @@ -1693,9 +1691,10 @@ mod snapshot { [doc] rustc 1 -> releases 2 [build] rustc 0 -> RustInstaller 1 [dist] docs - [doc] rustc 2 -> std 2 crates=[] - [dist] rustc 2 -> json-docs 3 + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 [dist] mingw + [build] rustdoc 2 [build] rustc 0 -> GenerateCopyright 1 [dist] rustc [dist] rustc 1 -> rustc_codegen_cranelift 2 @@ -1755,9 +1754,8 @@ mod snapshot { [doc] book/2018-edition (book) [build] rustdoc 1 [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> rustc 2 - [build] rustdoc 2 - [doc] rustc 2 -> std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> error-index 2 [doc] rustc 1 -> error-index 2 [doc] nomicon (book) @@ -2467,10 +2465,9 @@ mod snapshot { [doc] book/2018-edition (book) [build] rustdoc 1 [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> rustc 2 [build] rustc 1 -> WasmComponentLd 2 - [build] rustdoc 2 - [doc] rustc 2 -> std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] rustc 1 -> error-index 2 [doc] rustc 1 -> error-index 2 [doc] nomicon (book) @@ -2488,6 +2485,7 @@ mod snapshot { [build] rustc 0 -> RustInstaller 1 [dist] docs [dist] rustc 1 -> std 1 + [build] rustdoc 2 [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 [build] rustc 0 -> GenerateCopyright 1 [dist] rustc -- cgit 1.4.1-3-g733a5 From 6864a5bf42baeb64d23f0b086152a9c2893b5ade Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Tue, 26 Aug 2025 23:00:54 +0200 Subject: Use std uplifting more often --- src/bootstrap/src/core/build_steps/compile.rs | 28 ++++++--------------------- src/bootstrap/src/core/build_steps/dist.rs | 4 ++-- src/bootstrap/src/core/build_steps/doc.rs | 4 +--- src/bootstrap/src/core/builder/mod.rs | 5 +++-- src/bootstrap/src/core/builder/tests.rs | 19 ++++++++---------- 5 files changed, 20 insertions(+), 40 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 72069df4cbd..0b75e85772f 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -99,28 +99,12 @@ impl Std { deps } - /// Returns true if the standard library will be uplifted from stage 1 for the given - /// `build_compiler` (which determines the stdlib stage) and `target`. + /// Returns true if the standard library should be uplifted from stage 1. /// - /// Uplifting is enabled if we're building a stage2+ libstd, full bootstrap is - /// disabled and we have a stage1 libstd already compiled for the given target. - pub fn should_be_uplifted_from_stage_1( - builder: &Builder<'_>, - stage: u32, - target: TargetSelection, - ) -> bool { - stage > 1 - && !builder.config.full_bootstrap - // This estimates if a stage1 libstd exists for the given target. If we're not - // cross-compiling, it should definitely exist by the time we're building a stage2 - // libstd. - // Or if we are cross-compiling, and we are building a cross-compiled rustc, then that - // rustc needs to link to a cross-compiled libstd, so again we should have a stage1 - // libstd for the given target prepared. - // Even if we guess wrong in the cross-compiled case, the worst that should happen is - // that we build a fresh stage1 libstd below, and then we immediately uplift it, so we - // don't pay the libstd build cost twice. - && (target == builder.host_target || builder.config.hosts.contains(&target)) + /// Uplifting is enabled if we're building a stage2+ libstd and full bootstrap is + /// disabled. + pub fn should_be_uplifted_from_stage_1(builder: &Builder<'_>, stage: u32) -> bool { + stage > 1 && !builder.config.full_bootstrap } } @@ -228,7 +212,7 @@ impl Step for Std { // Stage of the stdlib that we're building let stage = build_compiler.stage; - if Self::should_be_uplifted_from_stage_1(builder, build_compiler.stage, target) { + if Self::should_be_uplifted_from_stage_1(builder, build_compiler.stage) { let build_compiler_for_std_to_uplift = builder.compiler(1, builder.host_target); let stage_1_stamp = builder.std(build_compiler_for_std_to_uplift, target); diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index a76bef93317..f113dd7683d 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -115,7 +115,7 @@ impl Step for JsonDocs { fn make_run(run: RunConfig<'_>) { run.builder.ensure(JsonDocs { - build_compiler: run.builder.compiler_for_std(run.builder.top_stage, run.target), + build_compiler: run.builder.compiler_for_std(run.builder.top_stage), target: run.target, }); } @@ -769,7 +769,7 @@ pub struct Std { impl Std { pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self { - Std { build_compiler: builder.compiler_for_std(builder.top_stage, target), target } + Std { build_compiler: builder.compiler_for_std(builder.top_stage), target } } } diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 379d997e1f2..9ef1fee1fec 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -616,9 +616,7 @@ impl Step for Std { return; } run.builder.ensure(Std { - build_compiler: run - .builder - .compiler_for_std(run.builder.top_stage, run.builder.host_target), + build_compiler: run.builder.compiler_for_std(run.builder.top_stage), target: run.target, format: if run.builder.config.cmd.json() { DocumentationFormat::Json diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 4f37e0edbad..b224a7e7322 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1373,10 +1373,11 @@ impl<'a> Builder<'a> { /// we need: /// - stage 2 libstd for target2 (uplifted from stage 1, where it was built by target1 rustc) /// - stage 2 rustc for target2 + /// /// However, without this optimization, we would also build stage 2 rustc for **target1**, /// which is completely wasteful. - pub fn compiler_for_std(&self, stage: u32, target: TargetSelection) -> Compiler { - if compile::Std::should_be_uplifted_from_stage_1(self, stage, target) { + pub fn compiler_for_std(&self, stage: u32) -> Compiler { + if compile::Std::should_be_uplifted_from_stage_1(self, stage) { self.compiler(1, self.host_target) } else { self.compiler(stage, self.host_target) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 491df10519a..b079117c5a7 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1066,6 +1066,7 @@ mod snapshot { [build] rustc 1 -> rustc 2 [build] rustc 2 -> std 2 [build] rustc 2 -> std 2 + [build] rustc 1 -> std 1 [build] rustc 2 -> std 2 "); } @@ -1295,16 +1296,15 @@ mod snapshot { [dist] docs [doc] rustc 1 -> std 1 crates=[] [dist] rustc 1 -> json-docs 2 - [build] rustdoc 2 - [doc] rustc 2 -> std 2 crates=[] - [dist] rustc 2 -> json-docs 3 + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 [dist] mingw [dist] mingw + [build] rustdoc 2 [build] rustc 0 -> GenerateCopyright 1 [dist] rustc [dist] rustc 1 -> std 1 - [build] rustc 2 -> std 2 - [dist] rustc 2 -> std 2 + [dist] rustc 1 -> std 1 [dist] rustc 1 -> rustc-dev 2 [dist] src <> [dist] reproducible-artifacts @@ -1495,13 +1495,10 @@ mod snapshot { [doc] rustc 1 -> releases 2 [build] rustc 0 -> RustInstaller 1 [dist] docs - [build] rustc 1 -> rustc 2 - [build] rustdoc 2 - [doc] rustc 2 -> std 2 crates=[] - [dist] rustc 2 -> json-docs 3 + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 [dist] mingw - [build] rustc 2 -> std 2 - [dist] rustc 2 -> std 2 + [dist] rustc 1 -> std 1 "); } -- cgit 1.4.1-3-g733a5 From 21de27c88a87a141003198ec0d9df789ca9c75cc Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 27 Aug 2025 17:30:59 +1000 Subject: Explicitly mark the end of a failed test's captured output --- src/bootstrap/src/utils/render_tests.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 40006aca5c5..90fd57d976d 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -250,8 +250,14 @@ impl<'a> Renderer<'a> { if failure.stdout.is_some() || failure.message.is_some() { println!("---- {} stdout ----", failure.name); if let Some(stdout) = &failure.stdout { - println!("{stdout}"); + // Captured test output normally ends with a newline, + // so only use `println!` if it doesn't. + print!("{stdout}"); + if !stdout.ends_with('\n') { + println!("\n\\ (no newline at end of output)"); + } } + println!("---- {} stdout end ----", failure.name); if let Some(message) = &failure.message { println!("NOTE: {message}"); } -- cgit 1.4.1-3-g733a5 From 2736c7461f6331bc674e974ac32f53846fd29a6f Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sun, 24 Aug 2025 20:26:27 +0200 Subject: Use `AcceptContext` in `AttribueParser::check_target` --- compiler/rustc_attr_parsing/src/interface.rs | 9 +----- compiler/rustc_attr_parsing/src/target_checking.rs | 37 ++++++++++------------ 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index a3558850ef3..0fe3c209421 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -273,14 +273,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { (accept.accept_fn)(&mut cx, args); if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) { Self::check_type(accept.attribute_type, target, &mut cx); - self.check_target( - path.get_attribute_path(), - attr.span, - &accept.allowed_targets, - target, - target_id, - &mut emit_lint, - ); + Self::check_target(&accept.allowed_targets, target, &mut cx); } } } else { diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 6f4dd76fa81..edc496b460c 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -3,9 +3,8 @@ use std::borrow::Cow; use rustc_ast::AttrStyle; use rustc_errors::DiagArgValue; use rustc_feature::{AttributeType, Features}; -use rustc_hir::lints::{AttributeLint, AttributeLintKind}; -use rustc_hir::{AttrPath, MethodKind, Target}; -use rustc_span::Span; +use rustc_hir::lints::AttributeLintKind; +use rustc_hir::{MethodKind, Target}; use crate::AttributeParser; use crate::context::{AcceptContext, Stage}; @@ -71,38 +70,34 @@ pub(crate) enum Policy { impl<'sess, S: Stage> AttributeParser<'sess, S> { pub(crate) fn check_target( - &self, - attr_name: AttrPath, - attr_span: Span, allowed_targets: &AllowedTargets, target: Target, - target_id: S::Id, - mut emit_lint: impl FnMut(AttributeLint), + cx: &mut AcceptContext<'_, 'sess, S>, ) { match allowed_targets.is_allowed(target) { AllowedResult::Allowed => {} AllowedResult::Warn => { let allowed_targets = allowed_targets.allowed_targets(); - let (applied, only) = - allowed_targets_applied(allowed_targets, target, self.features); - emit_lint(AttributeLint { - id: target_id, - span: attr_span, - kind: AttributeLintKind::InvalidTarget { - name: attr_name, + let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features); + let name = cx.attr_path.clone(); + let attr_span = cx.attr_span; + cx.emit_lint( + AttributeLintKind::InvalidTarget { + name, target, only: if only { "only " } else { "" }, applied, }, - }); + attr_span, + ); } AllowedResult::Error => { let allowed_targets = allowed_targets.allowed_targets(); - let (applied, only) = - allowed_targets_applied(allowed_targets, target, self.features); - self.dcx().emit_err(InvalidTarget { - span: attr_span, - name: attr_name, + let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features); + let name = cx.attr_path.clone(); + cx.dcx().emit_err(InvalidTarget { + span: cx.attr_span.clone(), + name, target: target.plural_name(), only: if only { "only " } else { "" }, applied: DiagArgValue::StrListSepByAnd( -- cgit 1.4.1-3-g733a5 From 0da328b2c61d39da1e0458ac528b667ae9055eb6 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Wed, 27 Aug 2025 11:45:42 +0800 Subject: Add spin_loop hint for LoongArch --- library/core/src/hint.rs | 56 ++++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index c72eeb9a9c9..535c5a8e77b 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -267,39 +267,29 @@ pub const unsafe fn assert_unchecked(cond: bool) { #[inline(always)] #[stable(feature = "renamed_spin_loop", since = "1.49.0")] pub fn spin_loop() { - #[cfg(target_arch = "x86")] - { - // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets. - unsafe { crate::arch::x86::_mm_pause() }; - } - - #[cfg(target_arch = "x86_64")] - { - // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets. - unsafe { crate::arch::x86_64::_mm_pause() }; - } - - #[cfg(target_arch = "riscv32")] - { - crate::arch::riscv32::pause(); - } - - #[cfg(target_arch = "riscv64")] - { - crate::arch::riscv64::pause(); - } - - #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] - { - // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets. - unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) }; - } - - #[cfg(all(target_arch = "arm", target_feature = "v6"))] - { - // SAFETY: the `cfg` attr ensures that we only execute this on arm targets - // with support for the v6 feature. - unsafe { crate::arch::arm::__yield() }; + crate::cfg_select! { + target_arch = "x86" => { + // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets. + unsafe { crate::arch::x86::_mm_pause() } + } + target_arch = "x86_64" => { + // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets. + unsafe { crate::arch::x86_64::_mm_pause() } + } + target_arch = "riscv32" => crate::arch::riscv32::pause(), + target_arch = "riscv64" => crate::arch::riscv64::pause(), + any(target_arch = "aarch64", target_arch = "arm64ec") => { + // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets. + unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) } + } + all(target_arch = "arm", target_feature = "v6") => { + // SAFETY: the `cfg` attr ensures that we only execute this on arm targets + // with support for the v6 feature. + unsafe { crate::arch::arm::__yield() } + } + target_arch = "loongarch32" => crate::arch::loongarch32::ibar::<0>(), + target_arch = "loongarch64" => crate::arch::loongarch64::ibar::<0>(), + _ => { /* do nothing */ } } } -- cgit 1.4.1-3-g733a5 From dacae07b6d8c42f5eca57de9c18e17349994d654 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 27 Aug 2025 12:42:49 +0000 Subject: Rename `Location::file_with_nul` to `file_as_c_str` --- library/core/src/panic/location.rs | 4 ++-- tests/ui/rfcs/rfc-2091-track-caller/file-is-nul-terminated.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs index cafdcfa2c2e..7a68d393906 100644 --- a/library/core/src/panic/location.rs +++ b/library/core/src/panic/location.rs @@ -39,7 +39,7 @@ use crate::ptr::NonNull; pub struct Location<'a> { // A raw pointer is used rather than a reference because the pointer is valid for one more byte // than the length stored in this pointer; the additional byte is the NUL-terminator used by - // `Location::file_with_nul`. + // `Location::file_as_c_str`. filename: NonNull, line: u32, col: u32, @@ -195,7 +195,7 @@ impl<'a> Location<'a> { #[must_use] #[unstable(feature = "file_with_nul", issue = "141727")] #[inline] - pub const fn file_with_nul(&self) -> &'a CStr { + pub const fn file_as_c_str(&self) -> &'a CStr { let filename = self.filename.as_ptr(); // SAFETY: The filename is valid for `filename_len+1` bytes, so this addition can't diff --git a/tests/ui/rfcs/rfc-2091-track-caller/file-is-nul-terminated.rs b/tests/ui/rfcs/rfc-2091-track-caller/file-is-nul-terminated.rs index 65e61a21f1a..7902f40b09b 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/file-is-nul-terminated.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/file-is-nul-terminated.rs @@ -5,12 +5,12 @@ const fn assert_file_has_trailing_zero() { let caller = core::panic::Location::caller(); let file_str = caller.file(); - let file_with_nul = caller.file_with_nul(); - if file_str.len() != file_with_nul.count_bytes() { + let file_cstr = caller.file_as_c_str(); + if file_str.len() != file_cstr.count_bytes() { panic!("mismatched lengths"); } let trailing_byte: core::ffi::c_char = unsafe { - *file_with_nul.as_ptr().offset(file_with_nul.count_bytes() as _) + *file_cstr.as_ptr().offset(file_cstr.count_bytes() as _) }; if trailing_byte != 0 { panic!("trailing byte was nonzero") -- cgit 1.4.1-3-g733a5 From 113aeac44aa35a2052e9d4c71f382cca7cfaea61 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 27 Aug 2025 20:55:50 +1000 Subject: Remove several remnants of the old libtest-based executor --- src/bootstrap/src/core/build_steps/test.rs | 2 - src/tools/compiletest/src/common.rs | 10 +-- src/tools/compiletest/src/executor.rs | 22 ++---- src/tools/compiletest/src/lib.rs | 105 +++++++++++--------------- src/tools/compiletest/src/runtest.rs | 2 +- src/tools/compiletest/src/runtest/run_make.rs | 2 +- 6 files changed, 53 insertions(+), 90 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index abe79405984..26b4aaa8b5b 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2025,8 +2025,6 @@ HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?} cmd.arg("--verbose"); } - cmd.arg("--json"); - if builder.config.rustc_debug_assertions { cmd.arg("--with-rustc-debug-assertions"); } diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 7fc80c1edb1..b72c0b7ed20 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -8,7 +8,7 @@ use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; use serde::de::{Deserialize, Deserializer, Error as _}; -use crate::executor::{ColorConfig, OutputFormat}; +use crate::executor::ColorConfig; use crate::fatal; use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum}; @@ -565,13 +565,6 @@ pub struct Config { /// FIXME: this is *way* too coarse; the user can't select *which* info to verbosely dump. pub verbose: bool, - /// (Useless) Adjust libtest output format. - /// - /// FIXME: the hand-rolled executor does not support non-JSON output, because `compiletest` need - /// to package test outcome as `libtest`-esque JSON that `bootstrap` can intercept *anyway*. - /// However, now that we don't use the `libtest` executor, this is useless. - pub format: OutputFormat, - /// Whether to use colors in test output. /// /// Note: the exact control mechanism is delegated to [`colored`]. @@ -768,7 +761,6 @@ impl Config { adb_device_status: Default::default(), lldb_python_dir: Default::default(), verbose: Default::default(), - format: Default::default(), color: Default::default(), remote_test_client: Default::default(), compare_mode: Default::default(), diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index df64f12784f..fdd7155c21f 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -1,5 +1,9 @@ //! This module contains a reimplementation of the subset of libtest //! functionality needed by compiletest. +//! +//! FIXME(Zalathar): Much of this code was originally designed to mimic libtest +//! as closely as possible, for ease of migration. Now that libtest is no longer +//! used, we can potentially redesign things to be a better fit for compiletest. use std::borrow::Cow; use std::collections::HashMap; @@ -207,7 +211,7 @@ impl TestOutcome { /// /// Adapted from `filter_tests` in libtest. /// -/// FIXME(#139660): After the libtest dependency is removed, redesign the whole filtering system to +/// FIXME(#139660): Now that libtest has been removed, redesign the whole filtering system to /// do a better job of understanding and filtering _paths_, instead of being tied to libtest's /// substring/exact matching behaviour. fn filter_tests(opts: &Config, tests: Vec) -> Vec { @@ -249,7 +253,7 @@ fn get_concurrency() -> usize { } } -/// Information needed to create a `test::TestDescAndFn`. +/// Information that was historically needed to create a libtest `TestDescAndFn`. pub(crate) struct CollectedTest { pub(crate) desc: CollectedTestDesc, pub(crate) config: Arc, @@ -257,7 +261,7 @@ pub(crate) struct CollectedTest { pub(crate) revision: Option, } -/// Information needed to create a `test::TestDesc`. +/// Information that was historically needed to create a libtest `TestDesc`. pub(crate) struct CollectedTestDesc { pub(crate) name: String, pub(crate) ignore: bool, @@ -274,18 +278,6 @@ pub enum ColorConfig { NeverColor, } -/// Format of the test results output. -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -pub enum OutputFormat { - /// Verbose output - Pretty, - /// Quiet output - #[default] - Terse, - /// JSON output - Json, -} - /// Whether test is expected to panic or not. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub(crate) enum ShouldPanic { diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 469dd68207e..58f7c6b5071 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -43,7 +43,7 @@ use crate::common::{ expected_output_path, output_base_dir, output_relative_path, }; use crate::directives::DirectivesCache; -use crate::executor::{CollectedTest, ColorConfig, OutputFormat}; +use crate::executor::{CollectedTest, ColorConfig}; use crate::util::logv; /// Creates the `Config` instance for this invocation of compiletest. @@ -137,9 +137,7 @@ pub fn parse_config(args: Vec) -> Config { "overwrite stderr/stdout files instead of complaining about a mismatch", ) .optflag("", "fail-fast", "stop as soon as possible after any test fails") - .optflag("", "quiet", "print one character per test instead of one line") .optopt("", "color", "coloring: auto, always, never", "WHEN") - .optflag("", "json", "emit json output instead of plaintext output") .optopt("", "target", "the target to build for", "TARGET") .optopt("", "host", "the host to build for", "HOST") .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH") @@ -203,7 +201,6 @@ pub fn parse_config(args: Vec) -> Config { "COMMAND", ) .reqopt("", "minicore-path", "path to minicore aux library", "PATH") - .optflag("N", "no-new-executor", "disables the new test executor, and uses libtest instead") .optopt( "", "debugger", @@ -436,12 +433,6 @@ pub fn parse_config(args: Vec) -> Config { && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(), lldb_python_dir: matches.opt_str("lldb-python-dir"), verbose: matches.opt_present("verbose"), - format: match (matches.opt_present("quiet"), matches.opt_present("json")) { - (true, true) => panic!("--quiet and --json are incompatible"), - (true, false) => OutputFormat::Terse, - (false, true) => OutputFormat::Json, - (false, false) => OutputFormat::Pretty, - }, only_modified: matches.opt_present("only-modified"), color, remote_test_client: matches.opt_str("remote-test-client").map(Utf8PathBuf::from), @@ -527,7 +518,6 @@ pub fn log_config(config: &Config) { logv(c, format!("target-linker: {:?}", config.target_linker)); logv(c, format!("host-linker: {:?}", config.host_linker)); logv(c, format!("verbose: {}", config.verbose)); - logv(c, format!("format: {:?}", config.format)); logv(c, format!("minicore_path: {}", config.minicore_path)); logv(c, "\n".to_string()); } @@ -601,7 +591,7 @@ pub fn run_tests(config: Arc) { configs.push(config.clone()); }; - // Discover all of the tests in the test suite directory, and build a libtest + // Discover all of the tests in the test suite directory, and build a `CollectedTest` // structure for each test (or each revision of a multi-revision test). let mut tests = Vec::new(); for c in configs { @@ -613,50 +603,35 @@ pub fn run_tests(config: Arc) { // Delegate to the executor to filter and run the big list of test structures // created during test discovery. When the executor decides to run a test, // it will return control to the rest of compiletest by calling `runtest::run`. - // FIXME(Zalathar): Once we're confident that we won't need to revert the - // removal of the libtest-based executor, remove this Result and other - // remnants of the old executor. - let res: io::Result = Ok(executor::run_tests(&config, tests)); - - // Check the outcome reported by libtest. - match res { - Ok(true) => {} - Ok(false) => { - // We want to report that the tests failed, but we also want to give - // some indication of just what tests we were running. Especially on - // CI, where there can be cross-compiled tests for a lot of - // architectures, without this critical information it can be quite - // easy to miss which tests failed, and as such fail to reproduce - // the failure locally. - - let mut msg = String::from("Some tests failed in compiletest"); - write!(msg, " suite={}", config.suite).unwrap(); - - if let Some(compare_mode) = config.compare_mode.as_ref() { - write!(msg, " compare_mode={}", compare_mode).unwrap(); - } + let ok = executor::run_tests(&config, tests); + + // Check the outcome reported by the executor. + if !ok { + // We want to report that the tests failed, but we also want to give + // some indication of just what tests we were running. Especially on + // CI, where there can be cross-compiled tests for a lot of + // architectures, without this critical information it can be quite + // easy to miss which tests failed, and as such fail to reproduce + // the failure locally. + + let mut msg = String::from("Some tests failed in compiletest"); + write!(msg, " suite={}", config.suite).unwrap(); + + if let Some(compare_mode) = config.compare_mode.as_ref() { + write!(msg, " compare_mode={}", compare_mode).unwrap(); + } - if let Some(pass_mode) = config.force_pass_mode.as_ref() { - write!(msg, " pass_mode={}", pass_mode).unwrap(); - } + if let Some(pass_mode) = config.force_pass_mode.as_ref() { + write!(msg, " pass_mode={}", pass_mode).unwrap(); + } - write!(msg, " mode={}", config.mode).unwrap(); - write!(msg, " host={}", config.host).unwrap(); - write!(msg, " target={}", config.target).unwrap(); + write!(msg, " mode={}", config.mode).unwrap(); + write!(msg, " host={}", config.host).unwrap(); + write!(msg, " target={}", config.target).unwrap(); - println!("{msg}"); + println!("{msg}"); - std::process::exit(1); - } - Err(e) => { - // We don't know if tests passed or not, but if there was an error - // during testing we don't want to just succeed (we may not have - // tested something), so fail. - // - // This should realistically "never" happen, so don't try to make - // this a pretty error message. - panic!("I/O failure during tests: {:?}", e); - } + std::process::exit(1); } } @@ -691,7 +666,11 @@ impl TestCollector { /// /// This always inspects _all_ test files in the suite (e.g. all 17k+ ui tests), /// regardless of whether any filters/tests were specified on the command-line, -/// because filtering is handled later by libtest. +/// because filtering is handled later by code that was copied from libtest. +/// +/// FIXME(Zalathar): Now that we no longer rely on libtest, try to overhaul +/// test discovery to take into account the filters/tests specified on the +/// command-line, instead of having to enumerate everything. pub(crate) fn collect_and_make_tests(config: Arc) -> Vec { debug!("making tests from {}", config.src_test_suite_root); let common_inputs_stamp = common_inputs_stamp(&config); @@ -805,7 +784,7 @@ fn modified_tests(config: &Config, dir: &Utf8Path) -> Result, S } /// Recursively scans a directory to find test files and create test structures -/// that will be handed over to libtest. +/// that will be handed over to the executor. fn collect_tests_from_dir( cx: &TestCollectorCx, dir: &Utf8Path, @@ -871,7 +850,7 @@ fn collect_tests_from_dir( if is_test(file_name) && (!cx.config.only_modified || cx.modified_tests.contains(&file_path)) { - // We found a test file, so create the corresponding libtest structures. + // We found a test file, so create the corresponding test structures. debug!(%file_path, "found test file"); // Record the stem of the test file, to check for overlaps later. @@ -915,7 +894,7 @@ pub fn is_test(file_name: &str) -> bool { } /// For a single test file, creates one or more test structures (one per revision) that can be -/// handed over to libtest to run, possibly in parallel. +/// handed over to the executor to run, possibly in parallel. fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &TestPaths) { // For run-make tests, each "test file" is actually a _directory_ containing an `rmake.rs`. But // for the purposes of directive parsing, we want to look at that recipe file, not the directory @@ -929,7 +908,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te // Scan the test file to discover its revisions, if any. let early_props = EarlyProps::from_file(&cx.config, &test_path); - // Normally we create one libtest structure per revision, with two exceptions: + // Normally we create one structure per revision, with two exceptions: // - If a test doesn't use revisions, create a dummy revision (None) so that // the test can still run. // - Incremental tests inherently can't run their revisions in parallel, so @@ -944,12 +923,12 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te // For each revision (or the sole dummy revision), create and append a // `CollectedTest` that can be handed over to the test executor. collector.tests.extend(revisions.into_iter().map(|revision| { - // Create a test name and description to hand over to libtest. + // Create a test name and description to hand over to the executor. let src_file = fs::File::open(&test_path).expect("open test file to parse ignores"); let test_name = make_test_name(&cx.config, testpaths, revision); - // Create a libtest description for the test/revision. + // Create a description struct for the test/revision. // This is where `ignore-*`/`only-*`/`needs-*` directives are handled, - // because they need to set the libtest ignored flag. + // because they historically needed to set the libtest ignored flag. let mut desc = make_test_description( &cx.config, &cx.cache, @@ -961,10 +940,12 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te ); // If a test's inputs haven't changed since the last time it ran, - // mark it as ignored so that libtest will skip it. + // mark it as ignored so that the executor will skip it. if !cx.config.force_rerun && is_up_to_date(cx, testpaths, &early_props, revision) { desc.ignore = true; // Keep this in sync with the "up-to-date" message detected by bootstrap. + // FIXME(Zalathar): Now that we are no longer tied to libtest, we could + // find a less fragile way to communicate this status to bootstrap. desc.ignore_message = Some("up-to-date".into()); } @@ -1104,7 +1085,7 @@ impl Stamp { } } -/// Creates a name for this test/revision that can be handed over to libtest. +/// Creates a name for this test/revision that can be handed over to the executor. fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> String { // Print the name of the file, relative to the sources root. let path = testpaths.file.strip_prefix(&config.src_root).unwrap(); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index c533293e791..3a05b242519 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2222,7 +2222,7 @@ impl<'test> TestCx<'test> { .env("PAGER", "") .stdin(File::open(&diff_filename).unwrap()) // Capture output and print it explicitly so it will in turn be - // captured by libtest. + // captured by output-capture. .output() .unwrap(); assert!(output.status.success()); diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index c8d5190c039..8a0e45cf8ca 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -308,7 +308,7 @@ impl TestCx<'_> { let stdout = String::from_utf8_lossy(&stdout).into_owned(); let stderr = String::from_utf8_lossy(&stderr).into_owned(); // This conditions on `status.success()` so we don't print output twice on error. - // NOTE: this code is called from a libtest thread, so it's hidden by default unless --nocapture is passed. + // NOTE: this code is called from an executor thread, so it's hidden by default unless --no-capture is passed. self.dump_output(status.success(), &cmd.get_program().to_string_lossy(), &stdout, &stderr); if !status.success() { let res = ProcRes { status, stdout, stderr, truncated, cmdline: format!("{:?}", cmd) }; -- cgit 1.4.1-3-g733a5 From e06cd9f2c82c5bb3999eafda7abe2b1951384f78 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Wed, 27 Aug 2025 16:15:08 +0300 Subject: `const`ify (the unstable) `str::as_str` --- library/core/src/str/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 1b6e84175b9..1a055a0a5ad 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -3072,7 +3072,7 @@ impl str { /// for example references to `Box` or `Arc`. #[inline] #[unstable(feature = "str_as_str", issue = "130366")] - pub fn as_str(&self) -> &str { + pub const fn as_str(&self) -> &str { self } } -- cgit 1.4.1-3-g733a5 From bf6e99d7348270a3f43fb180c7de1c6e15bcba2b Mon Sep 17 00:00:00 2001 From: Jana Dönszelmann Date: Wed, 27 Aug 2025 17:40:23 +0200 Subject: add doc-hidden to exports in attribute prelude --- compiler/rustc_attr_parsing/src/attributes/prelude.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/prelude.rs b/compiler/rustc_attr_parsing/src/attributes/prelude.rs index 2bcdee55c75..6aef7e7a67b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prelude.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prelude.rs @@ -1,20 +1,30 @@ -// parsing // templates +#[doc(hidden)] pub(super) use rustc_feature::{AttributeTemplate, template}; // data structures +#[doc(hidden)] pub(super) use rustc_hir::attrs::AttributeKind; +#[doc(hidden)] pub(super) use rustc_hir::lints::AttributeLintKind; +#[doc(hidden)] pub(super) use rustc_hir::{MethodKind, Target}; +#[doc(hidden)] pub(super) use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; +#[doc(hidden)] pub(super) use thin_vec::ThinVec; +#[doc(hidden)] pub(super) use crate::attributes::{ AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, }; // contexts +#[doc(hidden)] pub(super) use crate::context::{AcceptContext, FinalizeContext, Stage}; +#[doc(hidden)] pub(super) use crate::parser::*; // target checking +#[doc(hidden)] pub(super) use crate::target_checking::Policy::{Allow, Error, Warn}; +#[doc(hidden)] pub(super) use crate::target_checking::{ALL_TARGETS, AllowedTargets}; -- cgit 1.4.1-3-g733a5 From 5f39612e7af612f41cf2e78c254e06ad7e4c32e0 Mon Sep 17 00:00:00 2001 From: winstonallo Date: Wed, 13 Aug 2025 17:52:51 +0200 Subject: Add assembly tests verifying the functionality of `-Zreg-struct-return` for structs of different sizes. This test covers: * The callee side, making sure that the structs are correctly loaded into registers when `-Zreg-struct-return` is enabled * The caller side, making sure that callers do receive returned structs in registers when `-Zreg-struct-return` is enabled Structs of the size of up to 2 registers (8 bytes) can be returned in registers in x86_32. Therefore, the tests are done with 3 different struct sizes: * 2 bytes (register returns should happen) * 8 bytes (last value where register returns should happen) * 12 bytes (register returns should not happen even when `-Zreg-struct-return` is enabled) --- tests/assembly-llvm/reg-struct-return.rs | 143 +++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 tests/assembly-llvm/reg-struct-return.rs diff --git a/tests/assembly-llvm/reg-struct-return.rs b/tests/assembly-llvm/reg-struct-return.rs new file mode 100644 index 00000000000..b251d791d51 --- /dev/null +++ b/tests/assembly-llvm/reg-struct-return.rs @@ -0,0 +1,143 @@ +//! Tests that -Zreg-struct-return changes ABI for small struct returns +//! from hidden-pointer convention to register-return on x86_32. +//! This test covers: +//! * Callee side, verifying that the structs are correctly loaded into registers when +//! `-Zreg-struct-return` is activated +//! * Caller side, verifying callers do receive returned structs in registers when +//! `-Zreg-struct-return` is activated +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: -O --target=i686-unknown-linux-gnu -Crelocation-model=static +//@ revisions: WITH WITHOUT +//@[WITH] compile-flags: -Zreg-struct-return +//@ needs-llvm-components: x86 + +#![feature(no_core)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +// Verifies ABI changes for small structs, where both fields fit into one register. +// WITH is expected to use register return, WITHOUT should use hidden pointer. +mod Small { + struct SmallStruct { + a: i8, + b: i8, + } + + unsafe extern "C" { + fn small() -> SmallStruct; + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn small_callee() -> SmallStruct { + // (42 << 8) | 42 = 10794 + + // WITH-LABEL: small_callee + // WITH: movw $10794, %ax + // WITH: retl + + // WITHOUT-LABEL: small_callee + // WITHOUT: movl 4(%esp), %e{{.*}} + // WITHOUT: movw $10794, (%e{{.*}}) + // WITHOUT: retl $4 + SmallStruct { a: 42, b: 42 } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn small_caller(dst: &mut SmallStruct) { + // WITH-LABEL: small_caller + // WITH: calll small + // WITH: movw %ax, (%e{{.*}}) + + // WITHOUT-LABEL: small_caller + // WITHOUT: calll small + // WITHOUT: movzwl {{.*}}(%esp), %e[[TMP:..]] + // WITHOUT: movw %[[TMP]], (%e{{..}}) + *dst = small(); + } +} + +// Verifies ABI changes for a struct of size 8, which is the maximum size +// for reg-struct-return. +// WITH is expected to still use register return, WITHOUT should use hidden +// pointer. +mod Pivot { + struct PivotStruct { + a: i32, + b: i32, + } + + unsafe extern "C" { + fn pivot() -> PivotStruct; + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn pivot_callee() -> PivotStruct { + // WITH-LABEL: pivot_callee + // WITH: movl $42, %e{{.*}} + // WITH: movl $42, %e{{.*}} + // WITH: retl + + // WITHOUT-LABEL: pivot_callee + // WITHOUT: movl 4(%esp), %e{{.*}} + // WITHOUT-DAG: movl $42, (%e{{.*}}) + // WITHOUT-DAG: movl $42, 4(%e{{.*}}) + // WITHOUT: retl $4 + PivotStruct { a: 42, b: 42 } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn pivot_caller(dst: &mut PivotStruct) { + // WITH-LABEL: pivot_caller + // WITH: calll pivot + // WITH-DAG: movl %e{{.*}}, 4(%e{{.*}}) + // WITH-DAG: movl %e{{.*}}, (%e{{.*}}) + + // WITHOUT-LABEL: pivot_caller + // WITHOUT: calll pivot + // WITHOUT: movsd {{.*}}(%esp), %[[TMP:xmm.]] + // WITHOUT: movsd %[[TMP]], (%e{{..}}) + *dst = pivot(); + } +} + +// Verifies ABI changes for a struct of size 12, which is larger than the +// maximum size for reg-struct-return (8 bytes). +// Here, the hidden pointer convention should be used even when `-Zreg-struct-return` is set. +mod Large { + struct LargeStruct { + a: i32, + b: i32, + c: i32, + } + + unsafe extern "C" { + fn large() -> LargeStruct; + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn large_callee() -> LargeStruct { + // CHECK-LABEL: large_callee + // CHECK: movl 4(%esp), %e{{.*}} + // CHECK-DAG: movl $42, (%e{{.*}}) + // CHECK-DAG: movl $42, 4(%e{{.*}}) + // CHECK-DAG: movl $42, 8(%e{{.*}}) + // CHECK: retl $4 + LargeStruct { a: 42, b: 42, c: 42 } + } + + #[unsafe(no_mangle)] + pub unsafe extern "C" fn large_caller(dst: &mut LargeStruct) { + // CHECK-LABEL: large_caller + // CHECK: calll large + // CHECK-DAG: movl {{.*}}(%esp), %[[TMP1:e..]] + // CHECK-DAG: movl %[[TMP1]], {{.*}}(%e{{..}}) + // CHECK-DAG: movsd {{.*}}(%esp), %[[TMP2:xmm.]] + // CHECK-DAG: movsd %[[TMP2]], {{.*}}(%e{{..}}) + *dst = large(); + } +} -- cgit 1.4.1-3-g733a5 From aab5e0bf1fc26eb96ab6f694f05074a80d9de5f9 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 16 Jul 2025 13:45:36 +0200 Subject: Move `NativeLibKind` from `rustc_session` to `rustc_hir` --- Cargo.lock | 1 + compiler/rustc_attr_parsing/Cargo.toml | 1 + compiler/rustc_attr_parsing/src/lib.rs | 1 + .../rustc_codegen_ssa/src/back/link/raw_dylib.rs | 2 +- compiler/rustc_codegen_ssa/src/common.rs | 3 +- compiler/rustc_hir/src/attrs/data_structures.rs | 103 +++++++++++++++++++++ compiler/rustc_interface/src/tests.rs | 3 +- compiler/rustc_session/src/config/native_libs.rs | 3 +- compiler/rustc_session/src/cstore.rs | 24 +---- compiler/rustc_session/src/utils.rs | 64 +------------ 10 files changed, 116 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af7c24abd13..4f26f6db64c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3480,6 +3480,7 @@ dependencies = [ "rustc_parse", "rustc_session", "rustc_span", + "rustc_target", "thin-vec", ] diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index ba95b630b8c..8bfde43fd33 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -17,5 +17,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } thin-vec.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 4dd908cdc40..f51cc8c4e8b 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -79,6 +79,7 @@ // tidy-alphabetical-start #![allow(internal_features)] #![doc(rust_logo)] +#![feature(decl_macro)] #![feature(rustdoc_internals)] #![recursion_limit = "256"] // tidy-alphabetical-end diff --git a/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs index 509168b2cd2..9f42991d4c0 100644 --- a/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs +++ b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs @@ -7,9 +7,9 @@ use rustc_data_structures::base_n::{CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::stable_hasher::StableHasher; use rustc_hashes::Hash128; +use rustc_hir::attrs::NativeLibKind; use rustc_session::Session; use rustc_session::cstore::DllImport; -use rustc_session::utils::NativeLibKind; use rustc_span::Symbol; use crate::back::archive::ImportLibraryItem; diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index a6fd6c763ed..08e2f355953 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -1,10 +1,11 @@ #![allow(non_camel_case_types)] use rustc_hir::LangItem; +use rustc_hir::attrs::PeImportNameType; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_middle::{bug, mir, span_bug}; -use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType}; +use rustc_session::cstore::{DllCallingConvention, DllImport}; use rustc_span::Span; use rustc_target::spec::Target; diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 09da5772d23..1810ef2bdf9 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -248,6 +248,109 @@ impl IntoDiagArg for MirPhase { } } +/// Different ways that the PE Format can decorate a symbol name. +/// From +#[derive( + Copy, + Clone, + Debug, + Encodable, + Decodable, + HashStable_Generic, + PartialEq, + Eq, + PrintAttribute +)] +pub enum PeImportNameType { + /// IMPORT_ORDINAL + /// Uses the ordinal (i.e., a number) rather than the name. + Ordinal(u16), + /// Same as IMPORT_NAME + /// Name is decorated with all prefixes and suffixes. + Decorated, + /// Same as IMPORT_NAME_NOPREFIX + /// Prefix (e.g., the leading `_` or `@`) is skipped, but suffix is kept. + NoPrefix, + /// Same as IMPORT_NAME_UNDECORATE + /// Prefix (e.g., the leading `_` or `@`) and suffix (the first `@` and all + /// trailing characters) are skipped. + Undecorated, +} + +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Encodable, + Decodable, + PrintAttribute +)] +#[derive(HashStable_Generic)] +pub enum NativeLibKind { + /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) + Static { + /// Whether to bundle objects from static library into produced rlib + bundle: Option, + /// Whether to link static library without throwing any object files away + whole_archive: Option, + }, + /// Dynamic library (e.g. `libfoo.so` on Linux) + /// or an import library corresponding to a dynamic library (e.g. `foo.lib` on Windows/MSVC). + Dylib { + /// Whether the dynamic library will be linked only if it satisfies some undefined symbols + as_needed: Option, + }, + /// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library. + /// On Linux, it refers to a generated shared library stub. + RawDylib, + /// A macOS-specific kind of dynamic libraries. + Framework { + /// Whether the framework will be linked only if it satisfies some undefined symbols + as_needed: Option, + }, + /// Argument which is passed to linker, relative order with libraries and other arguments + /// is preserved + LinkArg, + + /// Module imported from WebAssembly + WasmImportModule, + + /// The library kind wasn't specified, `Dylib` is currently used as a default. + Unspecified, +} + +impl NativeLibKind { + pub fn has_modifiers(&self) -> bool { + match self { + NativeLibKind::Static { bundle, whole_archive } => { + bundle.is_some() || whole_archive.is_some() + } + NativeLibKind::Dylib { as_needed } | NativeLibKind::Framework { as_needed } => { + as_needed.is_some() + } + NativeLibKind::RawDylib + | NativeLibKind::Unspecified + | NativeLibKind::LinkArg + | NativeLibKind::WasmImportModule => false, + } + } + + pub fn is_statically_included(&self) -> bool { + matches!(self, NativeLibKind::Static { .. }) + } + + pub fn is_dllimport(&self) -> bool { + matches!( + self, + NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified + ) + } +} /// Represents parsed *built-in* inert attributes. /// /// ## Overview diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 4425877308a..7730bddc0f1 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -8,6 +8,7 @@ use rustc_abi::Align; use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, registry}; +use rustc_hir::attrs::NativeLibKind; use rustc_session::config::{ AutoDiff, BranchProtection, CFGuard, Cfg, CollapseMacroDebuginfo, CoverageLevel, CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, @@ -20,7 +21,7 @@ use rustc_session::config::{ }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; -use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; +use rustc_session::utils::{CanonicalizedPath, NativeLib}; use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, build_session, getopts}; use rustc_span::edition::{DEFAULT_EDITION, Edition}; use rustc_span::source_map::{RealFileLoader, SourceMapInputs}; diff --git a/compiler/rustc_session/src/config/native_libs.rs b/compiler/rustc_session/src/config/native_libs.rs index f1f0aeb5e59..50a0593f887 100644 --- a/compiler/rustc_session/src/config/native_libs.rs +++ b/compiler/rustc_session/src/config/native_libs.rs @@ -5,10 +5,11 @@ //! which have their own parser in `rustc_metadata`.) use rustc_feature::UnstableFeatures; +use rustc_hir::attrs::NativeLibKind; use crate::EarlyDiagCtxt; use crate::config::UnstableOptions; -use crate::utils::{NativeLib, NativeLibKind}; +use crate::utils::NativeLib; #[cfg(test)] mod tests; diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 4cfc745dec2..30f6256a75e 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -6,8 +6,8 @@ use std::any::Any; use std::path::PathBuf; use rustc_abi::ExternAbi; -use rustc_ast as ast; use rustc_data_structures::sync::{self, AppendOnlyIndexVec, FreezeLock}; +use rustc_hir::attrs::{CfgEntry, NativeLibKind, PeImportNameType}; use rustc_hir::def_id::{ CrateNum, DefId, LOCAL_CRATE, LocalDefId, StableCrateId, StableCrateIdMap, }; @@ -16,7 +16,6 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::{Span, Symbol}; use crate::search_paths::PathKind; -use crate::utils::NativeLibKind; // lonely orphan structs and enums looking for a better home @@ -72,7 +71,7 @@ pub struct NativeLib { pub name: Symbol, /// If packed_bundled_libs enabled, actual filename of library is stored. pub filename: Option, - pub cfg: Option, + pub cfg: Option, pub foreign_module: Option, pub verbatim: Option, pub dll_imports: Vec, @@ -88,25 +87,6 @@ impl NativeLib { } } -/// Different ways that the PE Format can decorate a symbol name. -/// From -#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic, PartialEq, Eq)] -pub enum PeImportNameType { - /// IMPORT_ORDINAL - /// Uses the ordinal (i.e., a number) rather than the name. - Ordinal(u16), - /// Same as IMPORT_NAME - /// Name is decorated with all prefixes and suffixes. - Decorated, - /// Same as IMPORT_NAME_NOPREFIX - /// Prefix (e.g., the leading `_` or `@`) is skipped, but suffix is kept. - NoPrefix, - /// Same as IMPORT_NAME_UNDECORATE - /// Prefix (e.g., the leading `_` or `@`) and suffix (the first `@` and all - /// trailing characters) are skipped. - Undecorated, -} - #[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)] pub struct DllImport { pub name: Symbol, diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index e9ddd66b5e8..c64d9bc1efe 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -3,6 +3,7 @@ use std::sync::OnceLock; use rustc_data_structures::profiling::VerboseTimingGuard; use rustc_fs_util::try_canonicalize; +use rustc_hir::attrs::NativeLibKind; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use crate::session::Session; @@ -17,69 +18,6 @@ impl Session { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] -#[derive(HashStable_Generic)] -pub enum NativeLibKind { - /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) - Static { - /// Whether to bundle objects from static library into produced rlib - bundle: Option, - /// Whether to link static library without throwing any object files away - whole_archive: Option, - }, - /// Dynamic library (e.g. `libfoo.so` on Linux) - /// or an import library corresponding to a dynamic library (e.g. `foo.lib` on Windows/MSVC). - Dylib { - /// Whether the dynamic library will be linked only if it satisfies some undefined symbols - as_needed: Option, - }, - /// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library. - /// On Linux, it refers to a generated shared library stub. - RawDylib, - /// A macOS-specific kind of dynamic libraries. - Framework { - /// Whether the framework will be linked only if it satisfies some undefined symbols - as_needed: Option, - }, - /// Argument which is passed to linker, relative order with libraries and other arguments - /// is preserved - LinkArg, - - /// Module imported from WebAssembly - WasmImportModule, - - /// The library kind wasn't specified, `Dylib` is currently used as a default. - Unspecified, -} - -impl NativeLibKind { - pub fn has_modifiers(&self) -> bool { - match self { - NativeLibKind::Static { bundle, whole_archive } => { - bundle.is_some() || whole_archive.is_some() - } - NativeLibKind::Dylib { as_needed } | NativeLibKind::Framework { as_needed } => { - as_needed.is_some() - } - NativeLibKind::RawDylib - | NativeLibKind::Unspecified - | NativeLibKind::LinkArg - | NativeLibKind::WasmImportModule => false, - } - } - - pub fn is_statically_included(&self) -> bool { - matches!(self, NativeLibKind::Static { .. }) - } - - pub fn is_dllimport(&self) -> bool { - matches!( - self, - NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified - ) - } -} - #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] #[derive(HashStable_Generic)] pub struct NativeLib { -- cgit 1.4.1-3-g733a5 From e8d08b5416c0fd159388fe6cdd1a3b43dd759132 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 16 Jul 2025 13:46:08 +0200 Subject: Port the `#[link]` attribute to the new parser --- compiler/rustc_attr_parsing/messages.ftl | 52 +++ compiler/rustc_attr_parsing/src/attributes/cfg.rs | 2 +- .../src/attributes/link_attrs.rs | 419 ++++++++++++++++++++- compiler/rustc_attr_parsing/src/context.rs | 3 +- .../rustc_attr_parsing/src/session_diagnostics.rs | 94 +++++ compiler/rustc_codegen_ssa/src/back/link.rs | 7 +- compiler/rustc_codegen_ssa/src/lib.rs | 5 +- compiler/rustc_hir/src/attrs/data_structures.rs | 14 + compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_metadata/messages.ftl | 95 ----- compiler/rustc_metadata/src/errors.rs | 217 ----------- compiler/rustc_metadata/src/native_libs.rs | 335 ++-------------- compiler/rustc_passes/src/check_attr.rs | 8 +- compiler/rustc_span/src/symbol.rs | 10 + 14 files changed, 639 insertions(+), 623 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 8f24b51f1d9..b8a748563d5 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -195,3 +195,55 @@ attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"` attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) + +attr_parsing_as_needed_compatibility = + linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds + +attr_parsing_bundle_needs_static = + linking modifier `bundle` is only compatible with `static` linking kind + +attr_parsing_empty_link_name = + link name must not be empty + .label = empty link name + +attr_parsing_import_name_type_raw = + import name type can only be used with link kind `raw-dylib` + +attr_parsing_import_name_type_x86 = + import name type is only supported on x86 + +attr_parsing_incompatible_wasm_link = + `wasm_import_module` is incompatible with other arguments in `#[link]` attributes + +attr_parsing_invalid_link_modifier = + invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed + +attr_parsing_link_arg_unstable = + link kind `link-arg` is unstable + +attr_parsing_link_cfg_unstable = + link cfg is unstable + +attr_parsing_link_framework_apple = + link kind `framework` is only supported on Apple targets + +attr_parsing_link_requires_name = + `#[link]` attribute requires a `name = "string"` argument + .label = missing `name` argument + +attr_parsing_multiple_modifiers = + multiple `{$modifier}` modifiers in a single `modifiers` argument + +attr_parsing_multiple_renamings = + multiple renamings were specified for library `{$lib_name}` +attr_parsing_raw_dylib_no_nul = + link name must not contain NUL characters if link kind is `raw-dylib` + +attr_parsing_raw_dylib_elf_unstable = + link kind `raw-dylib` is unstable on ELF platforms + +attr_parsing_raw_dylib_only_windows = + link kind `raw-dylib` is only supported on Windows targets + +attr_parsing_whole_archive_needs_static = + linking modifier `whole-archive` is only compatible with `static` linking kind diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 695ee666476..70855611079 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -36,7 +36,7 @@ pub fn parse_cfg_attr<'c, S: Stage>( parse_cfg_entry(cx, single) } -fn parse_cfg_entry( +pub(crate) fn parse_cfg_entry( cx: &mut AcceptContext<'_, '_, S>, item: &MetaItemOrLitParser<'_>, ) -> Option { diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 5e4551ccd79..d4942e56f42 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -1,9 +1,21 @@ +use rustc_feature::Features; use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; -use rustc_hir::attrs::Linkage; +use rustc_hir::attrs::*; +use rustc_session::Session; +use rustc_session::parse::feature_err; +use rustc_span::kw; +use rustc_target::spec::BinaryFormat; use super::prelude::*; use super::util::parse_single_integer; -use crate::session_diagnostics::{LinkOrdinalOutOfRange, NullOnLinkSection}; +use crate::attributes::cfg::parse_cfg_entry; +use crate::fluent_generated; +use crate::session_diagnostics::{ + AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ImportNameTypeRaw, ImportNameTypeX86, + IncompatibleWasmLink, InvalidLinkModifier, LinkFrameworkApple, LinkOrdinalOutOfRange, + LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, + WholeArchiveNeedsStatic, +}; pub(crate) struct LinkNameParser; @@ -34,6 +46,409 @@ impl SingleAttributeParser for LinkNameParser { } } +pub(crate) struct LinkParser; + +impl CombineAttributeParser for LinkParser { + type Item = LinkEntry; + const PATH: &[Symbol] = &[sym::link]; + const CONVERT: ConvertFn = AttributeKind::Link; + const TEMPLATE: AttributeTemplate = template!(List: &[ + r#"name = "...""#, + r#"name = "...", kind = "dylib|static|...""#, + r#"name = "...", wasm_import_module = "...""#, + r#"name = "...", import_name_type = "decorated|noprefix|undecorated""#, + r#"name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated""#, + ], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute"); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` + + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator + 'c { + let mut result = None; + let Some(items) = args.list() else { + cx.expected_list(cx.attr_span); + return result; + }; + + let sess = cx.sess(); + let features = cx.features(); + + let mut name = None; + let mut kind = None; + let mut modifiers = None; + let mut cfg = None; + let mut wasm_import_module = None; + let mut import_name_type = None; + for item in items.mixed() { + let Some(item) = item.meta_item() else { + cx.unexpected_literal(item.span()); + continue; + }; + + let cont = match item.path().word().map(|ident| ident.name) { + Some(sym::name) => Self::parse_link_name(item, &mut name, cx), + Some(sym::kind) => Self::parse_link_kind(item, &mut kind, cx, sess, features), + Some(sym::modifiers) => Self::parse_link_modifiers(item, &mut modifiers, cx), + Some(sym::cfg) => Self::parse_link_cfg(item, &mut cfg, cx, sess, features), + Some(sym::wasm_import_module) => { + Self::parse_link_wasm_import_module(item, &mut wasm_import_module, cx) + } + Some(sym::import_name_type) => { + Self::parse_link_import_name_type(item, &mut import_name_type, cx) + } + _ => { + cx.expected_specific_argument_strings( + item.span(), + &[ + sym::name, + sym::kind, + sym::modifiers, + sym::cfg, + sym::wasm_import_module, + sym::import_name_type, + ], + ); + true + } + }; + if !cont { + return result; + } + } + + // Do this outside the above loop so we don't depend on modifiers coming after kinds + let mut verbatim = None; + if let Some((modifiers, span)) = modifiers { + for modifier in modifiers.as_str().split(',') { + let (modifier, value): (Symbol, bool) = match modifier.strip_prefix(&['+', '-']) { + Some(m) => (Symbol::intern(m), modifier.starts_with('+')), + None => { + cx.emit_err(InvalidLinkModifier { span }); + continue; + } + }; + + macro report_unstable_modifier($feature: ident) { + if !features.$feature() { + // FIXME: make this translatable + #[expect(rustc::untranslatable_diagnostic)] + feature_err( + sess, + sym::$feature, + span, + format!("linking modifier `{modifier}` is unstable"), + ) + .emit(); + } + } + let assign_modifier = |dst: &mut Option| { + if dst.is_some() { + cx.emit_err(MultipleModifiers { span, modifier }); + } else { + *dst = Some(value); + } + }; + match (modifier, &mut kind) { + (sym::bundle, Some(NativeLibKind::Static { bundle, .. })) => { + assign_modifier(bundle) + } + (sym::bundle, _) => { + cx.emit_err(BundleNeedsStatic { span }); + } + + (sym::verbatim, _) => assign_modifier(&mut verbatim), + + ( + sym::whole_dash_archive, + Some(NativeLibKind::Static { whole_archive, .. }), + ) => assign_modifier(whole_archive), + (sym::whole_dash_archive, _) => { + cx.emit_err(WholeArchiveNeedsStatic { span }); + } + + (sym::as_dash_needed, Some(NativeLibKind::Dylib { as_needed })) + | (sym::as_dash_needed, Some(NativeLibKind::Framework { as_needed })) => { + report_unstable_modifier!(native_link_modifiers_as_needed); + assign_modifier(as_needed) + } + (sym::as_dash_needed, _) => { + cx.emit_err(AsNeededCompatibility { span }); + } + + _ => { + cx.expected_specific_argument_strings( + span, + &[ + sym::bundle, + sym::verbatim, + sym::whole_dash_archive, + sym::as_dash_needed, + ], + ); + } + } + } + } + + if let Some((_, span)) = wasm_import_module { + if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() { + cx.emit_err(IncompatibleWasmLink { span }); + } + } + + if wasm_import_module.is_some() { + (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule)); + } + let Some((name, name_span)) = name else { + cx.emit_err(LinkRequiresName { span: cx.attr_span }); + return result; + }; + + // Do this outside of the loop so that `import_name_type` can be specified before `kind`. + if let Some((_, span)) = import_name_type { + if kind != Some(NativeLibKind::RawDylib) { + cx.emit_err(ImportNameTypeRaw { span }); + } + } + + if let Some(NativeLibKind::RawDylib) = kind + && name.as_str().contains('\0') + { + cx.emit_err(RawDylibNoNul { span: name_span }); + } + + result = Some(LinkEntry { + span: cx.attr_span, + kind: kind.unwrap_or(NativeLibKind::Unspecified), + name, + cfg, + verbatim, + import_name_type, + }); + result + } +} + +impl LinkParser { + fn parse_link_name( + item: &MetaItemParser<'_>, + name: &mut Option<(Symbol, Span)>, + cx: &mut AcceptContext<'_, '_, S>, + ) -> bool { + if name.is_some() { + cx.duplicate_key(item.span(), sym::name); + return true; + } + let Some(nv) = item.args().name_value() else { + cx.expected_name_value(item.span(), Some(sym::name)); + return false; + }; + let Some(link_name) = nv.value_as_str() else { + cx.expected_name_value(item.span(), Some(sym::name)); + return false; + }; + + if link_name.is_empty() { + cx.emit_err(EmptyLinkName { span: nv.value_span }); + } + *name = Some((link_name, nv.value_span)); + true + } + + fn parse_link_kind( + item: &MetaItemParser<'_>, + kind: &mut Option, + cx: &mut AcceptContext<'_, '_, S>, + sess: &Session, + features: &Features, + ) -> bool { + if kind.is_some() { + cx.duplicate_key(item.span(), sym::kind); + return true; + } + let Some(nv) = item.args().name_value() else { + cx.expected_name_value(item.span(), Some(sym::kind)); + return true; + }; + let Some(link_kind) = nv.value_as_str() else { + cx.expected_name_value(item.span(), Some(sym::kind)); + return true; + }; + + let link_kind = match link_kind { + kw::Static => NativeLibKind::Static { bundle: None, whole_archive: None }, + sym::dylib => NativeLibKind::Dylib { as_needed: None }, + sym::framework => { + if !sess.target.is_like_darwin { + cx.emit_err(LinkFrameworkApple { span: nv.value_span }); + } + NativeLibKind::Framework { as_needed: None } + } + sym::raw_dash_dylib => { + if sess.target.is_like_windows { + // raw-dylib is stable and working on Windows + } else if sess.target.binary_format == BinaryFormat::Elf && features.raw_dylib_elf() + { + // raw-dylib is unstable on ELF, but the user opted in + } else if sess.target.binary_format == BinaryFormat::Elf && sess.is_nightly_build() + { + feature_err( + sess, + sym::raw_dylib_elf, + nv.value_span, + fluent_generated::attr_parsing_raw_dylib_elf_unstable, + ) + .emit(); + } else { + cx.emit_err(RawDylibOnlyWindows { span: nv.value_span }); + } + + NativeLibKind::RawDylib + } + sym::link_dash_arg => { + if !features.link_arg_attribute() { + feature_err( + sess, + sym::link_arg_attribute, + nv.value_span, + fluent_generated::attr_parsing_link_arg_unstable, + ) + .emit(); + } + NativeLibKind::LinkArg + } + _kind => { + cx.expected_specific_argument_strings( + nv.value_span, + &[ + kw::Static, + sym::dylib, + sym::framework, + sym::raw_dash_dylib, + sym::link_dash_arg, + ], + ); + return true; + } + }; + *kind = Some(link_kind); + true + } + + fn parse_link_modifiers( + item: &MetaItemParser<'_>, + modifiers: &mut Option<(Symbol, Span)>, + cx: &mut AcceptContext<'_, '_, S>, + ) -> bool { + if modifiers.is_some() { + cx.duplicate_key(item.span(), sym::modifiers); + return true; + } + let Some(nv) = item.args().name_value() else { + cx.expected_name_value(item.span(), Some(sym::modifiers)); + return true; + }; + let Some(link_modifiers) = nv.value_as_str() else { + cx.expected_name_value(item.span(), Some(sym::modifiers)); + return true; + }; + *modifiers = Some((link_modifiers, nv.value_span)); + true + } + + fn parse_link_cfg( + item: &MetaItemParser<'_>, + cfg: &mut Option, + cx: &mut AcceptContext<'_, '_, S>, + sess: &Session, + features: &Features, + ) -> bool { + if cfg.is_some() { + cx.duplicate_key(item.span(), sym::cfg); + return true; + } + let Some(link_cfg) = item.args().list() else { + cx.expected_list(item.span()); + return true; + }; + let Some(link_cfg) = link_cfg.single() else { + cx.expected_single_argument(item.span()); + return true; + }; + if !features.link_cfg() { + feature_err( + sess, + sym::link_cfg, + item.span(), + fluent_generated::attr_parsing_link_cfg_unstable, + ) + .emit(); + } + *cfg = parse_cfg_entry(cx, link_cfg); + true + } + + fn parse_link_wasm_import_module( + item: &MetaItemParser<'_>, + wasm_import_module: &mut Option<(Symbol, Span)>, + cx: &mut AcceptContext<'_, '_, S>, + ) -> bool { + if wasm_import_module.is_some() { + cx.duplicate_key(item.span(), sym::wasm_import_module); + return true; + } + let Some(nv) = item.args().name_value() else { + cx.expected_name_value(item.span(), Some(sym::wasm_import_module)); + return true; + }; + let Some(link_wasm_import_module) = nv.value_as_str() else { + cx.expected_name_value(item.span(), Some(sym::wasm_import_module)); + return true; + }; + *wasm_import_module = Some((link_wasm_import_module, item.span())); + true + } + + fn parse_link_import_name_type( + item: &MetaItemParser<'_>, + import_name_type: &mut Option<(PeImportNameType, Span)>, + cx: &mut AcceptContext<'_, '_, S>, + ) -> bool { + if import_name_type.is_some() { + cx.duplicate_key(item.span(), sym::import_name_type); + return true; + } + let Some(nv) = item.args().name_value() else { + cx.expected_name_value(item.span(), Some(sym::import_name_type)); + return true; + }; + let Some(link_import_name_type) = nv.value_as_str() else { + cx.expected_name_value(item.span(), Some(sym::import_name_type)); + return true; + }; + if cx.sess().target.arch != "x86" { + cx.emit_err(ImportNameTypeX86 { span: item.span() }); + return true; + } + + let link_import_name_type = match link_import_name_type { + sym::decorated => PeImportNameType::Decorated, + sym::noprefix => PeImportNameType::NoPrefix, + sym::undecorated => PeImportNameType::Undecorated, + _ => { + cx.expected_specific_argument_strings( + item.span(), + &[sym::decorated, sym::noprefix, sym::undecorated], + ); + return true; + } + }; + *import_name_type = Some((link_import_name_type, item.span())); + true + } +} + pub(crate) struct LinkSectionParser; impl SingleAttributeParser for LinkSectionParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b16ef7edd64..7f5b810f244 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -30,7 +30,7 @@ use crate::attributes::dummy::DummyParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::link_attrs::{ ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser, - LinkSectionParser, LinkageParser, StdInternalSymbolParser, + LinkParser, LinkSectionParser, LinkageParser, StdInternalSymbolParser, }; use crate::attributes::lint_helpers::{ AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser, @@ -162,6 +162,7 @@ attribute_parsers!( Combine, Combine, Combine, + Combine, Combine, Combine, Combine, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index a639b55e81f..a9dee23bf6a 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -836,3 +836,97 @@ pub(crate) struct InvalidAttrStyle { pub target_span: Option, pub target: Target, } + +#[derive(Diagnostic)] +#[diag(attr_parsing_empty_link_name, code = E0454)] +pub(crate) struct EmptyLinkName { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_link_framework_apple, code = E0455)] +pub(crate) struct LinkFrameworkApple { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_incompatible_wasm_link)] +pub(crate) struct IncompatibleWasmLink { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_link_requires_name, code = E0459)] +pub(crate) struct LinkRequiresName { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_raw_dylib_no_nul)] +pub(crate) struct RawDylibNoNul { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_raw_dylib_only_windows, code = E0455)] +pub(crate) struct RawDylibOnlyWindows { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_invalid_link_modifier)] +pub(crate) struct InvalidLinkModifier { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_multiple_modifiers)] +pub(crate) struct MultipleModifiers { + #[primary_span] + pub span: Span, + pub modifier: Symbol, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_import_name_type_x86)] +pub(crate) struct ImportNameTypeX86 { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_bundle_needs_static)] +pub(crate) struct BundleNeedsStatic { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_whole_archive_needs_static)] +pub(crate) struct WholeArchiveNeedsStatic { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_as_needed_compatibility)] +pub(crate) struct AsNeededCompatibility { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_import_name_type_raw)] +pub(crate) struct ImportNameTypeRaw { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index c3777f64e9e..19c919c0e4e 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -14,11 +14,13 @@ use itertools::Itertools; use regex::Regex; use rustc_arena::TypedArena; use rustc_ast::CRATE_NODE_ID; +use rustc_attr_parsing::{ShouldEmit, eval_config_entry}; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{DiagCtxtHandle, LintDiagnostic}; use rustc_fs_util::{TempDirBuilder, fix_windows_verbatim_for_gcc, try_canonicalize}; +use rustc_hir::attrs::NativeLibKind; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_macros::LintDiagnostic; use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file}; @@ -38,7 +40,6 @@ use rustc_session::config::{ use rustc_session::lint::builtin::LINKER_MESSAGES; use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; use rustc_session::search_paths::PathKind; -use rustc_session::utils::NativeLibKind; /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. use rustc_session::{Session, filesearch}; @@ -3019,7 +3020,9 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { - Some(ref cfg) => rustc_attr_parsing::cfg_matches(cfg, sess, CRATE_NODE_ID, None), + Some(ref cfg) => { + eval_config_entry(sess, cfg, CRATE_NODE_ID, None, ShouldEmit::ErrorsAndLints).as_bool() + } None => true, } } diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 23ed387a3ff..fe0500a5d4c 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -25,10 +25,10 @@ use std::io; use std::path::{Path, PathBuf}; use std::sync::Arc; -use rustc_ast as ast; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; use rustc_hir::CRATE_HIR_ID; +use rustc_hir::attrs::{CfgEntry, NativeLibKind}; use rustc_hir::def_id::CrateNum; use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_metadata::EncodedMetadata; @@ -45,7 +45,6 @@ use rustc_session::Session; use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT}; use rustc_session::cstore::{self, CrateSource}; use rustc_session::lint::builtin::LINKER_MESSAGES; -use rustc_session::utils::NativeLibKind; use rustc_span::Symbol; pub mod assert_module_sources; @@ -187,7 +186,7 @@ pub struct NativeLib { pub kind: NativeLibKind, pub name: Symbol, pub filename: Option, - pub cfg: Option, + pub cfg: Option, pub verbatim: bool, pub dll_imports: Vec, } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 1810ef2bdf9..dd5565d6f90 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -351,6 +351,17 @@ impl NativeLibKind { ) } } + +#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)] +pub struct LinkEntry { + pub span: Span, + pub kind: NativeLibKind, + pub name: Symbol, + pub cfg: Option, + pub verbatim: Option, + pub import_name_type: Option<(PeImportNameType, Span)>, +} + /// Represents parsed *built-in* inert attributes. /// /// ## Overview @@ -521,6 +532,9 @@ pub enum AttributeKind { /// Represents `#[inline]` and `#[rustc_force_inline]`. Inline(InlineAttr, Span), + /// Represents `#[link]`. + Link(ThinVec, Span), + /// Represents `#[link_name]`. LinkName { name: Symbol, span: Span }, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index e5329c104bb..3810bb6d003 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -50,6 +50,7 @@ impl AttributeKind { Fundamental { .. } => Yes, Ignore { .. } => No, Inline(..) => No, + Link(..) => No, LinkName { .. } => Yes, // Needed for rustdoc LinkOrdinal { .. } => No, LinkSection { .. } => Yes, // Needed for rustdoc diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 4d3e879a098..e104be2c466 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -1,6 +1,3 @@ -metadata_as_needed_compatibility = - linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds - metadata_async_drop_types_in_dependency = found async drop types in dependency `{$extern_crate}`, but async_drop feature is disabled for `{$local_crate}` .help = if async drop type will be dropped in a crate without `feature(async_drop)`, sync Drop will be used @@ -11,9 +8,6 @@ metadata_bad_panic_strategy = metadata_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `metadata` to stdout, but stdout is a tty -metadata_bundle_needs_static = - linking modifier `bundle` is only compatible with `static` linking kind - metadata_cannot_find_crate = can't find crate for `{$crate_name}`{$add_info} @@ -60,10 +54,6 @@ metadata_crate_not_panic_runtime = metadata_dl_error = {$path}{$err} -metadata_empty_link_name = - link name must not be empty - .label = empty link name - metadata_empty_renaming_target = an empty renaming target was specified for library `{$lib_name}` @@ -108,15 +98,6 @@ metadata_full_metadata_not_found = metadata_global_alloc_required = no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait -metadata_import_name_type_form = - import name type must be of the form `import_name_type = "string"` - -metadata_import_name_type_raw = - import name type can only be used with link kind `raw-dylib` - -metadata_import_name_type_x86 = - import name type is only supported on x86 - metadata_incompatible_panic_in_drop_strategy = the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}` @@ -143,15 +124,10 @@ metadata_incompatible_target_modifiers_r_missed = mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}` .note = `{$flag_name_prefixed}={$local_value}` in this crate is incompatible with unset `{$flag_name_prefixed}` in dependency `{$extern_crate}` .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely -metadata_incompatible_wasm_link = - `wasm_import_module` is incompatible with other arguments in `#[link]` attributes metadata_install_missing_components = maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview` -metadata_invalid_link_modifier = - invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed - metadata_invalid_meta_files = found invalid metadata files for crate `{$crate_name}`{$add_info} @@ -164,67 +140,18 @@ metadata_lib_framework_apple = metadata_lib_required = crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form -metadata_link_arg_unstable = - link kind `link-arg` is unstable - -metadata_link_cfg_form = - link cfg must be of the form `cfg(/* predicate */)` - -metadata_link_cfg_single_predicate = - link cfg must have a single predicate argument - -metadata_link_cfg_unstable = - link cfg is unstable - -metadata_link_framework_apple = - link kind `framework` is only supported on Apple targets - -metadata_link_kind_form = - link kind must be of the form `kind = "string"` - -metadata_link_modifiers_form = - link modifiers must be of the form `modifiers = "string"` - -metadata_link_name_form = - link name must be of the form `name = "string"` - metadata_link_ordinal_raw_dylib = `#[link_ordinal]` is only supported if link kind is `raw-dylib` -metadata_link_requires_name = - `#[link]` attribute requires a `name = "string"` argument - .label = missing `name` argument - metadata_missing_native_library = could not find native static library `{$libname}`, perhaps an -L flag is missing? metadata_multiple_candidates = multiple candidates for `{$flavor}` dependency `{$crate_name}` found -metadata_multiple_cfgs = - multiple `cfg` arguments in a single `#[link]` attribute - -metadata_multiple_import_name_type = - multiple `import_name_type` arguments in a single `#[link]` attribute - -metadata_multiple_kinds_in_link = - multiple `kind` arguments in a single `#[link]` attribute - -metadata_multiple_link_modifiers = - multiple `modifiers` arguments in a single `#[link]` attribute - -metadata_multiple_modifiers = - multiple `{$modifier}` modifiers in a single `modifiers` argument - -metadata_multiple_names_in_link = - multiple `name` arguments in a single `#[link]` attribute - metadata_multiple_renamings = multiple renamings were specified for library `{$lib_name}` -metadata_multiple_wasm_import = - multiple `wasm_import_module` arguments in a single `#[link]` attribute - metadata_newer_crate_version = found possibly newer version of crate `{$crate_name}`{$add_info} .note = perhaps that crate needs to be recompiled? @@ -263,15 +190,6 @@ metadata_prev_alloc_error_handler = metadata_prev_global_alloc = previous global allocator defined here -metadata_raw_dylib_elf_unstable = - link kind `raw-dylib` is unstable on ELF platforms - -metadata_raw_dylib_no_nul = - link name must not contain NUL characters if link kind is `raw-dylib` - -metadata_raw_dylib_only_windows = - link kind `raw-dylib` is only supported on Windows targets - metadata_raw_dylib_unsupported_abi = ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture @@ -307,19 +225,6 @@ metadata_target_not_installed = metadata_two_panic_runtimes = cannot link together two panic runtimes: {$prev_name} and {$cur_name} -metadata_unexpected_link_arg = - unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type - -metadata_unknown_import_name_type = - unknown import name type `{$import_name_type}`, expected one of: decorated, noprefix, undecorated - -metadata_unknown_link_kind = - unknown link kind `{$kind}`, expected one of: static, dylib, framework, raw-dylib, link-arg - .label = unknown link kind - -metadata_unknown_link_modifier = - unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed - metadata_unknown_target_modifier_unsafe_allowed = unknown target modifier `{$flag_name}`, requested by `-Cunsafe-allow-abi-mismatch={$flag_name}` metadata_wasm_c_abi = diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 0332dba1077..e5a4fd48353 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -83,187 +83,6 @@ pub struct IncompatiblePanicInDropStrategy { pub desired_strategy: PanicStrategy, } -#[derive(Diagnostic)] -#[diag(metadata_multiple_names_in_link)] -pub struct MultipleNamesInLink { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_multiple_kinds_in_link)] -pub struct MultipleKindsInLink { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_link_name_form)] -pub struct LinkNameForm { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_link_kind_form)] -pub struct LinkKindForm { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_link_modifiers_form)] -pub struct LinkModifiersForm { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_link_cfg_form)] -pub struct LinkCfgForm { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_wasm_import_form)] -pub struct WasmImportForm { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_empty_link_name, code = E0454)] -pub struct EmptyLinkName { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_link_framework_apple, code = E0455)] -pub struct LinkFrameworkApple { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_raw_dylib_only_windows, code = E0455)] -pub struct RawDylibOnlyWindows { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_unknown_link_kind, code = E0458)] -pub struct UnknownLinkKind<'a> { - #[primary_span] - #[label] - pub span: Span, - pub kind: &'a str, -} - -#[derive(Diagnostic)] -#[diag(metadata_multiple_link_modifiers)] -pub struct MultipleLinkModifiers { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_multiple_cfgs)] -pub struct MultipleCfgs { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_link_cfg_single_predicate)] -pub struct LinkCfgSinglePredicate { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_multiple_wasm_import)] -pub struct MultipleWasmImport { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_unexpected_link_arg)] -pub struct UnexpectedLinkArg { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_invalid_link_modifier)] -pub struct InvalidLinkModifier { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_multiple_modifiers)] -pub struct MultipleModifiers<'a> { - #[primary_span] - pub span: Span, - pub modifier: &'a str, -} - -#[derive(Diagnostic)] -#[diag(metadata_bundle_needs_static)] -pub struct BundleNeedsStatic { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_whole_archive_needs_static)] -pub struct WholeArchiveNeedsStatic { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_as_needed_compatibility)] -pub struct AsNeededCompatibility { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_unknown_link_modifier)] -pub struct UnknownLinkModifier<'a> { - #[primary_span] - pub span: Span, - pub modifier: &'a str, -} - -#[derive(Diagnostic)] -#[diag(metadata_incompatible_wasm_link)] -pub struct IncompatibleWasmLink { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_link_requires_name, code = E0459)] -pub struct LinkRequiresName { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_raw_dylib_no_nul)] -pub struct RawDylibNoNul { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(metadata_link_ordinal_raw_dylib)] pub struct LinkOrdinalRawDylib { @@ -706,42 +525,6 @@ pub struct LibFilenameForm<'a> { pub dll_suffix: &'a str, } -#[derive(Diagnostic)] -#[diag(metadata_multiple_import_name_type)] -pub struct MultipleImportNameType { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_import_name_type_form)] -pub struct ImportNameTypeForm { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_import_name_type_x86)] -pub struct ImportNameTypeX86 { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(metadata_unknown_import_name_type)] -pub struct UnknownImportNameType<'a> { - #[primary_span] - pub span: Span, - pub import_name_type: &'a str, -} - -#[derive(Diagnostic)] -#[diag(metadata_import_name_type_raw)] -pub struct ImportNameTypeRaw { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(metadata_wasm_c_abi)] pub(crate) struct WasmCAbi { diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 63f1b51df1c..82738c68c59 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -3,25 +3,21 @@ use std::path::{Path, PathBuf}; use rustc_abi::ExternAbi; use rustc_ast::CRATE_NODE_ID; -use rustc_attr_parsing as attr; +use rustc_attr_parsing::{ShouldEmit, eval_config_entry}; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::attrs::AttributeKind; +use rustc_hir::attrs::{AttributeKind, NativeLibKind, PeImportNameType}; use rustc_hir::find_attr; use rustc_middle::query::LocalCrate; use rustc_middle::ty::{self, List, Ty, TyCtxt}; use rustc_session::Session; use rustc_session::config::CrateType; -use rustc_session::cstore::{ - DllCallingConvention, DllImport, ForeignModule, NativeLib, PeImportNameType, -}; -use rustc_session::parse::feature_err; +use rustc_session::cstore::{DllCallingConvention, DllImport, ForeignModule, NativeLib}; use rustc_session::search_paths::PathKind; -use rustc_session::utils::NativeLibKind; +use rustc_span::Symbol; use rustc_span::def_id::{DefId, LOCAL_CRATE}; -use rustc_span::{Symbol, sym}; use rustc_target::spec::{BinaryFormat, LinkSelfContainedComponents}; -use crate::{errors, fluent_generated}; +use crate::errors; /// The fallback directories are passed to linker, but not used when rustc does the search, /// because in the latter case the set of fallback directories cannot always be determined @@ -192,7 +188,9 @@ pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { - Some(ref cfg) => attr::cfg_matches(cfg, sess, CRATE_NODE_ID, None), + Some(ref cfg) => { + eval_config_entry(sess, cfg, CRATE_NODE_ID, None, ShouldEmit::ErrorsAndLints).as_bool() + } None => true, } } @@ -213,289 +211,23 @@ impl<'tcx> Collector<'tcx> { return; } - // Process all of the #[link(..)]-style arguments - let features = self.tcx.features(); - - for m in self.tcx.get_attrs(def_id, sym::link) { - let Some(items) = m.meta_item_list() else { - continue; - }; - - let mut name = None; - let mut kind = None; - let mut modifiers = None; - let mut cfg = None; - let mut wasm_import_module = None; - let mut import_name_type = None; - for item in items.iter() { - match item.name() { - Some(sym::name) => { - if name.is_some() { - sess.dcx().emit_err(errors::MultipleNamesInLink { span: item.span() }); - continue; - } - let Some(link_name) = item.value_str() else { - sess.dcx().emit_err(errors::LinkNameForm { span: item.span() }); - continue; - }; - let span = item.name_value_literal_span().unwrap(); - if link_name.is_empty() { - sess.dcx().emit_err(errors::EmptyLinkName { span }); - } - name = Some((link_name, span)); - } - Some(sym::kind) => { - if kind.is_some() { - sess.dcx().emit_err(errors::MultipleKindsInLink { span: item.span() }); - continue; - } - let Some(link_kind) = item.value_str() else { - sess.dcx().emit_err(errors::LinkKindForm { span: item.span() }); - continue; - }; - - let span = item.name_value_literal_span().unwrap(); - let link_kind = match link_kind.as_str() { - "static" => NativeLibKind::Static { bundle: None, whole_archive: None }, - "dylib" => NativeLibKind::Dylib { as_needed: None }, - "framework" => { - if !sess.target.is_like_darwin { - sess.dcx().emit_err(errors::LinkFrameworkApple { span }); - } - NativeLibKind::Framework { as_needed: None } - } - "raw-dylib" => { - if sess.target.is_like_windows { - // raw-dylib is stable and working on Windows - } else if sess.target.binary_format == BinaryFormat::Elf - && features.raw_dylib_elf() - { - // raw-dylib is unstable on ELF, but the user opted in - } else if sess.target.binary_format == BinaryFormat::Elf - && sess.is_nightly_build() - { - feature_err( - sess, - sym::raw_dylib_elf, - span, - fluent_generated::metadata_raw_dylib_elf_unstable, - ) - .emit(); - } else { - sess.dcx().emit_err(errors::RawDylibOnlyWindows { span }); - } - - NativeLibKind::RawDylib - } - "link-arg" => { - if !features.link_arg_attribute() { - feature_err( - sess, - sym::link_arg_attribute, - span, - fluent_generated::metadata_link_arg_unstable, - ) - .emit(); - } - NativeLibKind::LinkArg - } - kind => { - sess.dcx().emit_err(errors::UnknownLinkKind { span, kind }); - continue; - } - }; - kind = Some(link_kind); - } - Some(sym::modifiers) => { - if modifiers.is_some() { - sess.dcx() - .emit_err(errors::MultipleLinkModifiers { span: item.span() }); - continue; - } - let Some(link_modifiers) = item.value_str() else { - sess.dcx().emit_err(errors::LinkModifiersForm { span: item.span() }); - continue; - }; - modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap())); - } - Some(sym::cfg) => { - if cfg.is_some() { - sess.dcx().emit_err(errors::MultipleCfgs { span: item.span() }); - continue; - } - let Some(link_cfg) = item.meta_item_list() else { - sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() }); - continue; - }; - let [link_cfg] = link_cfg else { - sess.dcx() - .emit_err(errors::LinkCfgSinglePredicate { span: item.span() }); - continue; - }; - let Some(link_cfg) = link_cfg.meta_item_or_bool() else { - sess.dcx() - .emit_err(errors::LinkCfgSinglePredicate { span: item.span() }); - continue; - }; - if !features.link_cfg() { - feature_err( - sess, - sym::link_cfg, - item.span(), - fluent_generated::metadata_link_cfg_unstable, - ) - .emit(); - } - cfg = Some(link_cfg.clone()); - } - Some(sym::wasm_import_module) => { - if wasm_import_module.is_some() { - sess.dcx().emit_err(errors::MultipleWasmImport { span: item.span() }); - continue; - } - let Some(link_wasm_import_module) = item.value_str() else { - sess.dcx().emit_err(errors::WasmImportForm { span: item.span() }); - continue; - }; - wasm_import_module = Some((link_wasm_import_module, item.span())); - } - Some(sym::import_name_type) => { - if import_name_type.is_some() { - sess.dcx() - .emit_err(errors::MultipleImportNameType { span: item.span() }); - continue; - } - let Some(link_import_name_type) = item.value_str() else { - sess.dcx().emit_err(errors::ImportNameTypeForm { span: item.span() }); - continue; - }; - if self.tcx.sess.target.arch != "x86" { - sess.dcx().emit_err(errors::ImportNameTypeX86 { span: item.span() }); - continue; - } - - let link_import_name_type = match link_import_name_type.as_str() { - "decorated" => PeImportNameType::Decorated, - "noprefix" => PeImportNameType::NoPrefix, - "undecorated" => PeImportNameType::Undecorated, - import_name_type => { - sess.dcx().emit_err(errors::UnknownImportNameType { - span: item.span(), - import_name_type, - }); - continue; - } - }; - import_name_type = Some((link_import_name_type, item.span())); - } - _ => { - sess.dcx().emit_err(errors::UnexpectedLinkArg { span: item.span() }); - } - } - } - - // Do this outside the above loop so we don't depend on modifiers coming after kinds - let mut verbatim = None; - if let Some((modifiers, span)) = modifiers { - for modifier in modifiers.as_str().split(',') { - let (modifier, value) = match modifier.strip_prefix(&['+', '-']) { - Some(m) => (m, modifier.starts_with('+')), - None => { - sess.dcx().emit_err(errors::InvalidLinkModifier { span }); - continue; - } - }; - - macro report_unstable_modifier($feature: ident) { - if !features.$feature() { - // FIXME: make this translatable - #[expect(rustc::untranslatable_diagnostic)] - feature_err( - sess, - sym::$feature, - span, - format!("linking modifier `{modifier}` is unstable"), - ) - .emit(); - } - } - let assign_modifier = |dst: &mut Option| { - if dst.is_some() { - sess.dcx().emit_err(errors::MultipleModifiers { span, modifier }); - } else { - *dst = Some(value); - } - }; - match (modifier, &mut kind) { - ("bundle", Some(NativeLibKind::Static { bundle, .. })) => { - assign_modifier(bundle) - } - ("bundle", _) => { - sess.dcx().emit_err(errors::BundleNeedsStatic { span }); - } - - ("verbatim", _) => assign_modifier(&mut verbatim), - - ("whole-archive", Some(NativeLibKind::Static { whole_archive, .. })) => { - assign_modifier(whole_archive) - } - ("whole-archive", _) => { - sess.dcx().emit_err(errors::WholeArchiveNeedsStatic { span }); - } - - ("as-needed", Some(NativeLibKind::Dylib { as_needed })) - | ("as-needed", Some(NativeLibKind::Framework { as_needed })) => { - report_unstable_modifier!(native_link_modifiers_as_needed); - assign_modifier(as_needed) - } - ("as-needed", _) => { - sess.dcx().emit_err(errors::AsNeededCompatibility { span }); - } - - _ => { - sess.dcx().emit_err(errors::UnknownLinkModifier { span, modifier }); - } - } - } - } - - if let Some((_, span)) = wasm_import_module { - if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() { - sess.dcx().emit_err(errors::IncompatibleWasmLink { span }); - } - } - - if wasm_import_module.is_some() { - (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule)); - } - let Some((name, name_span)) = name else { - sess.dcx().emit_err(errors::LinkRequiresName { span: m.span() }); - continue; - }; - - // Do this outside of the loop so that `import_name_type` can be specified before `kind`. - if let Some((_, span)) = import_name_type { - if kind != Some(NativeLibKind::RawDylib) { - sess.dcx().emit_err(errors::ImportNameTypeRaw { span }); - } - } - - let dll_imports = match kind { - Some(NativeLibKind::RawDylib) => { - if name.as_str().contains('\0') { - sess.dcx().emit_err(errors::RawDylibNoNul { span: name_span }); - } - foreign_items - .iter() - .map(|&child_item| { - self.build_dll_import( - abi, - import_name_type.map(|(import_name_type, _)| import_name_type), - child_item, - ) - }) - .collect() - } + for attr in + find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::Link(links, _) => links) + .iter() + .map(|v| v.iter()) + .flatten() + { + let dll_imports = match attr.kind { + NativeLibKind::RawDylib => foreign_items + .iter() + .map(|&child_item| { + self.build_dll_import( + abi, + attr.import_name_type.map(|(import_name_type, _)| import_name_type), + child_item, + ) + }) + .collect(), _ => { for &child_item in foreign_items { if let Some(span) = find_attr!(self.tcx.get_all_attrs(child_item), AttributeKind::LinkOrdinal {span, ..} => *span) @@ -508,15 +240,20 @@ impl<'tcx> Collector<'tcx> { } }; - let kind = kind.unwrap_or(NativeLibKind::Unspecified); - let filename = find_bundled_library(name, verbatim, kind, cfg.is_some(), self.tcx); + let filename = find_bundled_library( + attr.name, + attr.verbatim, + attr.kind, + attr.cfg.is_some(), + self.tcx, + ); self.libs.push(NativeLib { - name, + name: attr.name, filename, - kind, - cfg, + kind: attr.kind, + cfg: attr.cfg.clone(), foreign_module: Some(def_id.to_def_id()), - verbatim, + verbatim: attr.verbatim, dll_imports, }); } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3a79176f914..c47b488465b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -200,6 +200,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::Sanitize { on_set, off_set, span: attr_span}) => { self.check_sanitize(attr_span, on_set | off_set, span, target); }, + Attribute::Parsed(AttributeKind::Link(_, attr_span)) => { + self.check_link(hir_id, *attr_span, span, target) + } Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -305,7 +308,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::rustc_has_incoherent_inherent_impls, ..] => { self.check_has_incoherent_inherent_impls(attr, span, target) } - [sym::link, ..] => self.check_link(hir_id, attr, span, target), [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) @@ -1324,7 +1326,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[link]` is applied to an item other than a foreign module. - fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_link(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { if target == Target::ForeignMod && let hir::Node::Item(item) = self.tcx.hir_node(hir_id) && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item @@ -1336,7 +1338,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::Link { span: (target != Target::ForeignMod).then_some(span) }, ); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 585968044bf..89b07dba5c8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -466,6 +466,7 @@ symbols! { arm, arm_target_feature, array, + as_dash_needed: "as-needed", as_ptr, as_ref, as_str, @@ -592,6 +593,7 @@ symbols! { btreeset_iter, built, builtin_syntax, + bundle, c, c_dash_variadic, c_str, @@ -817,6 +819,7 @@ symbols! { decl_macro, declare_lint_pass, decode, + decorated, default_alloc_error_handler, default_field_values, default_fn, @@ -1075,6 +1078,7 @@ symbols! { format_macro, format_placeholder, format_unsafe_arg, + framework, freeze, freeze_impls, freg, @@ -1295,6 +1299,7 @@ symbols! { link_arg_attribute, link_args, link_cfg, + link_dash_arg: "link-arg", link_llvm_intrinsics, link_name, link_ordinal, @@ -1528,6 +1533,7 @@ symbols! { noop_method_borrow, noop_method_clone, noop_method_deref, + noprefix, noreturn, nostack, not, @@ -1741,6 +1747,7 @@ symbols! { quote, range_inclusive_new, range_step, + raw_dash_dylib: "raw-dylib", raw_dylib, raw_dylib_elf, raw_eq, @@ -2277,6 +2284,7 @@ symbols! { unchecked_shl, unchecked_shr, unchecked_sub, + undecorated, underscore_const_names, underscore_imports, underscore_lifetimes, @@ -2365,6 +2373,7 @@ symbols! { vecdeque_iter, vecdeque_reserve, vector, + verbatim, version, vfp2, vis, @@ -2389,6 +2398,7 @@ symbols! { weak_odr, where_clause_attrs, while_let, + whole_dash_archive: "whole-archive", width, windows, windows_subsystem, -- cgit 1.4.1-3-g733a5 From 7db184056909045802a66299947dc81c8e43e605 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 16 Jul 2025 13:46:25 +0200 Subject: Changes to the uitests Signed-off-by: Jonathan Brouwer --- .../rustc_error_codes/src/error_codes/E0458.md | 4 +- tests/crashes/120175.rs | 3 +- tests/ui/attributes/malformed-attrs.rs | 3 +- tests/ui/attributes/malformed-attrs.stderr | 147 ++++--- tests/ui/error-codes/E0458.rs | 2 +- tests/ui/error-codes/E0458.stderr | 29 +- .../issue-43106-gating-of-builtin-attrs.rs | 16 +- .../issue-43106-gating-of-builtin-attrs.stderr | 34 +- tests/ui/link-native-libs/issue-43925.rs | 4 +- tests/ui/link-native-libs/issue-43925.stderr | 14 +- tests/ui/link-native-libs/issue-43926.rs | 2 +- tests/ui/link-native-libs/issue-43926.stderr | 26 +- .../link-native-libs/link-attr-validation-early.rs | 6 +- .../link-attr-validation-early.stderr | 62 ++- .../link-native-libs/link-attr-validation-late.rs | 40 +- .../link-attr-validation-late.stderr | 467 +++++++++++++++++---- tests/ui/link-native-libs/modifiers-override-4.rs | 12 + .../link-native-libs/modifiers-override-4.stderr | 67 +++ tests/ui/link-native-libs/modifiers-override.rs | 5 - .../ui/link-native-libs/modifiers-override.stderr | 24 +- .../windows/import-name-type-invalid-format.rs | 13 +- .../windows/import-name-type-invalid-format.stderr | 26 +- .../raw-dylib/windows/import-name-type-multiple.rs | 13 +- .../windows/import-name-type-multiple.stderr | 26 +- .../windows/import-name-type-unknown-value.rs | 13 +- .../windows/import-name-type-unknown-value.stderr | 26 +- .../import-name-type-unsupported-link-kind.rs | 11 +- .../import-name-type-unsupported-link-kind.stderr | 4 +- .../raw-dylib/windows/import-name-type-x86-only.rs | 11 +- .../windows/import-name-type-x86-only.stderr | 2 +- .../windows/link-ordinal-not-foreign-fn.rs | 2 +- tests/ui/malformed/malformed-regressions.rs | 6 +- tests/ui/malformed/malformed-regressions.stderr | 65 ++- tests/ui/parser/bad-lit-suffixes.rs | 1 + tests/ui/parser/bad-lit-suffixes.stderr | 43 +- tests/ui/wasm/wasm-import-module.rs | 6 +- tests/ui/wasm/wasm-import-module.stderr | 76 +++- 37 files changed, 945 insertions(+), 366 deletions(-) create mode 100644 tests/ui/link-native-libs/modifiers-override-4.rs create mode 100644 tests/ui/link-native-libs/modifiers-override-4.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0458.md b/compiler/rustc_error_codes/src/error_codes/E0458.md index 1b280cba44f..651bc378879 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0458.md +++ b/compiler/rustc_error_codes/src/error_codes/E0458.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + An unknown "kind" was specified for a link attribute. Erroneous code example: -```compile_fail,E0458 +```ignore (no longer emitted) #[link(kind = "wonderful_unicorn")] extern "C" {} // error: unknown kind: `wonderful_unicorn` ``` diff --git a/tests/crashes/120175.rs b/tests/crashes/120175.rs index c6e7203ff98..e441454bed2 100644 --- a/tests/crashes/120175.rs +++ b/tests/crashes/120175.rs @@ -2,8 +2,9 @@ //@ needs-rustc-debug-assertions #![feature(extern_types)] +#![feature(raw_dylib_elf)] -#[link(name = "bar", import_name_type = "decorated", kind = "raw-dylib")] +#[link(name = "bar", kind = "raw-dylib")] extern "C" { pub type CrossCrate; } diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index 90ca007451e..932aaf7a9e2 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -81,8 +81,7 @@ #[export_stable = 1] //~^ ERROR malformed #[link] -//~^ ERROR valid forms for the attribute are -//~| WARN this was previously accepted by the compiler +//~^ ERROR malformed #[link_name] //~^ ERROR malformed #[link_section] diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 69f9a18c179..b85864b401e 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -1,5 +1,5 @@ error[E0539]: malformed `cfg` attribute input - --> $DIR/malformed-attrs.rs:102:1 + --> $DIR/malformed-attrs.rs:101:1 | LL | #[cfg] | ^^^^^^ @@ -10,7 +10,7 @@ LL | #[cfg] = note: for more information, visit error: malformed `cfg_attr` attribute input - --> $DIR/malformed-attrs.rs:104:1 + --> $DIR/malformed-attrs.rs:103:1 | LL | #[cfg_attr] | ^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | #[cfg_attr(condition, attribute, other_attribute, ...)] | ++++++++++++++++++++++++++++++++++++++++++++ error[E0463]: can't find crate for `wloop` - --> $DIR/malformed-attrs.rs:211:1 + --> $DIR/malformed-attrs.rs:210:1 | LL | extern crate wloop; | ^^^^^^^^^^^^^^^^^^^ can't find crate @@ -42,7 +42,7 @@ LL | #![windows_subsystem = "windows"] | +++++++++++ error: malformed `instruction_set` attribute input - --> $DIR/malformed-attrs.rs:106:1 + --> $DIR/malformed-attrs.rs:105:1 | LL | #[instruction_set] | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[instruction_set(set)]` @@ -50,13 +50,13 @@ LL | #[instruction_set] = note: for more information, visit error: malformed `patchable_function_entry` attribute input - --> $DIR/malformed-attrs.rs:108:1 + --> $DIR/malformed-attrs.rs:107:1 | LL | #[patchable_function_entry] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` error: malformed `must_not_suspend` attribute input - --> $DIR/malformed-attrs.rs:132:1 + --> $DIR/malformed-attrs.rs:131:1 | LL | #[must_not_suspend()] | ^^^^^^^^^^^^^^^^^^^^^ @@ -71,13 +71,13 @@ LL + #[must_not_suspend] | error: malformed `cfi_encoding` attribute input - --> $DIR/malformed-attrs.rs:134:1 + --> $DIR/malformed-attrs.rs:133:1 | LL | #[cfi_encoding] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]` error: malformed `allow` attribute input - --> $DIR/malformed-attrs.rs:178:1 + --> $DIR/malformed-attrs.rs:177:1 | LL | #[allow] | ^^^^^^^^ @@ -93,7 +93,7 @@ LL | #[allow(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error: malformed `expect` attribute input - --> $DIR/malformed-attrs.rs:180:1 + --> $DIR/malformed-attrs.rs:179:1 | LL | #[expect] | ^^^^^^^^^ @@ -109,7 +109,7 @@ LL | #[expect(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error: malformed `warn` attribute input - --> $DIR/malformed-attrs.rs:182:1 + --> $DIR/malformed-attrs.rs:181:1 | LL | #[warn] | ^^^^^^^ @@ -125,7 +125,7 @@ LL | #[warn(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error: malformed `deny` attribute input - --> $DIR/malformed-attrs.rs:184:1 + --> $DIR/malformed-attrs.rs:183:1 | LL | #[deny] | ^^^^^^^ @@ -141,7 +141,7 @@ LL | #[deny(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error: malformed `forbid` attribute input - --> $DIR/malformed-attrs.rs:186:1 + --> $DIR/malformed-attrs.rs:185:1 | LL | #[forbid] | ^^^^^^^^^ @@ -157,7 +157,7 @@ LL | #[forbid(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error: malformed `debugger_visualizer` attribute input - --> $DIR/malformed-attrs.rs:188:1 + --> $DIR/malformed-attrs.rs:187:1 | LL | #[debugger_visualizer] | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]` @@ -165,13 +165,13 @@ LL | #[debugger_visualizer] = note: for more information, visit error: malformed `thread_local` attribute input - --> $DIR/malformed-attrs.rs:203:1 + --> $DIR/malformed-attrs.rs:202:1 | LL | #[thread_local()] | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[thread_local]` error: malformed `no_link` attribute input - --> $DIR/malformed-attrs.rs:207:1 + --> $DIR/malformed-attrs.rs:206:1 | LL | #[no_link()] | ^^^^^^^^^^^^ help: must be of the form: `#[no_link]` @@ -179,7 +179,7 @@ LL | #[no_link()] = note: for more information, visit error: malformed `macro_export` attribute input - --> $DIR/malformed-attrs.rs:214:1 + --> $DIR/malformed-attrs.rs:213:1 | LL | #[macro_export = 18] | ^^^^^^^^^^^^^^^^^^^^ @@ -195,25 +195,25 @@ LL + #[macro_export] | error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:99:1 + --> $DIR/malformed-attrs.rs:98:1 | LL | #[proc_macro = 18] | ^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:116:1 + --> $DIR/malformed-attrs.rs:115:1 | LL | #[proc_macro_attribute = 19] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:123:1 + --> $DIR/malformed-attrs.rs:122:1 | LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^^^^ error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint - --> $DIR/malformed-attrs.rs:216:1 + --> $DIR/malformed-attrs.rs:215:1 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -242,18 +242,8 @@ LL | #[doc] = note: for more information, see issue #57571 = note: for more information, visit -error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]` - --> $DIR/malformed-attrs.rs:83:1 - | -LL | #[link] - | ^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit - error: invalid argument - --> $DIR/malformed-attrs.rs:188:1 + --> $DIR/malformed-attrs.rs:187:1 | LL | #[debugger_visualizer] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -494,8 +484,27 @@ LL | #[export_stable = 1] | | didn't expect any arguments here | help: must be of the form: `#[export_stable]` +error[E0539]: malformed `link` attribute input + --> $DIR/malformed-attrs.rs:83:1 + | +LL | #[link] + | ^^^^^^^ expected this to be a list + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL | #[link(name = "...")] + | ++++++++++++++ +LL | #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +LL | #[link(name = "...", kind = "dylib|static|...")] + | +++++++++++++++++++++++++++++++++++++++++ +LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + = and 1 other candidate + error[E0539]: malformed `link_name` attribute input - --> $DIR/malformed-attrs.rs:86:1 + --> $DIR/malformed-attrs.rs:85:1 | LL | #[link_name] | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]` @@ -503,7 +512,7 @@ LL | #[link_name] = note: for more information, visit error[E0539]: malformed `link_section` attribute input - --> $DIR/malformed-attrs.rs:88:1 + --> $DIR/malformed-attrs.rs:87:1 | LL | #[link_section] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]` @@ -511,7 +520,7 @@ LL | #[link_section] = note: for more information, visit error[E0539]: malformed `coverage` attribute input - --> $DIR/malformed-attrs.rs:90:1 + --> $DIR/malformed-attrs.rs:89:1 | LL | #[coverage] | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -524,7 +533,7 @@ LL | #[coverage(on)] | ++++ error[E0539]: malformed `sanitize` attribute input - --> $DIR/malformed-attrs.rs:92:1 + --> $DIR/malformed-attrs.rs:91:1 | LL | #[sanitize] | ^^^^^^^^^^^ expected this to be a list @@ -542,7 +551,7 @@ LL | #[sanitize(kcfi = "on|off")] = and 5 other candidates error[E0565]: malformed `no_implicit_prelude` attribute input - --> $DIR/malformed-attrs.rs:97:1 + --> $DIR/malformed-attrs.rs:96:1 | LL | #[no_implicit_prelude = 23] | ^^^^^^^^^^^^^^^^^^^^^^----^ @@ -551,7 +560,7 @@ LL | #[no_implicit_prelude = 23] | help: must be of the form: `#[no_implicit_prelude]` error[E0565]: malformed `proc_macro` attribute input - --> $DIR/malformed-attrs.rs:99:1 + --> $DIR/malformed-attrs.rs:98:1 | LL | #[proc_macro = 18] | ^^^^^^^^^^^^^----^ @@ -560,7 +569,7 @@ LL | #[proc_macro = 18] | help: must be of the form: `#[proc_macro]` error[E0565]: malformed `coroutine` attribute input - --> $DIR/malformed-attrs.rs:111:5 + --> $DIR/malformed-attrs.rs:110:5 | LL | #[coroutine = 63] || {} | ^^^^^^^^^^^^----^ @@ -569,7 +578,7 @@ LL | #[coroutine = 63] || {} | help: must be of the form: `#[coroutine]` error[E0565]: malformed `proc_macro_attribute` attribute input - --> $DIR/malformed-attrs.rs:116:1 + --> $DIR/malformed-attrs.rs:115:1 | LL | #[proc_macro_attribute = 19] | ^^^^^^^^^^^^^^^^^^^^^^^----^ @@ -578,7 +587,7 @@ LL | #[proc_macro_attribute = 19] | help: must be of the form: `#[proc_macro_attribute]` error[E0539]: malformed `must_use` attribute input - --> $DIR/malformed-attrs.rs:119:1 + --> $DIR/malformed-attrs.rs:118:1 | LL | #[must_use = 1] | ^^^^^^^^^^^^^-^ @@ -596,7 +605,7 @@ LL + #[must_use] | error[E0539]: malformed `proc_macro_derive` attribute input - --> $DIR/malformed-attrs.rs:123:1 + --> $DIR/malformed-attrs.rs:122:1 | LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^^^^ expected this to be a list @@ -610,7 +619,7 @@ LL | #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | ++++++++++++++++++++++++++++++++++++++++++ error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input - --> $DIR/malformed-attrs.rs:128:1 + --> $DIR/malformed-attrs.rs:127:1 | LL | #[rustc_layout_scalar_valid_range_start] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -619,7 +628,7 @@ LL | #[rustc_layout_scalar_valid_range_start] | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` error[E0539]: malformed `rustc_layout_scalar_valid_range_end` attribute input - --> $DIR/malformed-attrs.rs:130:1 + --> $DIR/malformed-attrs.rs:129:1 | LL | #[rustc_layout_scalar_valid_range_end] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -628,7 +637,7 @@ LL | #[rustc_layout_scalar_valid_range_end] | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]` error[E0565]: malformed `marker` attribute input - --> $DIR/malformed-attrs.rs:155:1 + --> $DIR/malformed-attrs.rs:154:1 | LL | #[marker = 3] | ^^^^^^^^^---^ @@ -637,7 +646,7 @@ LL | #[marker = 3] | help: must be of the form: `#[marker]` error[E0565]: malformed `fundamental` attribute input - --> $DIR/malformed-attrs.rs:157:1 + --> $DIR/malformed-attrs.rs:156:1 | LL | #[fundamental()] | ^^^^^^^^^^^^^--^ @@ -646,7 +655,7 @@ LL | #[fundamental()] | help: must be of the form: `#[fundamental]` error[E0565]: malformed `ffi_pure` attribute input - --> $DIR/malformed-attrs.rs:165:5 + --> $DIR/malformed-attrs.rs:164:5 | LL | #[unsafe(ffi_pure = 1)] | ^^^^^^^^^^^^^^^^^^---^^ @@ -655,7 +664,7 @@ LL | #[unsafe(ffi_pure = 1)] | help: must be of the form: `#[ffi_pure]` error[E0539]: malformed `link_ordinal` attribute input - --> $DIR/malformed-attrs.rs:167:5 + --> $DIR/malformed-attrs.rs:166:5 | LL | #[link_ordinal] | ^^^^^^^^^^^^^^^ @@ -666,7 +675,7 @@ LL | #[link_ordinal] = note: for more information, visit error[E0565]: malformed `ffi_const` attribute input - --> $DIR/malformed-attrs.rs:171:5 + --> $DIR/malformed-attrs.rs:170:5 | LL | #[unsafe(ffi_const = 1)] | ^^^^^^^^^^^^^^^^^^^---^^ @@ -675,7 +684,7 @@ LL | #[unsafe(ffi_const = 1)] | help: must be of the form: `#[ffi_const]` error[E0539]: malformed `linkage` attribute input - --> $DIR/malformed-attrs.rs:173:5 + --> $DIR/malformed-attrs.rs:172:5 | LL | #[linkage] | ^^^^^^^^^^ expected this to be of the form `linkage = "..."` @@ -693,7 +702,7 @@ LL | #[linkage = "external"] = and 5 other candidates error[E0565]: malformed `automatically_derived` attribute input - --> $DIR/malformed-attrs.rs:191:1 + --> $DIR/malformed-attrs.rs:190:1 | LL | #[automatically_derived = 18] | ^^^^^^^^^^^^^^^^^^^^^^^^----^ @@ -702,7 +711,7 @@ LL | #[automatically_derived = 18] | help: must be of the form: `#[automatically_derived]` error[E0565]: malformed `non_exhaustive` attribute input - --> $DIR/malformed-attrs.rs:197:1 + --> $DIR/malformed-attrs.rs:196:1 | LL | #[non_exhaustive = 1] | ^^^^^^^^^^^^^^^^^---^ @@ -711,13 +720,13 @@ LL | #[non_exhaustive = 1] | help: must be of the form: `#[non_exhaustive]` error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `#[macro_use]` - --> $DIR/malformed-attrs.rs:209:1 + --> $DIR/malformed-attrs.rs:208:1 | LL | #[macro_use = 1] | ^^^^^^^^^^^^^^^^ error[E0565]: malformed `allow_internal_unsafe` attribute input - --> $DIR/malformed-attrs.rs:216:1 + --> $DIR/malformed-attrs.rs:215:1 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^---^ @@ -726,7 +735,7 @@ LL | #[allow_internal_unsafe = 1] | help: must be of the form: `#[allow_internal_unsafe]` error[E0565]: malformed `type_const` attribute input - --> $DIR/malformed-attrs.rs:143:5 + --> $DIR/malformed-attrs.rs:142:5 | LL | #[type_const = 1] | ^^^^^^^^^^^^^---^ @@ -759,7 +768,7 @@ LL | #[repr] | ^^^^^^^ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/malformed-attrs.rs:149:1 + --> $DIR/malformed-attrs.rs:148:1 | LL | #[diagnostic::do_not_recommend()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -767,7 +776,7 @@ LL | #[diagnostic::do_not_recommend()] = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default warning: missing options for `on_unimplemented` attribute - --> $DIR/malformed-attrs.rs:138:1 + --> $DIR/malformed-attrs.rs:137:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -775,7 +784,7 @@ LL | #[diagnostic::on_unimplemented] = help: at least one of the `message`, `note` and `label` options are expected warning: malformed `on_unimplemented` attribute - --> $DIR/malformed-attrs.rs:140:1 + --> $DIR/malformed-attrs.rs:139:1 | LL | #[diagnostic::on_unimplemented = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -792,7 +801,7 @@ LL | #[inline = 5] = note: for more information, see issue #57571 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:94:1 + --> $DIR/malformed-attrs.rs:93:1 | LL | #[ignore()] | ^^^^^^^^^^^ @@ -801,7 +810,7 @@ LL | #[ignore()] = note: for more information, see issue #57571 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:223:1 + --> $DIR/malformed-attrs.rs:222:1 | LL | #[ignore = 1] | ^^^^^^^^^^^^^ @@ -810,7 +819,7 @@ LL | #[ignore = 1] = note: for more information, see issue #57571 error[E0308]: mismatched types - --> $DIR/malformed-attrs.rs:111:23 + --> $DIR/malformed-attrs.rs:110:23 | LL | fn test() { | - help: a return type might be missing here: `-> _` @@ -818,7 +827,7 @@ LL | #[coroutine = 63] || {} | ^^^^^ expected `()`, found coroutine | = note: expected unit type `()` - found coroutine `{coroutine@$DIR/malformed-attrs.rs:111:23: 111:25}` + found coroutine `{coroutine@$DIR/malformed-attrs.rs:110:23: 110:25}` error: aborting due to 77 previous errors; 3 warnings emitted @@ -848,18 +857,6 @@ LL | #[doc] = note: for more information, visit = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default -Future breakage diagnostic: -error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]` - --> $DIR/malformed-attrs.rs:83:1 - | -LL | #[link] - | ^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit - = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default - Future breakage diagnostic: error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` --> $DIR/malformed-attrs.rs:52:1 @@ -873,7 +870,7 @@ LL | #[inline = 5] Future breakage diagnostic: error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:94:1 + --> $DIR/malformed-attrs.rs:93:1 | LL | #[ignore()] | ^^^^^^^^^^^ @@ -884,7 +881,7 @@ LL | #[ignore()] Future breakage diagnostic: error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:223:1 + --> $DIR/malformed-attrs.rs:222:1 | LL | #[ignore = 1] | ^^^^^^^^^^^^^ diff --git a/tests/ui/error-codes/E0458.rs b/tests/ui/error-codes/E0458.rs index 35e7e84d479..0e35ba43bfb 100644 --- a/tests/ui/error-codes/E0458.rs +++ b/tests/ui/error-codes/E0458.rs @@ -1,4 +1,4 @@ -#[link(kind = "wonderful_unicorn")] extern "C" {} //~ ERROR E0458 +#[link(kind = "wonderful_unicorn")] extern "C" {} //~ ERROR malformed `link` attribute input [E0539] //~| ERROR E0459 fn main() { diff --git a/tests/ui/error-codes/E0458.stderr b/tests/ui/error-codes/E0458.stderr index c13ae4e7862..524765ea12a 100644 --- a/tests/ui/error-codes/E0458.stderr +++ b/tests/ui/error-codes/E0458.stderr @@ -1,8 +1,27 @@ -error[E0458]: unknown link kind `wonderful_unicorn`, expected one of: static, dylib, framework, raw-dylib, link-arg - --> $DIR/E0458.rs:1:15 +error[E0539]: malformed `link` attribute input + --> $DIR/E0458.rs:1:1 | LL | #[link(kind = "wonderful_unicorn")] extern "C" {} - | ^^^^^^^^^^^^^^^^^^^ unknown link kind + | ^^^^^^^^^^^^^^-------------------^^ + | | + | valid arguments are "static", "dylib", "framework", "raw-dylib" or "link-arg" + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(kind = "wonderful_unicorn")] extern "C" {} +LL + #[link(name = "...")] extern "C" {} + | +LL - #[link(kind = "wonderful_unicorn")] extern "C" {} +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] extern "C" {} + | +LL - #[link(kind = "wonderful_unicorn")] extern "C" {} +LL + #[link(name = "...", kind = "dylib|static|...")] extern "C" {} + | +LL - #[link(kind = "wonderful_unicorn")] extern "C" {} +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] extern "C" {} + | + = and 1 other candidate error[E0459]: `#[link]` attribute requires a `name = "string"` argument --> $DIR/E0458.rs:1:1 @@ -12,5 +31,5 @@ LL | #[link(kind = "wonderful_unicorn")] extern "C" {} error: aborting due to 2 previous errors -Some errors have detailed explanations: E0458, E0459. -For more information about an error, try `rustc --explain E0458`. +Some errors have detailed explanations: E0459, E0539. +For more information about an error, try `rustc --explain E0459`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index 3d814700d98..e5dae4c0069 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -69,7 +69,7 @@ //~| WARN previously accepted //~| HELP can only be applied to //~| HELP remove the attribute -#![link()] //~ WARN attribute should be applied to an `extern` block +#![link(name = "x")] //~ WARN attribute should be applied to an `extern` block //~^ WARN this was previously accepted #![link_name = "1900"] //~^ WARN attribute cannot be used on @@ -692,38 +692,38 @@ mod link_section { // Note that this is a `check-pass` test, so it will never invoke the linker. -#[link()] +#[link(name = "x")] //~^ WARN attribute should be applied to an `extern` block //~| WARN this was previously accepted mod link { //~^ NOTE not an `extern` block - mod inner { #![link()] } + mod inner { #![link(name = "x")] } //~^ WARN attribute should be applied to an `extern` block //~| WARN this was previously accepted //~| NOTE not an `extern` block - #[link()] fn f() { } + #[link(name = "x")] fn f() { } //~^ WARN attribute should be applied to an `extern` block //~| WARN this was previously accepted //~| NOTE not an `extern` block - #[link()] struct S; + #[link(name = "x")] struct S; //~^ WARN attribute should be applied to an `extern` block //~| WARN this was previously accepted //~| NOTE not an `extern` block - #[link()] type T = S; + #[link(name = "x")] type T = S; //~^ WARN attribute should be applied to an `extern` block //~| WARN this was previously accepted //~| NOTE not an `extern` block - #[link()] impl S { } + #[link(name = "x")] impl S { } //~^ WARN attribute should be applied to an `extern` block //~| WARN this was previously accepted //~| NOTE not an `extern` block - #[link()] extern "Rust" {} + #[link(name = "x")] extern "Rust" {} //~^ WARN attribute should be applied to an `extern` block //~| WARN this was previously accepted } diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 65e3d29e269..ef74a00e5a1 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -223,13 +223,13 @@ LL | #![no_std] warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:1 | -LL | #[link()] - | ^^^^^^^^^ +LL | #[link(name = "x")] + | ^^^^^^^^^^^^^^^^^^^ ... LL | / mod link { LL | | LL | | -LL | | mod inner { #![link()] } +LL | | mod inner { #![link(name = "x")] } ... | LL | | } | |_- not an `extern` block @@ -316,8 +316,8 @@ LL | #![type_length_limit="0100"] warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1 | -LL | #![link()] - | ^^^^^^^^^^ not an `extern` block +LL | #![link(name = "x")] + | ^^^^^^^^^^^^^^^^^^^^ not an `extern` block | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -462,48 +462,48 @@ LL | #![no_std] impl S { } warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:17 | -LL | mod inner { #![link()] } - | ------------^^^^^^^^^^-- not an `extern` block +LL | mod inner { #![link(name = "x")] } + | ------------^^^^^^^^^^^^^^^^^^^^-- not an `extern` block | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5 | -LL | #[link()] fn f() { } - | ^^^^^^^^^ ---------- not an `extern` block +LL | #[link(name = "x")] fn f() { } + | ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:5 | -LL | #[link()] struct S; - | ^^^^^^^^^ --------- not an `extern` block +LL | #[link(name = "x")] struct S; + | ^^^^^^^^^^^^^^^^^^^ --------- not an `extern` block | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 | -LL | #[link()] type T = S; - | ^^^^^^^^^ ----------- not an `extern` block +LL | #[link(name = "x")] type T = S; + | ^^^^^^^^^^^^^^^^^^^ ----------- not an `extern` block | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 | -LL | #[link()] impl S { } - | ^^^^^^^^^ ---------- not an `extern` block +LL | #[link(name = "x")] impl S { } + | ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 | -LL | #[link()] extern "Rust" {} - | ^^^^^^^^^ +LL | #[link(name = "x")] extern "Rust" {} + | ^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/tests/ui/link-native-libs/issue-43925.rs b/tests/ui/link-native-libs/issue-43925.rs index 1a210887154..e3ce71352c0 100644 --- a/tests/ui/link-native-libs/issue-43925.rs +++ b/tests/ui/link-native-libs/issue-43925.rs @@ -1,4 +1,6 @@ -#[link(name = "foo", cfg("rlib"))] //~ ERROR link cfg must have a single predicate argument +#[link(name = "foo", cfg("rlib"))] +//~^ ERROR link cfg is unstable +//~| ERROR `cfg` predicate key must be an identifier extern "C" {} fn main() {} diff --git a/tests/ui/link-native-libs/issue-43925.stderr b/tests/ui/link-native-libs/issue-43925.stderr index 7cc347c6163..82d204222df 100644 --- a/tests/ui/link-native-libs/issue-43925.stderr +++ b/tests/ui/link-native-libs/issue-43925.stderr @@ -1,8 +1,18 @@ -error: link cfg must have a single predicate argument +error[E0658]: link cfg is unstable --> $DIR/issue-43925.rs:1:22 | LL | #[link(name = "foo", cfg("rlib"))] | ^^^^^^^^^^^ + | + = help: add `#![feature(link_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: `cfg` predicate key must be an identifier + --> $DIR/issue-43925.rs:1:26 + | +LL | #[link(name = "foo", cfg("rlib"))] + | ^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/link-native-libs/issue-43926.rs b/tests/ui/link-native-libs/issue-43926.rs index 6d3003552dc..293ad3f4ec1 100644 --- a/tests/ui/link-native-libs/issue-43926.rs +++ b/tests/ui/link-native-libs/issue-43926.rs @@ -1,4 +1,4 @@ -#[link(name = "foo", cfg())] //~ ERROR link cfg must have a single predicate argument +#[link(name = "foo", cfg())] //~ ERROR malformed `link` attribute input extern "C" {} fn main() {} diff --git a/tests/ui/link-native-libs/issue-43926.stderr b/tests/ui/link-native-libs/issue-43926.stderr index 7c5c50a38a9..9e3ec21cc94 100644 --- a/tests/ui/link-native-libs/issue-43926.stderr +++ b/tests/ui/link-native-libs/issue-43926.stderr @@ -1,8 +1,28 @@ -error: link cfg must have a single predicate argument - --> $DIR/issue-43926.rs:1:22 +error[E0805]: malformed `link` attribute input + --> $DIR/issue-43926.rs:1:1 | LL | #[link(name = "foo", cfg())] - | ^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^-----^^ + | | + | expected a single argument here + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "foo", cfg())] +LL + #[link(name = "...")] + | +LL - #[link(name = "foo", cfg())] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "foo", cfg())] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "foo", cfg())] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0805`. diff --git a/tests/ui/link-native-libs/link-attr-validation-early.rs b/tests/ui/link-native-libs/link-attr-validation-early.rs index a7dd80f8920..89a34ac6ca1 100644 --- a/tests/ui/link-native-libs/link-attr-validation-early.rs +++ b/tests/ui/link-native-libs/link-attr-validation-early.rs @@ -1,8 +1,6 @@ // Top-level ill-formed -#[link] //~ ERROR valid forms for the attribute are - //~| WARN this was previously accepted -#[link = "foo"] //~ ERROR valid forms for the attribute are - //~| WARN this was previously accepted +#[link] //~ ERROR malformed +#[link = "foo"] //~ ERROR malformed extern "C" {} fn main() {} diff --git a/tests/ui/link-native-libs/link-attr-validation-early.stderr b/tests/ui/link-native-libs/link-attr-validation-early.stderr index d4fc2e272f8..e4799b1a161 100644 --- a/tests/ui/link-native-libs/link-attr-validation-early.stderr +++ b/tests/ui/link-native-libs/link-attr-validation-early.stderr @@ -1,47 +1,45 @@ -error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]` +error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-early.rs:2:1 | LL | #[link] - | ^^^^^^^ + | ^^^^^^^ expected this to be a list | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 = note: for more information, visit - = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default +help: try changing it to one of the following valid forms of the attribute + | +LL | #[link(name = "...")] + | ++++++++++++++ +LL | #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +LL | #[link(name = "...", kind = "dylib|static|...")] + | +++++++++++++++++++++++++++++++++++++++++ +LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + = and 1 other candidate -error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]` - --> $DIR/link-attr-validation-early.rs:4:1 +error[E0539]: malformed `link` attribute input + --> $DIR/link-attr-validation-early.rs:3:1 | LL | #[link = "foo"] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ expected this to be a list | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 = note: for more information, visit - -error: aborting due to 2 previous errors - -Future incompatibility report: Future breakage diagnostic: -error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]` - --> $DIR/link-attr-validation-early.rs:2:1 +help: try changing it to one of the following valid forms of the attribute | -LL | #[link] - | ^^^^^^^ +LL - #[link = "foo"] +LL + #[link(name = "...")] | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit - = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default - -Future breakage diagnostic: -error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]` - --> $DIR/link-attr-validation-early.rs:4:1 +LL - #[link = "foo"] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] | -LL | #[link = "foo"] - | ^^^^^^^^^^^^^^^ +LL - #[link = "foo"] +LL + #[link(name = "...", kind = "dylib|static|...")] | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit - = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default +LL - #[link = "foo"] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/link-native-libs/link-attr-validation-late.rs b/tests/ui/link-native-libs/link-attr-validation-late.rs index 4eeb8ba4884..d2947b5f61a 100644 --- a/tests/ui/link-native-libs/link-attr-validation-late.rs +++ b/tests/ui/link-native-libs/link-attr-validation-late.rs @@ -1,38 +1,36 @@ #![feature(link_cfg)] // Top-level ill-formed -#[link(name = "...", "literal")] //~ ERROR unexpected `#[link]` argument -#[link(name = "...", unknown)] //~ ERROR unexpected `#[link]` argument +#[link(name = "...", "literal")] //~ ERROR malformed `link` attribute input +#[link(name = "...", unknown)] //~ ERROR malformed `link` attribute input extern "C" {} // Duplicate arguments -#[link(name = "foo", name = "bar")] //~ ERROR multiple `name` arguments -#[link(name = "...", kind = "dylib", kind = "bar")] //~ ERROR multiple `kind` arguments -#[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] //~ ERROR multiple `modifiers` arguments -#[link(name = "...", cfg(false), cfg(false))] //~ ERROR multiple `cfg` arguments -#[link(wasm_import_module = "foo", wasm_import_module = "bar")] //~ ERROR multiple `wasm_import_module` arguments +#[link(name = "foo", name = "bar")] //~ ERROR malformed `link` attribute input +#[link(name = "...", kind = "dylib", kind = "bar")] //~ ERROR malformed `link` attribute input +#[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] //~ ERROR malformed `link` attribute input +#[link(name = "...", cfg(false), cfg(false))] //~ ERROR malformed `link` attribute input +#[link(wasm_import_module = "foo", wasm_import_module = "bar")] //~ ERROR malformed `link` attribute input extern "C" {} // Ill-formed arguments -#[link(name)] //~ ERROR link name must be of the form `name = "string"` - //~| ERROR `#[link]` attribute requires a `name = "string"` argument -#[link(name())] //~ ERROR link name must be of the form `name = "string"` - //~| ERROR `#[link]` attribute requires a `name = "string"` argument -#[link(name = "...", kind)] //~ ERROR link kind must be of the form `kind = "string"` -#[link(name = "...", kind())] //~ ERROR link kind must be of the form `kind = "string"` -#[link(name = "...", modifiers)] //~ ERROR link modifiers must be of the form `modifiers = "string"` -#[link(name = "...", modifiers())] //~ ERROR link modifiers must be of the form `modifiers = "string"` -#[link(name = "...", cfg)] //~ ERROR link cfg must be of the form `cfg(/* predicate */)` -#[link(name = "...", cfg = "literal")] //~ ERROR link cfg must be of the form `cfg(/* predicate */)` -#[link(name = "...", cfg("literal"))] //~ ERROR link cfg must have a single predicate argument -#[link(name = "...", wasm_import_module)] //~ ERROR wasm import module must be of the form `wasm_import_module = "string"` -#[link(name = "...", wasm_import_module())] //~ ERROR wasm import module must be of the form `wasm_import_module = "string"` +#[link(name)] //~ ERROR malformed `link` attribute input +#[link(name())] //~ ERROR malformed `link` attribute input +#[link(name = "...", kind)] //~ ERROR malformed `link` attribute input +#[link(name = "...", kind())] //~ ERROR malformed `link` attribute input +#[link(name = "...", modifiers)] //~ ERROR malformed `link` attribute input +#[link(name = "...", modifiers())] //~ ERROR malformed `link` attribute input +#[link(name = "...", cfg)] //~ ERROR malformed `link` attribute input +#[link(name = "...", cfg = "literal")] //~ ERROR malformed `link` attribute input +#[link(name = "...", cfg("literal"))] //~ ERROR `cfg` predicate key must be an identifier +#[link(name = "...", wasm_import_module)] //~ ERROR malformed `link` attribute input +#[link(name = "...", wasm_import_module())] //~ ERROR malformed `link` attribute input extern "C" {} // Basic modifier validation #[link(name = "...", modifiers = "")] //~ ERROR invalid linking modifier syntax, expected '+' or '-' prefix #[link(name = "...", modifiers = "no-plus-minus")] //~ ERROR invalid linking modifier syntax, expected '+' or '-' prefix -#[link(name = "...", modifiers = "+unknown")] //~ ERROR unknown linking modifier `unknown` +#[link(name = "...", modifiers = "+unknown")] //~ ERROR malformed `link` attribute input #[link(name = "...", modifiers = "+verbatim,+verbatim")] //~ ERROR multiple `verbatim` modifiers extern "C" {} diff --git a/tests/ui/link-native-libs/link-attr-validation-late.stderr b/tests/ui/link-native-libs/link-attr-validation-late.stderr index f3989c09360..834dca0bc0b 100644 --- a/tests/ui/link-native-libs/link-attr-validation-late.stderr +++ b/tests/ui/link-native-libs/link-attr-validation-late.stderr @@ -1,147 +1,472 @@ -error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type - --> $DIR/link-attr-validation-late.rs:4:22 +error[E0565]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:4:1 | LL | #[link(name = "...", "literal")] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^---------^^ + | | + | didn't expect a literal here + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", "literal")] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", "literal")] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", "literal")] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", "literal")] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type - --> $DIR/link-attr-validation-late.rs:5:22 +error[E0539]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:5:1 | LL | #[link(name = "...", unknown)] - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^-------^^ + | | + | valid arguments are "name", "kind", "modifiers", "cfg", "wasm_import_module" or "import_name_type" + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", unknown)] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", unknown)] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", unknown)] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", unknown)] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: multiple `name` arguments in a single `#[link]` attribute - --> $DIR/link-attr-validation-late.rs:9:22 +error[E0538]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:9:1 | LL | #[link(name = "foo", name = "bar")] - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^------------^^ + | | + | found `name` used as a key more than once + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "foo", name = "bar")] +LL + #[link(name = "...")] + | +LL - #[link(name = "foo", name = "bar")] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "foo", name = "bar")] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "foo", name = "bar")] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: multiple `kind` arguments in a single `#[link]` attribute - --> $DIR/link-attr-validation-late.rs:10:38 +error[E0538]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:10:1 | LL | #[link(name = "...", kind = "dylib", kind = "bar")] - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------^^ + | | + | found `kind` used as a key more than once + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", kind = "dylib", kind = "bar")] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", kind = "dylib", kind = "bar")] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", kind = "dylib", kind = "bar")] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", kind = "dylib", kind = "bar")] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: multiple `modifiers` arguments in a single `#[link]` attribute - --> $DIR/link-attr-validation-late.rs:11:47 +error[E0538]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:11:1 | LL | #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^ + | | + | found `modifiers` used as a key more than once + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: multiple `cfg` arguments in a single `#[link]` attribute - --> $DIR/link-attr-validation-late.rs:12:34 +error[E0538]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:12:1 | LL | #[link(name = "...", cfg(false), cfg(false))] - | ^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------^^ + | | + | found `cfg` used as a key more than once + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", cfg(false), cfg(false))] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", cfg(false), cfg(false))] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", cfg(false), cfg(false))] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", cfg(false), cfg(false))] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: multiple `wasm_import_module` arguments in a single `#[link]` attribute - --> $DIR/link-attr-validation-late.rs:13:36 +error[E0538]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:13:1 | LL | #[link(wasm_import_module = "foo", wasm_import_module = "bar")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: link name must be of the form `name = "string"` - --> $DIR/link-attr-validation-late.rs:17:8 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------^^ + | | + | found `wasm_import_module` used as a key more than once | -LL | #[link(name)] - | ^^^^ + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(wasm_import_module = "foo", wasm_import_module = "bar")] +LL + #[link(name = "...")] + | +LL - #[link(wasm_import_module = "foo", wasm_import_module = "bar")] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(wasm_import_module = "foo", wasm_import_module = "bar")] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(wasm_import_module = "foo", wasm_import_module = "bar")] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error[E0459]: `#[link]` attribute requires a `name = "string"` argument +error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:17:1 | LL | #[link(name)] - | ^^^^^^^^^^^^^ missing `name` argument - -error: link name must be of the form `name = "string"` - --> $DIR/link-attr-validation-late.rs:19:8 + | ^^^^^^^----^^ + | | + | expected this to be of the form `name = "..."` | -LL | #[link(name())] - | ^^^^^^ + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL | #[link(name = "...")] + | +++++++ +LL | #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +LL | #[link(name = "...", kind = "dylib|static|...")] + | ++++++++++++++++++++++++++++++++++ +LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + = and 1 other candidate -error[E0459]: `#[link]` attribute requires a `name = "string"` argument - --> $DIR/link-attr-validation-late.rs:19:1 +error[E0539]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:18:1 | LL | #[link(name())] - | ^^^^^^^^^^^^^^^ missing `name` argument + | ^^^^^^^------^^ + | | + | expected this to be of the form `name = "..."` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name())] +LL + #[link(name = "...")] + | +LL - #[link(name())] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name())] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name())] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: link kind must be of the form `kind = "string"` - --> $DIR/link-attr-validation-late.rs:21:22 +error[E0539]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:19:1 | LL | #[link(name = "...", kind)] - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^----^^ + | | + | expected this to be of the form `kind = "..."` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", kind)] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", kind)] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL | #[link(name = "...", kind = "dylib|static|...")] + | ++++++++++++++++++++ +LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + = and 1 other candidate -error: link kind must be of the form `kind = "string"` - --> $DIR/link-attr-validation-late.rs:22:22 +error[E0539]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:20:1 | LL | #[link(name = "...", kind())] - | ^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^------^^ + | | + | expected this to be of the form `kind = "..."` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", kind())] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", kind())] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", kind())] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", kind())] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: link modifiers must be of the form `modifiers = "string"` - --> $DIR/link-attr-validation-late.rs:23:22 +error[E0539]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:21:1 | LL | #[link(name = "...", modifiers)] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^---------^^ + | | + | expected this to be of the form `modifiers = "..."` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", modifiers)] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", modifiers)] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", modifiers)] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", modifiers)] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: link modifiers must be of the form `modifiers = "string"` - --> $DIR/link-attr-validation-late.rs:24:22 +error[E0539]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:22:1 | LL | #[link(name = "...", modifiers())] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^-----------^^ + | | + | expected this to be of the form `modifiers = "..."` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", modifiers())] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", modifiers())] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", modifiers())] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", modifiers())] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: link cfg must be of the form `cfg(/* predicate */)` - --> $DIR/link-attr-validation-late.rs:25:22 +error[E0539]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:23:1 | LL | #[link(name = "...", cfg)] - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^---^^ + | | + | expected this to be a list + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", cfg)] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", cfg)] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", cfg)] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", cfg)] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: link cfg must be of the form `cfg(/* predicate */)` - --> $DIR/link-attr-validation-late.rs:26:22 +error[E0539]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:24:1 | LL | #[link(name = "...", cfg = "literal")] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^---------------^^ + | | + | expected this to be a list + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", cfg = "literal")] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", cfg = "literal")] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", cfg = "literal")] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", cfg = "literal")] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: link cfg must have a single predicate argument - --> $DIR/link-attr-validation-late.rs:27:22 +error: `cfg` predicate key must be an identifier + --> $DIR/link-attr-validation-late.rs:25:26 | LL | #[link(name = "...", cfg("literal"))] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^ -error: wasm import module must be of the form `wasm_import_module = "string"` - --> $DIR/link-attr-validation-late.rs:28:22 +error[E0539]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:26:1 | LL | #[link(name = "...", wasm_import_module)] - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^------------------^^ + | | + | expected this to be of the form `wasm_import_module = "..."` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", wasm_import_module)] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", wasm_import_module)] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", wasm_import_module)] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", wasm_import_module)] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: wasm import module must be of the form `wasm_import_module = "string"` - --> $DIR/link-attr-validation-late.rs:29:22 +error[E0539]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:27:1 | LL | #[link(name = "...", wasm_import_module())] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^--------------------^^ + | | + | expected this to be of the form `wasm_import_module = "..."` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", wasm_import_module())] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", wasm_import_module())] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", wasm_import_module())] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", wasm_import_module())] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed - --> $DIR/link-attr-validation-late.rs:33:34 + --> $DIR/link-attr-validation-late.rs:31:34 | LL | #[link(name = "...", modifiers = "")] | ^^ error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed - --> $DIR/link-attr-validation-late.rs:34:34 + --> $DIR/link-attr-validation-late.rs:32:34 | LL | #[link(name = "...", modifiers = "no-plus-minus")] | ^^^^^^^^^^^^^^^ -error: unknown linking modifier `unknown`, expected one of: bundle, verbatim, whole-archive, as-needed - --> $DIR/link-attr-validation-late.rs:35:34 +error[E0539]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:33:1 | LL | #[link(name = "...", modifiers = "+unknown")] - | ^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------^^ + | | + | valid arguments are "bundle", "verbatim", "whole-archive" or "as-needed" + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", modifiers = "+unknown")] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", modifiers = "+unknown")] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", modifiers = "+unknown")] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", modifiers = "+unknown")] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate error: multiple `verbatim` modifiers in a single `modifiers` argument - --> $DIR/link-attr-validation-late.rs:36:34 + --> $DIR/link-attr-validation-late.rs:34:34 | LL | #[link(name = "...", modifiers = "+verbatim,+verbatim")] | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 24 previous errors +error: aborting due to 22 previous errors -For more information about this error, try `rustc --explain E0459`. +Some errors have detailed explanations: E0538, E0539, E0565. +For more information about an error, try `rustc --explain E0538`. diff --git a/tests/ui/link-native-libs/modifiers-override-4.rs b/tests/ui/link-native-libs/modifiers-override-4.rs new file mode 100644 index 00000000000..cc5b07e20cc --- /dev/null +++ b/tests/ui/link-native-libs/modifiers-override-4.rs @@ -0,0 +1,12 @@ +#[link(name = "foo")] +#[link( +//~^ ERROR malformed `link` attribute input + name = "bar", + kind = "static", + modifiers = "+whole-archive,-whole-archive", + //~^ ERROR multiple `whole-archive` modifiers in a single `modifiers` argument + modifiers = "+bundle" +)] +extern "C" {} + +fn main() {} diff --git a/tests/ui/link-native-libs/modifiers-override-4.stderr b/tests/ui/link-native-libs/modifiers-override-4.stderr new file mode 100644 index 00000000000..317e89cb39c --- /dev/null +++ b/tests/ui/link-native-libs/modifiers-override-4.stderr @@ -0,0 +1,67 @@ +error[E0538]: malformed `link` attribute input + --> $DIR/modifiers-override-4.rs:2:1 + | +LL | / #[link( +LL | | +LL | | name = "bar", +LL | | kind = "static", +... | +LL | | modifiers = "+bundle" + | | --------------------- found `modifiers` used as a key more than once +LL | | )] + | |__^ + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link( +LL - +LL - name = "bar", +LL - kind = "static", +LL - modifiers = "+whole-archive,-whole-archive", +LL - +LL - modifiers = "+bundle" +LL - )] +LL + #[link(name = "...")] + | +LL - #[link( +LL - +LL - name = "bar", +LL - kind = "static", +LL - modifiers = "+whole-archive,-whole-archive", +LL - +LL - modifiers = "+bundle" +LL - )] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link( +LL - +LL - name = "bar", +LL - kind = "static", +LL - modifiers = "+whole-archive,-whole-archive", +LL - +LL - modifiers = "+bundle" +LL - )] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link( +LL - +LL - name = "bar", +LL - kind = "static", +LL - modifiers = "+whole-archive,-whole-archive", +LL - +LL - modifiers = "+bundle" +LL - )] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate + +error: multiple `whole-archive` modifiers in a single `modifiers` argument + --> $DIR/modifiers-override-4.rs:6:17 + | +LL | modifiers = "+whole-archive,-whole-archive", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0538`. diff --git a/tests/ui/link-native-libs/modifiers-override.rs b/tests/ui/link-native-libs/modifiers-override.rs index cd2d003664a..a44b7d37ed8 100644 --- a/tests/ui/link-native-libs/modifiers-override.rs +++ b/tests/ui/link-native-libs/modifiers-override.rs @@ -4,13 +4,8 @@ #[link( name = "bar", kind = "static", - modifiers = "+whole-archive,-whole-archive", - //~^ ERROR multiple `whole-archive` modifiers in a single `modifiers` argument - modifiers = "+bundle" - //~^ ERROR multiple `modifiers` arguments in a single `#[link]` attribute )] extern "C" {} //~^ ERROR overriding linking modifiers from command line is not supported -//~| ERROR overriding linking modifiers from command line is not supported fn main() {} diff --git a/tests/ui/link-native-libs/modifiers-override.stderr b/tests/ui/link-native-libs/modifiers-override.stderr index 64427651e9f..3cc99c96c7c 100644 --- a/tests/ui/link-native-libs/modifiers-override.stderr +++ b/tests/ui/link-native-libs/modifiers-override.stderr @@ -1,28 +1,8 @@ -error: multiple `modifiers` arguments in a single `#[link]` attribute - --> $DIR/modifiers-override.rs:9:5 - | -LL | modifiers = "+bundle" - | ^^^^^^^^^^^^^^^^^^^^^ - -error: multiple `whole-archive` modifiers in a single `modifiers` argument - --> $DIR/modifiers-override.rs:7:17 - | -LL | modifiers = "+whole-archive,-whole-archive", - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: overriding linking modifiers from command line is not supported - --> $DIR/modifiers-override.rs:12:1 - | -LL | extern "C" {} - | ^^^^^^^^^^^^^ - error: overriding linking modifiers from command line is not supported - --> $DIR/modifiers-override.rs:12:1 + --> $DIR/modifiers-override.rs:8:1 | LL | extern "C" {} | ^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 4 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.rs b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.rs index 50ad8a173ad..542f34b3eb1 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.rs @@ -1,7 +1,10 @@ -//@ only-windows -//@ only-x86 +//@ add-core-stubs +//@ compile-flags: --target i686-pc-windows-msvc +//@ needs-llvm-components: x86 +#![feature(no_core, rustc_attrs, lang_items)] +#![no_core] +#![crate_type = "lib"] + #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] -//~^ ERROR import name type must be of the form `import_name_type = "string"` +//~^ ERROR malformed extern "C" { } - -fn main() {} diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr index d2cf7a0ba1f..6121762fb03 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr @@ -1,8 +1,28 @@ -error: import name type must be of the form `import_name_type = "string"` - --> $DIR/import-name-type-invalid-format.rs:3:42 +error[E0539]: malformed `link` attribute input + --> $DIR/import-name-type-invalid-format.rs:8:1 | LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------^^ + | | + | expected this to be of the form `import_name_type = "..."` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] +LL + #[link(name = "...")] + | +LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.rs b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.rs index cf456b9b261..e2418642aea 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.rs @@ -1,8 +1,11 @@ // ignore-tidy-linelength -//@ only-windows -//@ only-x86 +//@ add-core-stubs +//@ compile-flags: --target i686-pc-windows-msvc +//@ needs-llvm-components: x86 +#![feature(no_core, rustc_attrs, lang_items)] +#![no_core] +#![crate_type = "lib"] + #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] -//~^ ERROR multiple `import_name_type` arguments in a single `#[link]` attribute +//~^ ERROR malformed extern "C" { } - -fn main() {} diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr index 8e65baf65df..adfe915b464 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr @@ -1,8 +1,28 @@ -error: multiple `import_name_type` arguments in a single `#[link]` attribute - --> $DIR/import-name-type-multiple.rs:4:74 +error[E0538]: malformed `link` attribute input + --> $DIR/import-name-type-multiple.rs:9:1 | LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------^^ + | | + | found `import_name_type` used as a key more than once + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] +LL + #[link(name = "...")] + | +LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0538`. diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.rs b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.rs index b3859ba1ce6..174e8682f29 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.rs @@ -1,7 +1,10 @@ -//@ only-windows -//@ only-x86 +//@ add-core-stubs +//@ compile-flags: --target i686-pc-windows-msvc +//@ needs-llvm-components: x86 +#![feature(no_core, rustc_attrs, lang_items)] +#![no_core] +#![crate_type = "lib"] + #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] -//~^ ERROR unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated +//~^ ERROR malformed extern "C" { } - -fn main() {} diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr index 4b8b90eb6e2..fc24a6bed17 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr @@ -1,8 +1,28 @@ -error: unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated - --> $DIR/import-name-type-unknown-value.rs:3:42 +error[E0539]: malformed `link` attribute input + --> $DIR/import-name-type-unknown-value.rs:8:1 | LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------^^ + | | + | valid arguments are "decorated", "noprefix" or "undecorated" + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] +LL + #[link(name = "...")] + | +LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unsupported-link-kind.rs b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unsupported-link-kind.rs index 3ead5cb1fd7..ca6aef79c95 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unsupported-link-kind.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unsupported-link-kind.rs @@ -1,5 +1,10 @@ -//@ only-windows -//@ only-x86 +//@ add-core-stubs +//@ compile-flags: --target i686-pc-windows-msvc +//@ needs-llvm-components: x86 +#![feature(no_core, rustc_attrs, lang_items)] +#![no_core] +#![crate_type = "lib"] + #[link(name = "foo", import_name_type = "decorated")] //~^ ERROR import name type can only be used with link kind `raw-dylib` extern "C" { } @@ -11,5 +16,3 @@ extern "C" { } // Specifying `import_name_type` before `kind` shouldn't raise an error. #[link(name = "bar", import_name_type = "decorated", kind = "raw-dylib")] extern "C" { } - -fn main() {} diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unsupported-link-kind.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unsupported-link-kind.stderr index 75cadc471c4..075e4ffffb8 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unsupported-link-kind.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unsupported-link-kind.stderr @@ -1,11 +1,11 @@ error: import name type can only be used with link kind `raw-dylib` - --> $DIR/import-name-type-unsupported-link-kind.rs:3:22 + --> $DIR/import-name-type-unsupported-link-kind.rs:8:22 | LL | #[link(name = "foo", import_name_type = "decorated")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: import name type can only be used with link kind `raw-dylib` - --> $DIR/import-name-type-unsupported-link-kind.rs:7:39 + --> $DIR/import-name-type-unsupported-link-kind.rs:12:39 | LL | #[link(name = "bar", kind = "static", import_name_type = "decorated")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-x86-only.rs b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-x86-only.rs index ab0dcda64e6..5f1410f7d2a 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-x86-only.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-x86-only.rs @@ -1,7 +1,10 @@ -//@ only-windows -//@ ignore-x86 +//@ add-core-stubs +//@ compile-flags: --target aarch64-pc-windows-msvc +//@ needs-llvm-components: aarch64 +#![feature(no_core, rustc_attrs, lang_items)] +#![no_core] +#![crate_type = "lib"] + #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")] //~^ ERROR import name type is only supported on x86 extern "C" { } - -fn main() {} diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-x86-only.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-x86-only.stderr index 757f1f7994e..ad3b9f79c84 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-x86-only.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-x86-only.stderr @@ -1,5 +1,5 @@ error: import name type is only supported on x86 - --> $DIR/import-name-type-x86-only.rs:3:42 + --> $DIR/import-name-type-x86-only.rs:8:42 | LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.rs index 301e690be38..8651a4e7175 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.rs @@ -10,7 +10,7 @@ fn test() {} //~^ ERROR attribute cannot be used on static mut imported_val: i32 = 123; -#[link(name = "exporter", kind = "raw-dylib")] +#[link(name = "exporter")] extern "C" { #[link_ordinal(13)] fn imported_function(); diff --git a/tests/ui/malformed/malformed-regressions.rs b/tests/ui/malformed/malformed-regressions.rs index 99f0fc904a9..407920c4e4e 100644 --- a/tests/ui/malformed/malformed-regressions.rs +++ b/tests/ui/malformed/malformed-regressions.rs @@ -4,9 +4,7 @@ //~^ WARN this was previously accepted #[inline = ""] //~ ERROR valid forms for the attribute are //~^ WARN this was previously accepted -#[link] //~ ERROR valid forms for the attribute are -//~^ WARN this was previously accepted -#[link = ""] //~ ERROR valid forms for the attribute are -//~^ WARN this was previously accepted +#[link] //~ ERROR malformed +#[link = ""] //~ ERROR malformed fn main() {} diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr index cab347a8062..850bcb6cbc2 100644 --- a/tests/ui/malformed/malformed-regressions.stderr +++ b/tests/ui/malformed/malformed-regressions.stderr @@ -9,25 +9,47 @@ LL | #[doc] = note: for more information, visit = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default -error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]` +error[E0539]: malformed `link` attribute input --> $DIR/malformed-regressions.rs:7:1 | LL | #[link] - | ^^^^^^^ + | ^^^^^^^ expected this to be a list | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL | #[link(name = "...")] + | ++++++++++++++ +LL | #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +LL | #[link(name = "...", kind = "dylib|static|...")] + | +++++++++++++++++++++++++++++++++++++++++ +LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + = and 1 other candidate -error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]` - --> $DIR/malformed-regressions.rs:9:1 +error[E0539]: malformed `link` attribute input + --> $DIR/malformed-regressions.rs:8:1 | LL | #[link = ""] - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ expected this to be a list | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link = ""] +LL + #[link(name = "...")] + | +LL - #[link = ""] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link = ""] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link = ""] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` --> $DIR/malformed-regressions.rs:3:1 @@ -49,6 +71,7 @@ LL | #[inline = ""] error: aborting due to 5 previous errors +For more information about this error, try `rustc --explain E0539`. Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` --> $DIR/malformed-regressions.rs:1:1 @@ -61,30 +84,6 @@ LL | #[doc] = note: for more information, visit = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default -Future breakage diagnostic: -error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]` - --> $DIR/malformed-regressions.rs:7:1 - | -LL | #[link] - | ^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit - = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default - -Future breakage diagnostic: -error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]` - --> $DIR/malformed-regressions.rs:9:1 - | -LL | #[link = ""] - | ^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit - = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default - Future breakage diagnostic: error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` --> $DIR/malformed-regressions.rs:3:1 diff --git a/tests/ui/parser/bad-lit-suffixes.rs b/tests/ui/parser/bad-lit-suffixes.rs index 0a01bb84f01..91b32fd4539 100644 --- a/tests/ui/parser/bad-lit-suffixes.rs +++ b/tests/ui/parser/bad-lit-suffixes.rs @@ -38,6 +38,7 @@ fn g() {} #[link(name = "string"suffix)] //~^ ERROR suffixes on string literals are invalid +//~| ERROR malformed `link` attribute input extern "C" {} #[rustc_layout_scalar_valid_range_start(0suffix)] diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr index e1a8a6834f4..217cc74b8eb 100644 --- a/tests/ui/parser/bad-lit-suffixes.stderr +++ b/tests/ui/parser/bad-lit-suffixes.stderr @@ -10,12 +10,6 @@ error: suffixes on string literals are invalid LL | "C"suffix | ^^^^^^^^^ invalid suffix `suffix` -error: suffixes on string literals are invalid - --> $DIR/bad-lit-suffixes.rs:39:15 - | -LL | #[link(name = "string"suffix)] - | ^^^^^^^^^^^^^^ invalid suffix `suffix` - warning: `extern` declarations without an explicit ABI are deprecated --> $DIR/bad-lit-suffixes.rs:3:1 | @@ -160,8 +154,39 @@ LL - #[must_use = "string"suffix] LL + #[must_use] | +error: suffixes on string literals are invalid + --> $DIR/bad-lit-suffixes.rs:39:15 + | +LL | #[link(name = "string"suffix)] + | ^^^^^^^^^^^^^^ invalid suffix `suffix` + +error[E0539]: malformed `link` attribute input + --> $DIR/bad-lit-suffixes.rs:39:1 + | +LL | #[link(name = "string"suffix)] + | ^^^^^^^---------------------^^ + | | + | expected this to be of the form `name = "..."` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "string"suffix)] +LL + #[link(name = "...")] + | +LL - #[link(name = "string"suffix)] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "string"suffix)] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "string"suffix)] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate + error: invalid suffix `suffix` for number literal - --> $DIR/bad-lit-suffixes.rs:43:41 + --> $DIR/bad-lit-suffixes.rs:44:41 | LL | #[rustc_layout_scalar_valid_range_start(0suffix)] | ^^^^^^^ invalid suffix `suffix` @@ -169,7 +194,7 @@ LL | #[rustc_layout_scalar_valid_range_start(0suffix)] = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input - --> $DIR/bad-lit-suffixes.rs:43:1 + --> $DIR/bad-lit-suffixes.rs:44:1 | LL | #[rustc_layout_scalar_valid_range_start(0suffix)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^ @@ -177,6 +202,6 @@ LL | #[rustc_layout_scalar_valid_range_start(0suffix)] | | expected an integer literal here | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` -error: aborting due to 22 previous errors; 2 warnings emitted +error: aborting due to 23 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/wasm/wasm-import-module.rs b/tests/ui/wasm/wasm-import-module.rs index 2b3bca9a411..c38fcb1a000 100644 --- a/tests/ui/wasm/wasm-import-module.rs +++ b/tests/ui/wasm/wasm-import-module.rs @@ -1,12 +1,12 @@ #![feature(link_cfg)] -#[link(name = "...", wasm_import_module)] //~ ERROR: must be of the form +#[link(name = "...", wasm_import_module)] //~ ERROR: malformed `link` attribute input extern "C" {} -#[link(name = "...", wasm_import_module(x))] //~ ERROR: must be of the form +#[link(name = "...", wasm_import_module(x))] //~ ERROR: malformed `link` attribute input extern "C" {} -#[link(name = "...", wasm_import_module())] //~ ERROR: must be of the form +#[link(name = "...", wasm_import_module())] //~ ERROR: malformed `link` attribute input extern "C" {} #[link(wasm_import_module = "foo", name = "bar")] //~ ERROR: `wasm_import_module` is incompatible with other arguments diff --git a/tests/ui/wasm/wasm-import-module.stderr b/tests/ui/wasm/wasm-import-module.stderr index 84f437941a7..f5ea449839b 100644 --- a/tests/ui/wasm/wasm-import-module.stderr +++ b/tests/ui/wasm/wasm-import-module.stderr @@ -1,20 +1,77 @@ -error: wasm import module must be of the form `wasm_import_module = "string"` - --> $DIR/wasm-import-module.rs:3:22 +error[E0539]: malformed `link` attribute input + --> $DIR/wasm-import-module.rs:3:1 | LL | #[link(name = "...", wasm_import_module)] - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^------------------^^ + | | + | expected this to be of the form `wasm_import_module = "..."` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", wasm_import_module)] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", wasm_import_module)] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", wasm_import_module)] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", wasm_import_module)] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: wasm import module must be of the form `wasm_import_module = "string"` - --> $DIR/wasm-import-module.rs:6:22 +error[E0539]: malformed `link` attribute input + --> $DIR/wasm-import-module.rs:6:1 | LL | #[link(name = "...", wasm_import_module(x))] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^---------------------^^ + | | + | expected this to be of the form `wasm_import_module = "..."` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", wasm_import_module(x))] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", wasm_import_module(x))] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", wasm_import_module(x))] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", wasm_import_module(x))] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate -error: wasm import module must be of the form `wasm_import_module = "string"` - --> $DIR/wasm-import-module.rs:9:22 +error[E0539]: malformed `link` attribute input + --> $DIR/wasm-import-module.rs:9:1 | LL | #[link(name = "...", wasm_import_module())] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^--------------------^^ + | | + | expected this to be of the form `wasm_import_module = "..."` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", wasm_import_module())] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", wasm_import_module())] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", wasm_import_module())] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", wasm_import_module())] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate error: `wasm_import_module` is incompatible with other arguments in `#[link]` attributes --> $DIR/wasm-import-module.rs:12:8 @@ -36,3 +93,4 @@ LL | #[link(wasm_import_module = "foo", cfg(false))] error: aborting due to 6 previous errors +For more information about this error, try `rustc --explain E0539`. -- cgit 1.4.1-3-g733a5 From a8c837e7ffc6b559987c8fc71581ded676cf29f3 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 27 Aug 2025 19:27:51 +0200 Subject: Disable `int_to_ptr_transmutes` suggestion for unsized types --- compiler/rustc_lint/src/lints.rs | 2 +- compiler/rustc_lint/src/transmute.rs | 30 ++++++++++++++++++------------ tests/ui/lint/int_to_ptr-unsized.rs | 23 +++++++++++++++++++++++ tests/ui/lint/int_to_ptr-unsized.stderr | 27 +++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 13 deletions(-) create mode 100644 tests/ui/lint/int_to_ptr-unsized.rs create mode 100644 tests/ui/lint/int_to_ptr-unsized.stderr diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 426500dda4a..56d65ed08f9 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1554,7 +1554,7 @@ impl<'a> LintDiagnostic<'a, ()> for DropGlue<'_> { #[help(lint_help_exposed_provenance)] pub(crate) struct IntegerToPtrTransmutes<'tcx> { #[subdiagnostic] - pub suggestion: IntegerToPtrTransmutesSuggestion<'tcx>, + pub suggestion: Option>, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs index 239c8649041..98510eea73b 100644 --- a/compiler/rustc_lint/src/transmute.rs +++ b/compiler/rustc_lint/src/transmute.rs @@ -169,19 +169,25 @@ fn check_int_to_ptr_transmute<'tcx>( expr.hir_id, expr.span, IntegerToPtrTransmutes { - suggestion: if dst.is_ref() { - IntegerToPtrTransmutesSuggestion::ToRef { - dst: *inner_ty, - suffix, - ref_mutbl: mutbl.prefix_str(), - start_call: expr.span.shrink_to_lo().until(arg.span), - } + suggestion: if layout_inner_ty.is_sized() { + Some(if dst.is_ref() { + IntegerToPtrTransmutesSuggestion::ToRef { + dst: *inner_ty, + suffix, + ref_mutbl: mutbl.prefix_str(), + start_call: expr.span.shrink_to_lo().until(arg.span), + } + } else { + IntegerToPtrTransmutesSuggestion::ToPtr { + dst: *inner_ty, + suffix, + start_call: expr.span.shrink_to_lo().until(arg.span), + } + }) } else { - IntegerToPtrTransmutesSuggestion::ToPtr { - dst: *inner_ty, - suffix, - start_call: expr.span.shrink_to_lo().until(arg.span), - } + // We can't suggest using `with_exposed_provenance` for unsized type + // so don't suggest anything. + None }, }, ); diff --git a/tests/ui/lint/int_to_ptr-unsized.rs b/tests/ui/lint/int_to_ptr-unsized.rs new file mode 100644 index 00000000000..bbdc2474561 --- /dev/null +++ b/tests/ui/lint/int_to_ptr-unsized.rs @@ -0,0 +1,23 @@ +// Checks for the `integer_to_pointer_transmutes` lint with unsized types +// +// Related to https://github.com/rust-lang/rust/issues/145935 + +//@ check-pass + +#![allow(non_camel_case_types)] +#![allow(unused_unsafe)] + +#[cfg(target_pointer_width = "64")] +type usizemetadata = i128; + +#[cfg(target_pointer_width = "32")] +type usizemetadata = i64; + +unsafe fn unsized_type(a: usize) { + let _ref = unsafe { std::mem::transmute::(0xff) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::mem::transmute::(0xff) }; + //~^ WARN transmuting an integer to a pointer +} + +fn main() {} diff --git a/tests/ui/lint/int_to_ptr-unsized.stderr b/tests/ui/lint/int_to_ptr-unsized.stderr new file mode 100644 index 00000000000..9799af8b12c --- /dev/null +++ b/tests/ui/lint/int_to_ptr-unsized.stderr @@ -0,0 +1,27 @@ +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr-unsized.rs:17:25 + | +LL | let _ref = unsafe { std::mem::transmute::(0xff) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see + = note: `#[warn(integer_to_ptr_transmutes)]` on by default + +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr-unsized.rs:19:25 + | +LL | let _ptr = unsafe { std::mem::transmute::(0xff) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this is dangerous because dereferencing the resulting pointer is undefined behavior + = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + = help: for more information about transmute, see + = help: for more information about exposed provenance, see + +warning: 2 warnings emitted + -- cgit 1.4.1-3-g733a5 From 2dc4638c4637bf8ddb83577535317dad21abdf6d Mon Sep 17 00:00:00 2001 From: Oneirical Date: Wed, 20 Aug 2025 14:02:44 -0400 Subject: Add test batch 2 --- .../fixed-length-vector-pattern-matching-7784.rs | 31 +++++++++++++ .../matching-on-vector-slice-option-8498.rs | 28 ------------ .../pattern-matching-fixed-length-vectors-7784.rs | 31 ------------- .../array-slice-vec/vector-slice-matching-8498.rs | 28 ++++++++++++ tests/ui/binding/match-with-at-binding-8391.rs | 10 +++++ ...method-call-nonsensical-pattern-binding-7092.rs | 16 +++++++ ...od-call-nonsensical-pattern-binding-7092.stderr | 14 ++++++ tests/ui/binding/ref-pattern-drop-behavior-8860.rs | 52 ++++++++++++++++++++++ tests/ui/cast/associated-type-bounds-cast-54094.rs | 15 +++++++ tests/ui/codegen/matrix-row-swap-54462.rs | 26 +++++++++++ tests/ui/coercion/coerce-mut-trait-object-8248.rs | 15 +++++++ .../coercion/coerce-mut-trait-object-8248.stderr | 12 +++++ tests/ui/coercion/mut-trait-coercion-8248.rs | 15 ------- tests/ui/coercion/mut-trait-coercion-8248.stderr | 12 ----- .../collections/vecdeque-append-operation-54477.rs | 27 +++++++++++ tests/ui/cross-crate/auxiliary/aux-7178.rs | 7 +++ ...tic-method-returning-self-with-generics-7178.rs | 9 ++++ .../static-regions-in-cross-crate-8259.rs | 11 ----- .../static-with-cross-crate-regions-8259.rs | 11 +++++ .../cross-crate/tuple-struct-cross-crate-7899.rs | 10 +++++ .../function-pointer-comparison-54696.rs | 11 +++++ tests/ui/issues/auxiliary/issue-7178.rs | 7 --- tests/ui/issues/issue-53419.rs | 8 ---- tests/ui/issues/issue-53568.rs | 47 ------------------- tests/ui/issues/issue-53728.rs | 19 -------- tests/ui/issues/issue-54094.rs | 14 ------ tests/ui/issues/issue-54410.rs | 8 ---- tests/ui/issues/issue-54410.stderr | 12 ----- .../issue-54462-mutable-noalias-correctness.rs | 25 ----------- tests/ui/issues/issue-54477-reduced-2.rs | 26 ----------- tests/ui/issues/issue-54696.rs | 10 ----- tests/ui/issues/issue-55376.rs | 16 ------- tests/ui/issues/issue-55380.rs | 28 ------------ tests/ui/issues/issue-55380.stderr | 12 ----- tests/ui/issues/issue-7044.rs | 4 -- tests/ui/issues/issue-7044.stderr | 13 ------ tests/ui/issues/issue-7092.rs | 15 ------- tests/ui/issues/issue-7092.stderr | 14 ------ tests/ui/issues/issue-7178.rs | 9 ---- tests/ui/issues/issue-7268.rs | 9 ---- tests/ui/issues/issue-7344.rs | 21 --------- tests/ui/issues/issue-7364.rs | 8 ---- tests/ui/issues/issue-7364.stderr | 26 ----------- .../lifetimes/dyn-trait-function-pointer-53419.rs | 9 ++++ .../static-bound-fulfillment-with-pointer-7268.rs | 10 +++++ tests/ui/match/mismatched-types-in-match-7867.rs | 17 +++++++ .../ui/match/mismatched-types-in-match-7867.stderr | 17 +++++++ .../mismatched-types-in-match-pattern-7867.rs | 17 ------- .../mismatched-types-in-match-pattern-7867.stderr | 17 ------- tests/ui/methods/trait-method-resolution-7575.rs | 18 ++++++++ .../ui/methods/trait-method-resolution-7575.stderr | 10 +++++ .../methods/trait-method-self-param-error-7575.rs | 18 -------- .../trait-method-self-param-error-7575.stderr | 10 ----- .../modules/use-statement-duplicate-check-7663.rs | 33 ++++++++++++++ tests/ui/pattern/match-with-at-binding-8391.rs | 10 ----- .../ref-in-function-parameter-patterns-8860.rs | 52 ---------------------- .../ui/privacy/pub-restricted-path-usage-55376.rs | 17 +++++++ tests/ui/repr/packed-struct-with-enum-53728.rs | 20 +++++++++ tests/ui/resolve/module-import-resolution-7663.rs | 33 -------------- .../unit-like-struct-masks-constant-7044.rs | 5 +++ .../unit-like-struct-masks-constant-7044.stderr | 13 ++++++ .../trait-specialization-default-methods-55380.rs | 29 ++++++++++++ ...ait-specialization-default-methods-55380.stderr | 12 +++++ .../static/global-variable-promotion-error-7364.rs | 9 ++++ .../global-variable-promotion-error-7364.stderr | 26 +++++++++++ tests/ui/structs-enums/auxiliary/aux-8044.rs | 15 ------- .../ui/structs-enums/struct-and-enum-usage-8044.rs | 10 ----- tests/ui/structs/auxiliary/aux-8044.rs | 15 +++++++ tests/ui/structs/btree-struct-usage-8044.rs | 10 +++++ tests/ui/traits/nll-ice-custom-type-ops-53568.rs | 48 ++++++++++++++++++++ ...elf-implements-kinds-in-default-methods-8171.rs | 19 -------- .../traits/self-not-send-in-default-method-8171.rs | 19 ++++++++ .../traits/trait-implementation-and-usage-7563.rs | 29 ------------ .../ui/traits/trait-object-lifetime-bounds-7563.rs | 29 ++++++++++++ .../boolean-negation-in-unreachable-code-7344.rs | 22 +++++++++ 75 files changed, 682 insertions(+), 678 deletions(-) create mode 100644 tests/ui/array-slice-vec/fixed-length-vector-pattern-matching-7784.rs delete mode 100644 tests/ui/array-slice-vec/matching-on-vector-slice-option-8498.rs delete mode 100644 tests/ui/array-slice-vec/pattern-matching-fixed-length-vectors-7784.rs create mode 100644 tests/ui/array-slice-vec/vector-slice-matching-8498.rs create mode 100644 tests/ui/binding/match-with-at-binding-8391.rs create mode 100644 tests/ui/binding/method-call-nonsensical-pattern-binding-7092.rs create mode 100644 tests/ui/binding/method-call-nonsensical-pattern-binding-7092.stderr create mode 100644 tests/ui/binding/ref-pattern-drop-behavior-8860.rs create mode 100644 tests/ui/cast/associated-type-bounds-cast-54094.rs create mode 100644 tests/ui/codegen/matrix-row-swap-54462.rs create mode 100644 tests/ui/coercion/coerce-mut-trait-object-8248.rs create mode 100644 tests/ui/coercion/coerce-mut-trait-object-8248.stderr delete mode 100644 tests/ui/coercion/mut-trait-coercion-8248.rs delete mode 100644 tests/ui/coercion/mut-trait-coercion-8248.stderr create mode 100644 tests/ui/collections/vecdeque-append-operation-54477.rs create mode 100644 tests/ui/cross-crate/auxiliary/aux-7178.rs create mode 100644 tests/ui/cross-crate/static-method-returning-self-with-generics-7178.rs delete mode 100644 tests/ui/cross-crate/static-regions-in-cross-crate-8259.rs create mode 100644 tests/ui/cross-crate/static-with-cross-crate-regions-8259.rs create mode 100644 tests/ui/cross-crate/tuple-struct-cross-crate-7899.rs create mode 100644 tests/ui/function-pointer/function-pointer-comparison-54696.rs delete mode 100644 tests/ui/issues/auxiliary/issue-7178.rs delete mode 100644 tests/ui/issues/issue-53419.rs delete mode 100644 tests/ui/issues/issue-53568.rs delete mode 100644 tests/ui/issues/issue-53728.rs delete mode 100644 tests/ui/issues/issue-54094.rs delete mode 100644 tests/ui/issues/issue-54410.rs delete mode 100644 tests/ui/issues/issue-54410.stderr delete mode 100644 tests/ui/issues/issue-54462-mutable-noalias-correctness.rs delete mode 100644 tests/ui/issues/issue-54477-reduced-2.rs delete mode 100644 tests/ui/issues/issue-54696.rs delete mode 100644 tests/ui/issues/issue-55376.rs delete mode 100644 tests/ui/issues/issue-55380.rs delete mode 100644 tests/ui/issues/issue-55380.stderr delete mode 100644 tests/ui/issues/issue-7044.rs delete mode 100644 tests/ui/issues/issue-7044.stderr delete mode 100644 tests/ui/issues/issue-7092.rs delete mode 100644 tests/ui/issues/issue-7092.stderr delete mode 100644 tests/ui/issues/issue-7178.rs delete mode 100644 tests/ui/issues/issue-7268.rs delete mode 100644 tests/ui/issues/issue-7344.rs delete mode 100644 tests/ui/issues/issue-7364.rs delete mode 100644 tests/ui/issues/issue-7364.stderr create mode 100644 tests/ui/lifetimes/dyn-trait-function-pointer-53419.rs create mode 100644 tests/ui/lifetimes/static-bound-fulfillment-with-pointer-7268.rs create mode 100644 tests/ui/match/mismatched-types-in-match-7867.rs create mode 100644 tests/ui/match/mismatched-types-in-match-7867.stderr delete mode 100644 tests/ui/match/mismatched-types-in-match-pattern-7867.rs delete mode 100644 tests/ui/match/mismatched-types-in-match-pattern-7867.stderr create mode 100644 tests/ui/methods/trait-method-resolution-7575.rs create mode 100644 tests/ui/methods/trait-method-resolution-7575.stderr delete mode 100644 tests/ui/methods/trait-method-self-param-error-7575.rs delete mode 100644 tests/ui/methods/trait-method-self-param-error-7575.stderr create mode 100644 tests/ui/modules/use-statement-duplicate-check-7663.rs delete mode 100644 tests/ui/pattern/match-with-at-binding-8391.rs delete mode 100644 tests/ui/pattern/ref-in-function-parameter-patterns-8860.rs create mode 100644 tests/ui/privacy/pub-restricted-path-usage-55376.rs create mode 100644 tests/ui/repr/packed-struct-with-enum-53728.rs delete mode 100644 tests/ui/resolve/module-import-resolution-7663.rs create mode 100644 tests/ui/resolve/unit-like-struct-masks-constant-7044.rs create mode 100644 tests/ui/resolve/unit-like-struct-masks-constant-7044.stderr create mode 100644 tests/ui/specialization/trait-specialization-default-methods-55380.rs create mode 100644 tests/ui/specialization/trait-specialization-default-methods-55380.stderr create mode 100644 tests/ui/static/global-variable-promotion-error-7364.rs create mode 100644 tests/ui/static/global-variable-promotion-error-7364.stderr delete mode 100644 tests/ui/structs-enums/auxiliary/aux-8044.rs delete mode 100644 tests/ui/structs-enums/struct-and-enum-usage-8044.rs create mode 100644 tests/ui/structs/auxiliary/aux-8044.rs create mode 100644 tests/ui/structs/btree-struct-usage-8044.rs create mode 100644 tests/ui/traits/nll-ice-custom-type-ops-53568.rs delete mode 100644 tests/ui/traits/self-implements-kinds-in-default-methods-8171.rs create mode 100644 tests/ui/traits/self-not-send-in-default-method-8171.rs delete mode 100644 tests/ui/traits/trait-implementation-and-usage-7563.rs create mode 100644 tests/ui/traits/trait-object-lifetime-bounds-7563.rs create mode 100644 tests/ui/unreachable-code/boolean-negation-in-unreachable-code-7344.rs diff --git a/tests/ui/array-slice-vec/fixed-length-vector-pattern-matching-7784.rs b/tests/ui/array-slice-vec/fixed-length-vector-pattern-matching-7784.rs new file mode 100644 index 00000000000..7d987e92b63 --- /dev/null +++ b/tests/ui/array-slice-vec/fixed-length-vector-pattern-matching-7784.rs @@ -0,0 +1,31 @@ +// https://github.com/rust-lang/rust/issues/7784 +//@ run-pass + +use std::ops::Add; + +fn foo + Clone>([x, y, z]: [T; 3]) -> (T, T, T) { + (x.clone(), x.clone() + y.clone(), x + y + z) +} +fn bar(a: &'static str, b: &'static str) -> [&'static str; 4] { + [a, b, b, a] +} + +fn main() { + assert_eq!(foo([1, 2, 3]), (1, 3, 6)); + + let [a, b, c, d] = bar("foo", "bar"); + assert_eq!(a, "foo"); + assert_eq!(b, "bar"); + assert_eq!(c, "bar"); + assert_eq!(d, "foo"); + + let [a, _, _, d] = bar("baz", "foo"); + assert_eq!(a, "baz"); + assert_eq!(d, "baz"); + + let out = bar("baz", "foo"); + let [a, xs @ .., d] = out; + assert_eq!(a, "baz"); + assert_eq!(xs, ["foo", "foo"]); + assert_eq!(d, "baz"); +} diff --git a/tests/ui/array-slice-vec/matching-on-vector-slice-option-8498.rs b/tests/ui/array-slice-vec/matching-on-vector-slice-option-8498.rs deleted file mode 100644 index e243a247ed5..00000000000 --- a/tests/ui/array-slice-vec/matching-on-vector-slice-option-8498.rs +++ /dev/null @@ -1,28 +0,0 @@ -// https://github.com/rust-lang/rust/issues/8498 -//@ run-pass - -pub fn main() { - match &[(Box::new(5),Box::new(7))] { - ps => { - let (ref y, _) = ps[0]; - assert_eq!(**y, 5); - } - } - - match Some(&[(Box::new(5),)]) { - Some(ps) => { - let (ref y,) = ps[0]; - assert_eq!(**y, 5); - } - None => () - } - - match Some(&[(Box::new(5),Box::new(7))]) { - Some(ps) => { - let (ref y, ref z) = ps[0]; - assert_eq!(**y, 5); - assert_eq!(**z, 7); - } - None => () - } -} diff --git a/tests/ui/array-slice-vec/pattern-matching-fixed-length-vectors-7784.rs b/tests/ui/array-slice-vec/pattern-matching-fixed-length-vectors-7784.rs deleted file mode 100644 index 7d987e92b63..00000000000 --- a/tests/ui/array-slice-vec/pattern-matching-fixed-length-vectors-7784.rs +++ /dev/null @@ -1,31 +0,0 @@ -// https://github.com/rust-lang/rust/issues/7784 -//@ run-pass - -use std::ops::Add; - -fn foo + Clone>([x, y, z]: [T; 3]) -> (T, T, T) { - (x.clone(), x.clone() + y.clone(), x + y + z) -} -fn bar(a: &'static str, b: &'static str) -> [&'static str; 4] { - [a, b, b, a] -} - -fn main() { - assert_eq!(foo([1, 2, 3]), (1, 3, 6)); - - let [a, b, c, d] = bar("foo", "bar"); - assert_eq!(a, "foo"); - assert_eq!(b, "bar"); - assert_eq!(c, "bar"); - assert_eq!(d, "foo"); - - let [a, _, _, d] = bar("baz", "foo"); - assert_eq!(a, "baz"); - assert_eq!(d, "baz"); - - let out = bar("baz", "foo"); - let [a, xs @ .., d] = out; - assert_eq!(a, "baz"); - assert_eq!(xs, ["foo", "foo"]); - assert_eq!(d, "baz"); -} diff --git a/tests/ui/array-slice-vec/vector-slice-matching-8498.rs b/tests/ui/array-slice-vec/vector-slice-matching-8498.rs new file mode 100644 index 00000000000..e243a247ed5 --- /dev/null +++ b/tests/ui/array-slice-vec/vector-slice-matching-8498.rs @@ -0,0 +1,28 @@ +// https://github.com/rust-lang/rust/issues/8498 +//@ run-pass + +pub fn main() { + match &[(Box::new(5),Box::new(7))] { + ps => { + let (ref y, _) = ps[0]; + assert_eq!(**y, 5); + } + } + + match Some(&[(Box::new(5),)]) { + Some(ps) => { + let (ref y,) = ps[0]; + assert_eq!(**y, 5); + } + None => () + } + + match Some(&[(Box::new(5),Box::new(7))]) { + Some(ps) => { + let (ref y, ref z) = ps[0]; + assert_eq!(**y, 5); + assert_eq!(**z, 7); + } + None => () + } +} diff --git a/tests/ui/binding/match-with-at-binding-8391.rs b/tests/ui/binding/match-with-at-binding-8391.rs new file mode 100644 index 00000000000..bc4e7be7989 --- /dev/null +++ b/tests/ui/binding/match-with-at-binding-8391.rs @@ -0,0 +1,10 @@ +// https://github.com/rust-lang/rust/issues/8391 +//@ run-pass + +fn main() { + let x = match Some(1) { + ref _y @ Some(_) => 1, + None => 2, + }; + assert_eq!(x, 1); +} diff --git a/tests/ui/binding/method-call-nonsensical-pattern-binding-7092.rs b/tests/ui/binding/method-call-nonsensical-pattern-binding-7092.rs new file mode 100644 index 00000000000..4cb04cdf5be --- /dev/null +++ b/tests/ui/binding/method-call-nonsensical-pattern-binding-7092.rs @@ -0,0 +1,16 @@ +// https://github.com/rust-lang/rust/issues/7092 +enum Whatever { +} + +fn foo(x: Whatever) { + match x { //~ NOTE this expression has type `Whatever` + Some(field) => +//~^ ERROR mismatched types +//~| NOTE expected `Whatever`, found `Option<_>` +//~| NOTE expected enum `Whatever` +//~| NOTE found enum `Option<_>` + field.access(), + } +} + +fn main(){} diff --git a/tests/ui/binding/method-call-nonsensical-pattern-binding-7092.stderr b/tests/ui/binding/method-call-nonsensical-pattern-binding-7092.stderr new file mode 100644 index 00000000000..1f8ff2d8df1 --- /dev/null +++ b/tests/ui/binding/method-call-nonsensical-pattern-binding-7092.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/method-call-nonsensical-pattern-binding-7092.rs:7:9 + | +LL | match x { + | - this expression has type `Whatever` +LL | Some(field) => + | ^^^^^^^^^^^ expected `Whatever`, found `Option<_>` + | + = note: expected enum `Whatever` + found enum `Option<_>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/binding/ref-pattern-drop-behavior-8860.rs b/tests/ui/binding/ref-pattern-drop-behavior-8860.rs new file mode 100644 index 00000000000..1a67caf021c --- /dev/null +++ b/tests/ui/binding/ref-pattern-drop-behavior-8860.rs @@ -0,0 +1,52 @@ +// https://github.com/rust-lang/rust/issues/8860 +//@ run-pass +// FIXME(static_mut_refs): this could use an atomic +#![allow(static_mut_refs)] +#![allow(dead_code)] + +static mut DROP: isize = 0; +static mut DROP_S: isize = 0; +static mut DROP_T: isize = 0; + +struct S; +impl Drop for S { + fn drop(&mut self) { + unsafe { + DROP_S += 1; + DROP += 1; + } + } +} +fn f(ref _s: S) {} + +struct T { i: isize } +impl Drop for T { + fn drop(&mut self) { + unsafe { + DROP_T += 1; + DROP += 1; + } + } +} +fn g(ref _t: T) {} + +fn do_test() { + let s = S; + f(s); + unsafe { + assert_eq!(1, DROP); + assert_eq!(1, DROP_S); + } + let t = T { i: 1 }; + g(t); + unsafe { assert_eq!(1, DROP_T); } +} + +fn main() { + do_test(); + unsafe { + assert_eq!(2, DROP); + assert_eq!(1, DROP_S); + assert_eq!(1, DROP_T); + } +} diff --git a/tests/ui/cast/associated-type-bounds-cast-54094.rs b/tests/ui/cast/associated-type-bounds-cast-54094.rs new file mode 100644 index 00000000000..c9f307e95b9 --- /dev/null +++ b/tests/ui/cast/associated-type-bounds-cast-54094.rs @@ -0,0 +1,15 @@ +// https://github.com/rust-lang/rust/issues/54094 +//@ check-pass +trait Zoo { + type X; +} + +impl Zoo for u16 { + type X = usize; +} + +fn foo(abc: ::X) {} + +fn main() { + let x: *const u8 = foo as _; +} diff --git a/tests/ui/codegen/matrix-row-swap-54462.rs b/tests/ui/codegen/matrix-row-swap-54462.rs new file mode 100644 index 00000000000..6bfc600399a --- /dev/null +++ b/tests/ui/codegen/matrix-row-swap-54462.rs @@ -0,0 +1,26 @@ +// https://github.com/rust-lang/rust/issues/54462 +//@ run-pass +// +//@ compile-flags: -Ccodegen-units=1 -O + +fn linidx(row: usize, col: usize) -> usize { + row * 1 + col * 3 +} + +fn main() { + let mut mat = [1.0f32, 5.0, 9.0, 2.0, 6.0, 10.0, 3.0, 7.0, 11.0, 4.0, 8.0, 12.0]; + + for i in 0..2 { + for j in i+1..3 { + if mat[linidx(j, 3)] > mat[linidx(i, 3)] { + for k in 0..4 { + let (x, rest) = mat.split_at_mut(linidx(i, k) + 1); + let a = x.last_mut().unwrap(); + let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap(); + ::std::mem::swap(a, b); + } + } + } + } + assert_eq!([9.0, 5.0, 1.0, 10.0, 6.0, 2.0, 11.0, 7.0, 3.0, 12.0, 8.0, 4.0], mat); +} diff --git a/tests/ui/coercion/coerce-mut-trait-object-8248.rs b/tests/ui/coercion/coerce-mut-trait-object-8248.rs new file mode 100644 index 00000000000..a45a4d94315 --- /dev/null +++ b/tests/ui/coercion/coerce-mut-trait-object-8248.rs @@ -0,0 +1,15 @@ +// https://github.com/rust-lang/rust/issues/8248 +//@ run-pass + +trait A { + fn dummy(&self) { } //~ WARN method `dummy` is never used +} +struct B; +impl A for B {} + +fn foo(_: &mut dyn A) {} + +pub fn main() { + let mut b = B; + foo(&mut b as &mut dyn A); +} diff --git a/tests/ui/coercion/coerce-mut-trait-object-8248.stderr b/tests/ui/coercion/coerce-mut-trait-object-8248.stderr new file mode 100644 index 00000000000..c3b35a7063c --- /dev/null +++ b/tests/ui/coercion/coerce-mut-trait-object-8248.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/coerce-mut-trait-object-8248.rs:5:8 + | +LL | trait A { + | - method in this trait +LL | fn dummy(&self) { } + | ^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default + +warning: 1 warning emitted + diff --git a/tests/ui/coercion/mut-trait-coercion-8248.rs b/tests/ui/coercion/mut-trait-coercion-8248.rs deleted file mode 100644 index a45a4d94315..00000000000 --- a/tests/ui/coercion/mut-trait-coercion-8248.rs +++ /dev/null @@ -1,15 +0,0 @@ -// https://github.com/rust-lang/rust/issues/8248 -//@ run-pass - -trait A { - fn dummy(&self) { } //~ WARN method `dummy` is never used -} -struct B; -impl A for B {} - -fn foo(_: &mut dyn A) {} - -pub fn main() { - let mut b = B; - foo(&mut b as &mut dyn A); -} diff --git a/tests/ui/coercion/mut-trait-coercion-8248.stderr b/tests/ui/coercion/mut-trait-coercion-8248.stderr deleted file mode 100644 index 0c7d5f9dc45..00000000000 --- a/tests/ui/coercion/mut-trait-coercion-8248.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: method `dummy` is never used - --> $DIR/mut-trait-coercion-8248.rs:5:8 - | -LL | trait A { - | - method in this trait -LL | fn dummy(&self) { } - | ^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default - -warning: 1 warning emitted - diff --git a/tests/ui/collections/vecdeque-append-operation-54477.rs b/tests/ui/collections/vecdeque-append-operation-54477.rs new file mode 100644 index 00000000000..7680fd0bb01 --- /dev/null +++ b/tests/ui/collections/vecdeque-append-operation-54477.rs @@ -0,0 +1,27 @@ +// https://github.com/rust-lang/rust/issues/54477 +//@ run-pass +// rust-lang/rust#54477: runtime bug in the VecDeque library that was +// exposed by this test case, derived from test suite of crates.io +// `collection` crate. + +use std::collections::VecDeque; + +fn main() { + let mut vecdeque_13 = VecDeque::from(vec![ ]); + let mut vecdeque_29 = VecDeque::from(vec![ 0 ]); + vecdeque_29.insert(0, 30 ); + vecdeque_29.insert(1, 31 ); + vecdeque_29.insert(2, 32 ); + vecdeque_29.insert(3, 33 ); + vecdeque_29.insert(4, 34 ); + vecdeque_29.insert(5, 35 ); + // println!("vecdeque_13: {:?}", vecdeque_13); + // println!("vecdeque_29: {:?}", vecdeque_29); + + // println!("Invoking: `vecdeque_13.append(&mut vecdeque_29)`"); + vecdeque_13.append(&mut vecdeque_29); + + // println!("vecdeque_13: {:?}", vecdeque_13); + + assert_eq!(vecdeque_13, VecDeque::from(vec![30, 31, 32, 33, 34, 35, 0])); +} diff --git a/tests/ui/cross-crate/auxiliary/aux-7178.rs b/tests/ui/cross-crate/auxiliary/aux-7178.rs new file mode 100644 index 00000000000..56ae5139af4 --- /dev/null +++ b/tests/ui/cross-crate/auxiliary/aux-7178.rs @@ -0,0 +1,7 @@ +pub struct Foo<'a, A:'a>(&'a A); + +impl<'a, A> Foo<'a, A> { + pub fn new(a: &'a A) -> Foo<'a, A> { + Foo(a) + } +} diff --git a/tests/ui/cross-crate/static-method-returning-self-with-generics-7178.rs b/tests/ui/cross-crate/static-method-returning-self-with-generics-7178.rs new file mode 100644 index 00000000000..3888d3bdaa9 --- /dev/null +++ b/tests/ui/cross-crate/static-method-returning-self-with-generics-7178.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust/issues/7178 +//@ run-pass +//@ aux-build:aux-7178.rs + +extern crate aux_7178 as cross_crate_self; + +pub fn main() { + let _ = cross_crate_self::Foo::new(&1); +} diff --git a/tests/ui/cross-crate/static-regions-in-cross-crate-8259.rs b/tests/ui/cross-crate/static-regions-in-cross-crate-8259.rs deleted file mode 100644 index 347cfa2aee1..00000000000 --- a/tests/ui/cross-crate/static-regions-in-cross-crate-8259.rs +++ /dev/null @@ -1,11 +0,0 @@ -// https://github.com/rust-lang/rust/issues/8259 -//@ run-pass -#![allow(dead_code)] -#![allow(non_upper_case_globals)] - -//@ aux-build:aux-8259.rs - -extern crate aux_8259 as other; -static a: other::Foo<'static> = other::Foo::A; - -pub fn main() {} diff --git a/tests/ui/cross-crate/static-with-cross-crate-regions-8259.rs b/tests/ui/cross-crate/static-with-cross-crate-regions-8259.rs new file mode 100644 index 00000000000..347cfa2aee1 --- /dev/null +++ b/tests/ui/cross-crate/static-with-cross-crate-regions-8259.rs @@ -0,0 +1,11 @@ +// https://github.com/rust-lang/rust/issues/8259 +//@ run-pass +#![allow(dead_code)] +#![allow(non_upper_case_globals)] + +//@ aux-build:aux-8259.rs + +extern crate aux_8259 as other; +static a: other::Foo<'static> = other::Foo::A; + +pub fn main() {} diff --git a/tests/ui/cross-crate/tuple-struct-cross-crate-7899.rs b/tests/ui/cross-crate/tuple-struct-cross-crate-7899.rs new file mode 100644 index 00000000000..ce3ea7dd579 --- /dev/null +++ b/tests/ui/cross-crate/tuple-struct-cross-crate-7899.rs @@ -0,0 +1,10 @@ +// https://github.com/rust-lang/rust/issues/7899 +//@ run-pass +#![allow(unused_variables)] +//@ aux-build:aux-7899.rs + +extern crate aux_7899 as testcrate; + +fn main() { + let f = testcrate::V2(1.0f32, 2.0f32); +} diff --git a/tests/ui/function-pointer/function-pointer-comparison-54696.rs b/tests/ui/function-pointer/function-pointer-comparison-54696.rs new file mode 100644 index 00000000000..2e28dfeaaf8 --- /dev/null +++ b/tests/ui/function-pointer/function-pointer-comparison-54696.rs @@ -0,0 +1,11 @@ +// https://github.com/rust-lang/rust/issues/54696 +//@ run-pass + +#![allow(unpredictable_function_pointer_comparisons)] + +fn main() { + // We shouldn't promote this + let _ = &(main as fn() == main as fn()); + // Also check nested case + let _ = &(&(main as fn()) == &(main as fn())); +} diff --git a/tests/ui/issues/auxiliary/issue-7178.rs b/tests/ui/issues/auxiliary/issue-7178.rs deleted file mode 100644 index 56ae5139af4..00000000000 --- a/tests/ui/issues/auxiliary/issue-7178.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub struct Foo<'a, A:'a>(&'a A); - -impl<'a, A> Foo<'a, A> { - pub fn new(a: &'a A) -> Foo<'a, A> { - Foo(a) - } -} diff --git a/tests/ui/issues/issue-53419.rs b/tests/ui/issues/issue-53419.rs deleted file mode 100644 index 55d41f2005d..00000000000 --- a/tests/ui/issues/issue-53419.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ check-pass - -struct Foo { - bar: dyn for<'r> Fn(usize, &'r dyn FnMut()) -} - -fn main() { -} diff --git a/tests/ui/issues/issue-53568.rs b/tests/ui/issues/issue-53568.rs deleted file mode 100644 index 9862d4ced12..00000000000 --- a/tests/ui/issues/issue-53568.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Regression test for an NLL-related ICE (#53568) -- we failed to -// resolve inference variables in "custom type-ops". -// -//@ check-pass - -trait Future { - type Item; -} - -impl Future for F -where F: Fn() -> T -{ - type Item = T; -} - -trait Connect {} - -struct Connector { - handler: H, -} - -impl Connect for Connector -where - T: 'static, - H: Future -{ -} - -struct Client { - connector: C, -} - -fn build(_connector: C) -> Client { - unimplemented!() -} - -fn client(handler: H) -> Client -where H: Fn() + Copy -{ - let connector = Connector { - handler, - }; - let client = build(connector); - client -} - -fn main() { } diff --git a/tests/ui/issues/issue-53728.rs b/tests/ui/issues/issue-53728.rs deleted file mode 100644 index 364965228c6..00000000000 --- a/tests/ui/issues/issue-53728.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ run-pass - -#![allow(dead_code)] -#[repr(u16)] -enum DeviceKind { - Nil = 0, -} - -#[repr(packed)] -struct DeviceInfo { - endianness: u8, - device_kind: DeviceKind, -} - -fn main() { - let _x = None::<(DeviceInfo, u8)>; - let _y = None::<(DeviceInfo, u16)>; - let _z = None::<(DeviceInfo, u64)>; -} diff --git a/tests/ui/issues/issue-54094.rs b/tests/ui/issues/issue-54094.rs deleted file mode 100644 index 4ca7d1d81b6..00000000000 --- a/tests/ui/issues/issue-54094.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ check-pass -trait Zoo { - type X; -} - -impl Zoo for u16 { - type X = usize; -} - -fn foo(abc: ::X) {} - -fn main() { - let x: *const u8 = foo as _; -} diff --git a/tests/ui/issues/issue-54410.rs b/tests/ui/issues/issue-54410.rs deleted file mode 100644 index e3e8ca985b9..00000000000 --- a/tests/ui/issues/issue-54410.rs +++ /dev/null @@ -1,8 +0,0 @@ -extern "C" { - pub static mut symbol: [i8]; - //~^ ERROR the size for values of type `[i8]` cannot be known at compilation time -} - -fn main() { - println!("{:p}", unsafe { &symbol }); -} diff --git a/tests/ui/issues/issue-54410.stderr b/tests/ui/issues/issue-54410.stderr deleted file mode 100644 index cb68ada7e13..00000000000 --- a/tests/ui/issues/issue-54410.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0277]: the size for values of type `[i8]` cannot be known at compilation time - --> $DIR/issue-54410.rs:2:5 - | -LL | pub static mut symbol: [i8]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[i8]` - = note: statics and constants must have a statically known size - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/issues/issue-54462-mutable-noalias-correctness.rs b/tests/ui/issues/issue-54462-mutable-noalias-correctness.rs deleted file mode 100644 index 70d0bee7332..00000000000 --- a/tests/ui/issues/issue-54462-mutable-noalias-correctness.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ run-pass -// -//@ compile-flags: -Ccodegen-units=1 -O - -fn linidx(row: usize, col: usize) -> usize { - row * 1 + col * 3 -} - -fn main() { - let mut mat = [1.0f32, 5.0, 9.0, 2.0, 6.0, 10.0, 3.0, 7.0, 11.0, 4.0, 8.0, 12.0]; - - for i in 0..2 { - for j in i+1..3 { - if mat[linidx(j, 3)] > mat[linidx(i, 3)] { - for k in 0..4 { - let (x, rest) = mat.split_at_mut(linidx(i, k) + 1); - let a = x.last_mut().unwrap(); - let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap(); - ::std::mem::swap(a, b); - } - } - } - } - assert_eq!([9.0, 5.0, 1.0, 10.0, 6.0, 2.0, 11.0, 7.0, 3.0, 12.0, 8.0, 4.0], mat); -} diff --git a/tests/ui/issues/issue-54477-reduced-2.rs b/tests/ui/issues/issue-54477-reduced-2.rs deleted file mode 100644 index 5f65e545182..00000000000 --- a/tests/ui/issues/issue-54477-reduced-2.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ run-pass -// rust-lang/rust#54477: runtime bug in the VecDeque library that was -// exposed by this test case, derived from test suite of crates.io -// `collection` crate. - -use std::collections::VecDeque; - -fn main() { - let mut vecdeque_13 = VecDeque::from(vec![ ]); - let mut vecdeque_29 = VecDeque::from(vec![ 0 ]); - vecdeque_29.insert(0, 30 ); - vecdeque_29.insert(1, 31 ); - vecdeque_29.insert(2, 32 ); - vecdeque_29.insert(3, 33 ); - vecdeque_29.insert(4, 34 ); - vecdeque_29.insert(5, 35 ); - // println!("vecdeque_13: {:?}", vecdeque_13); - // println!("vecdeque_29: {:?}", vecdeque_29); - - // println!("Invoking: `vecdeque_13.append(&mut vecdeque_29)`"); - vecdeque_13.append(&mut vecdeque_29); - - // println!("vecdeque_13: {:?}", vecdeque_13); - - assert_eq!(vecdeque_13, VecDeque::from(vec![30, 31, 32, 33, 34, 35, 0])); -} diff --git a/tests/ui/issues/issue-54696.rs b/tests/ui/issues/issue-54696.rs deleted file mode 100644 index 63ffbe42bcc..00000000000 --- a/tests/ui/issues/issue-54696.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass - -#![allow(unpredictable_function_pointer_comparisons)] - -fn main() { - // We shouldn't promote this - let _ = &(main as fn() == main as fn()); - // Also check nested case - let _ = &(&(main as fn()) == &(main as fn())); -} diff --git a/tests/ui/issues/issue-55376.rs b/tests/ui/issues/issue-55376.rs deleted file mode 100644 index 5a6862b6530..00000000000 --- a/tests/ui/issues/issue-55376.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ run-pass -// Tests that paths in `pub(...)` don't fail HIR verification. - -#![allow(unused_imports)] -#![allow(dead_code)] - -pub(self) use self::my_mod::Foo; - -mod my_mod { - pub(super) use self::Foo as Bar; - pub(in super::my_mod) use self::Foo as Baz; - - pub struct Foo; -} - -fn main() {} diff --git a/tests/ui/issues/issue-55380.rs b/tests/ui/issues/issue-55380.rs deleted file mode 100644 index 54894cdede0..00000000000 --- a/tests/ui/issues/issue-55380.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ run-pass -#![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete - -pub trait Foo { - fn abc() -> u32; - fn def() -> u32; -} - -pub trait Marker {} - -impl Marker for () {} - -impl Foo for T { - default fn abc() -> u32 { 16 } - default fn def() -> u32 { 42 } -} - -impl Foo for T { - fn def() -> u32 { - Self::abc() - } -} - -fn main() { - assert_eq!(<()>::def(), 16); - assert_eq!(::def(), 42); -} diff --git a/tests/ui/issues/issue-55380.stderr b/tests/ui/issues/issue-55380.stderr deleted file mode 100644 index 403844c726f..00000000000 --- a/tests/ui/issues/issue-55380.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-55380.rs:2:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/issues/issue-7044.rs b/tests/ui/issues/issue-7044.rs deleted file mode 100644 index a6e22bc5237..00000000000 --- a/tests/ui/issues/issue-7044.rs +++ /dev/null @@ -1,4 +0,0 @@ -static X: isize = 0; -struct X; //~ ERROR the name `X` is defined multiple times - -fn main() {} diff --git a/tests/ui/issues/issue-7044.stderr b/tests/ui/issues/issue-7044.stderr deleted file mode 100644 index 9d1fb3a10dd..00000000000 --- a/tests/ui/issues/issue-7044.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0428]: the name `X` is defined multiple times - --> $DIR/issue-7044.rs:2:1 - | -LL | static X: isize = 0; - | -------------------- previous definition of the value `X` here -LL | struct X; - | ^^^^^^^^^ `X` redefined here - | - = note: `X` must be defined only once in the value namespace of this module - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0428`. diff --git a/tests/ui/issues/issue-7092.rs b/tests/ui/issues/issue-7092.rs deleted file mode 100644 index fab18bd7cf7..00000000000 --- a/tests/ui/issues/issue-7092.rs +++ /dev/null @@ -1,15 +0,0 @@ -enum Whatever { -} - -fn foo(x: Whatever) { - match x { //~ NOTE this expression has type `Whatever` - Some(field) => -//~^ ERROR mismatched types -//~| NOTE expected `Whatever`, found `Option<_>` -//~| NOTE expected enum `Whatever` -//~| NOTE found enum `Option<_>` - field.access(), - } -} - -fn main(){} diff --git a/tests/ui/issues/issue-7092.stderr b/tests/ui/issues/issue-7092.stderr deleted file mode 100644 index e2e57486746..00000000000 --- a/tests/ui/issues/issue-7092.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-7092.rs:6:9 - | -LL | match x { - | - this expression has type `Whatever` -LL | Some(field) => - | ^^^^^^^^^^^ expected `Whatever`, found `Option<_>` - | - = note: expected enum `Whatever` - found enum `Option<_>` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/issues/issue-7178.rs b/tests/ui/issues/issue-7178.rs deleted file mode 100644 index 408ce0b03eb..00000000000 --- a/tests/ui/issues/issue-7178.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass -//@ aux-build:issue-7178.rs - - -extern crate issue_7178 as cross_crate_self; - -pub fn main() { - let _ = cross_crate_self::Foo::new(&1); -} diff --git a/tests/ui/issues/issue-7268.rs b/tests/ui/issues/issue-7268.rs deleted file mode 100644 index a3bc1bc3446..00000000000 --- a/tests/ui/issues/issue-7268.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ check-pass -#![allow(dead_code)] - -fn foo(_: T) {} - -fn bar(x: &'static T) { - foo(x); -} -fn main() {} diff --git a/tests/ui/issues/issue-7344.rs b/tests/ui/issues/issue-7344.rs deleted file mode 100644 index 406b24634f5..00000000000 --- a/tests/ui/issues/issue-7344.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ run-pass -#![allow(unused_must_use)] - -#![allow(unreachable_code)] - -fn foo() -> bool { false } - -fn bar() { - return; - !foo(); -} - -fn baz() { - return; - if "" == "" {} -} - -pub fn main() { - bar(); - baz(); -} diff --git a/tests/ui/issues/issue-7364.rs b/tests/ui/issues/issue-7364.rs deleted file mode 100644 index 4ce9beb68cd..00000000000 --- a/tests/ui/issues/issue-7364.rs +++ /dev/null @@ -1,8 +0,0 @@ -use std::cell::RefCell; - -// Regression test for issue 7364 -static boxed: Box> = Box::new(RefCell::new(0)); -//~^ ERROR `RefCell` cannot be shared between threads safely [E0277] -//~| ERROR cannot call non-const associated function - -fn main() { } diff --git a/tests/ui/issues/issue-7364.stderr b/tests/ui/issues/issue-7364.stderr deleted file mode 100644 index a47a90c90ce..00000000000 --- a/tests/ui/issues/issue-7364.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0277]: `RefCell` cannot be shared between threads safely - --> $DIR/issue-7364.rs:4:15 - | -LL | static boxed: Box> = Box::new(RefCell::new(0)); - | ^^^^^^^^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely - | - = help: the trait `Sync` is not implemented for `RefCell` - = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead - = note: required for `Unique>` to implement `Sync` -note: required because it appears within the type `Box>` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - = note: shared static variables must have a type that implements `Sync` - -error[E0015]: cannot call non-const associated function `Box::>::new` in statics - --> $DIR/issue-7364.rs:4:37 - | -LL | static boxed: Box> = Box::new(RefCell::new(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0015, E0277. -For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/lifetimes/dyn-trait-function-pointer-53419.rs b/tests/ui/lifetimes/dyn-trait-function-pointer-53419.rs new file mode 100644 index 00000000000..b1017b104ac --- /dev/null +++ b/tests/ui/lifetimes/dyn-trait-function-pointer-53419.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust/issues/53419 +//@ check-pass + +struct Foo { + bar: dyn for<'r> Fn(usize, &'r dyn FnMut()) +} + +fn main() { +} diff --git a/tests/ui/lifetimes/static-bound-fulfillment-with-pointer-7268.rs b/tests/ui/lifetimes/static-bound-fulfillment-with-pointer-7268.rs new file mode 100644 index 00000000000..8ec58e6cd80 --- /dev/null +++ b/tests/ui/lifetimes/static-bound-fulfillment-with-pointer-7268.rs @@ -0,0 +1,10 @@ +// https://github.com/rust-lang/rust/issues/7268 +//@ check-pass +#![allow(dead_code)] + +fn foo(_: T) {} + +fn bar(x: &'static T) { + foo(x); +} +fn main() {} diff --git a/tests/ui/match/mismatched-types-in-match-7867.rs b/tests/ui/match/mismatched-types-in-match-7867.rs new file mode 100644 index 00000000000..9ff8755c819 --- /dev/null +++ b/tests/ui/match/mismatched-types-in-match-7867.rs @@ -0,0 +1,17 @@ +// https://github.com/rust-lang/rust/issues/7867 +//@ dont-require-annotations: NOTE + +enum A { B, C } + +mod foo { pub fn bar() {} } + +fn main() { + match (true, false) { + A::B => (), + //~^ ERROR mismatched types + //~| NOTE expected `(bool, bool)`, found `A` + //~| NOTE expected tuple `(bool, bool)` + //~| NOTE found enum `A` + _ => () + } +} diff --git a/tests/ui/match/mismatched-types-in-match-7867.stderr b/tests/ui/match/mismatched-types-in-match-7867.stderr new file mode 100644 index 00000000000..e41a61e42f4 --- /dev/null +++ b/tests/ui/match/mismatched-types-in-match-7867.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/mismatched-types-in-match-7867.rs:10:9 + | +LL | enum A { B, C } + | - unit variant defined here +... +LL | match (true, false) { + | ------------- this expression has type `(bool, bool)` +LL | A::B => (), + | ^^^^ expected `(bool, bool)`, found `A` + | + = note: expected tuple `(bool, bool)` + found enum `A` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/mismatched-types-in-match-pattern-7867.rs b/tests/ui/match/mismatched-types-in-match-pattern-7867.rs deleted file mode 100644 index 9ff8755c819..00000000000 --- a/tests/ui/match/mismatched-types-in-match-pattern-7867.rs +++ /dev/null @@ -1,17 +0,0 @@ -// https://github.com/rust-lang/rust/issues/7867 -//@ dont-require-annotations: NOTE - -enum A { B, C } - -mod foo { pub fn bar() {} } - -fn main() { - match (true, false) { - A::B => (), - //~^ ERROR mismatched types - //~| NOTE expected `(bool, bool)`, found `A` - //~| NOTE expected tuple `(bool, bool)` - //~| NOTE found enum `A` - _ => () - } -} diff --git a/tests/ui/match/mismatched-types-in-match-pattern-7867.stderr b/tests/ui/match/mismatched-types-in-match-pattern-7867.stderr deleted file mode 100644 index 8997f36114a..00000000000 --- a/tests/ui/match/mismatched-types-in-match-pattern-7867.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/mismatched-types-in-match-pattern-7867.rs:10:9 - | -LL | enum A { B, C } - | - unit variant defined here -... -LL | match (true, false) { - | ------------- this expression has type `(bool, bool)` -LL | A::B => (), - | ^^^^ expected `(bool, bool)`, found `A` - | - = note: expected tuple `(bool, bool)` - found enum `A` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/methods/trait-method-resolution-7575.rs b/tests/ui/methods/trait-method-resolution-7575.rs new file mode 100644 index 00000000000..9793d43cc24 --- /dev/null +++ b/tests/ui/methods/trait-method-resolution-7575.rs @@ -0,0 +1,18 @@ +// https://github.com/rust-lang/rust/issues/7575 +//@ run-pass + +trait Foo { //~ WARN trait `Foo` is never used + fn new() -> bool { false } + fn dummy(&self) { } +} + +trait Bar { + fn new(&self) -> bool { true } +} + +impl Bar for isize {} +impl Foo for isize {} + +fn main() { + assert!(1.new()); +} diff --git a/tests/ui/methods/trait-method-resolution-7575.stderr b/tests/ui/methods/trait-method-resolution-7575.stderr new file mode 100644 index 00000000000..8bbc360de57 --- /dev/null +++ b/tests/ui/methods/trait-method-resolution-7575.stderr @@ -0,0 +1,10 @@ +warning: trait `Foo` is never used + --> $DIR/trait-method-resolution-7575.rs:4:7 + | +LL | trait Foo { + | ^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default + +warning: 1 warning emitted + diff --git a/tests/ui/methods/trait-method-self-param-error-7575.rs b/tests/ui/methods/trait-method-self-param-error-7575.rs deleted file mode 100644 index 9793d43cc24..00000000000 --- a/tests/ui/methods/trait-method-self-param-error-7575.rs +++ /dev/null @@ -1,18 +0,0 @@ -// https://github.com/rust-lang/rust/issues/7575 -//@ run-pass - -trait Foo { //~ WARN trait `Foo` is never used - fn new() -> bool { false } - fn dummy(&self) { } -} - -trait Bar { - fn new(&self) -> bool { true } -} - -impl Bar for isize {} -impl Foo for isize {} - -fn main() { - assert!(1.new()); -} diff --git a/tests/ui/methods/trait-method-self-param-error-7575.stderr b/tests/ui/methods/trait-method-self-param-error-7575.stderr deleted file mode 100644 index 656db30352d..00000000000 --- a/tests/ui/methods/trait-method-self-param-error-7575.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: trait `Foo` is never used - --> $DIR/trait-method-self-param-error-7575.rs:4:7 - | -LL | trait Foo { - | ^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default - -warning: 1 warning emitted - diff --git a/tests/ui/modules/use-statement-duplicate-check-7663.rs b/tests/ui/modules/use-statement-duplicate-check-7663.rs new file mode 100644 index 00000000000..872806594fc --- /dev/null +++ b/tests/ui/modules/use-statement-duplicate-check-7663.rs @@ -0,0 +1,33 @@ +// https://github.com/rust-lang/rust/issues/7663 +//@ run-pass + +#![allow(unused_imports, dead_code)] + +mod test1 { + + mod foo { pub fn p() -> isize { 1 } } + mod bar { pub fn p() -> isize { 2 } } + + pub mod baz { + use crate::test1::bar::p; + + pub fn my_main() { assert_eq!(p(), 2); } + } +} + +mod test2 { + + mod foo { pub fn p() -> isize { 1 } } + mod bar { pub fn p() -> isize { 2 } } + + pub mod baz { + use crate::test2::bar::p; + + pub fn my_main() { assert_eq!(p(), 2); } + } +} + +fn main() { + test1::baz::my_main(); + test2::baz::my_main(); +} diff --git a/tests/ui/pattern/match-with-at-binding-8391.rs b/tests/ui/pattern/match-with-at-binding-8391.rs deleted file mode 100644 index bc4e7be7989..00000000000 --- a/tests/ui/pattern/match-with-at-binding-8391.rs +++ /dev/null @@ -1,10 +0,0 @@ -// https://github.com/rust-lang/rust/issues/8391 -//@ run-pass - -fn main() { - let x = match Some(1) { - ref _y @ Some(_) => 1, - None => 2, - }; - assert_eq!(x, 1); -} diff --git a/tests/ui/pattern/ref-in-function-parameter-patterns-8860.rs b/tests/ui/pattern/ref-in-function-parameter-patterns-8860.rs deleted file mode 100644 index 1a67caf021c..00000000000 --- a/tests/ui/pattern/ref-in-function-parameter-patterns-8860.rs +++ /dev/null @@ -1,52 +0,0 @@ -// https://github.com/rust-lang/rust/issues/8860 -//@ run-pass -// FIXME(static_mut_refs): this could use an atomic -#![allow(static_mut_refs)] -#![allow(dead_code)] - -static mut DROP: isize = 0; -static mut DROP_S: isize = 0; -static mut DROP_T: isize = 0; - -struct S; -impl Drop for S { - fn drop(&mut self) { - unsafe { - DROP_S += 1; - DROP += 1; - } - } -} -fn f(ref _s: S) {} - -struct T { i: isize } -impl Drop for T { - fn drop(&mut self) { - unsafe { - DROP_T += 1; - DROP += 1; - } - } -} -fn g(ref _t: T) {} - -fn do_test() { - let s = S; - f(s); - unsafe { - assert_eq!(1, DROP); - assert_eq!(1, DROP_S); - } - let t = T { i: 1 }; - g(t); - unsafe { assert_eq!(1, DROP_T); } -} - -fn main() { - do_test(); - unsafe { - assert_eq!(2, DROP); - assert_eq!(1, DROP_S); - assert_eq!(1, DROP_T); - } -} diff --git a/tests/ui/privacy/pub-restricted-path-usage-55376.rs b/tests/ui/privacy/pub-restricted-path-usage-55376.rs new file mode 100644 index 00000000000..ca4e27c30a8 --- /dev/null +++ b/tests/ui/privacy/pub-restricted-path-usage-55376.rs @@ -0,0 +1,17 @@ +// https://github.com/rust-lang/rust/issues/55376 +//@ run-pass +// Tests that paths in `pub(...)` don't fail HIR verification. + +#![allow(unused_imports)] +#![allow(dead_code)] + +pub(self) use self::my_mod::Foo; + +mod my_mod { + pub(super) use self::Foo as Bar; + pub(in super::my_mod) use self::Foo as Baz; + + pub struct Foo; +} + +fn main() {} diff --git a/tests/ui/repr/packed-struct-with-enum-53728.rs b/tests/ui/repr/packed-struct-with-enum-53728.rs new file mode 100644 index 00000000000..6ce65ed634f --- /dev/null +++ b/tests/ui/repr/packed-struct-with-enum-53728.rs @@ -0,0 +1,20 @@ +// https://github.com/rust-lang/rust/issues/53728 +//@ run-pass + +#![allow(dead_code)] +#[repr(u16)] +enum DeviceKind { + Nil = 0, +} + +#[repr(packed)] +struct DeviceInfo { + endianness: u8, + device_kind: DeviceKind, +} + +fn main() { + let _x = None::<(DeviceInfo, u8)>; + let _y = None::<(DeviceInfo, u16)>; + let _z = None::<(DeviceInfo, u64)>; +} diff --git a/tests/ui/resolve/module-import-resolution-7663.rs b/tests/ui/resolve/module-import-resolution-7663.rs deleted file mode 100644 index 872806594fc..00000000000 --- a/tests/ui/resolve/module-import-resolution-7663.rs +++ /dev/null @@ -1,33 +0,0 @@ -// https://github.com/rust-lang/rust/issues/7663 -//@ run-pass - -#![allow(unused_imports, dead_code)] - -mod test1 { - - mod foo { pub fn p() -> isize { 1 } } - mod bar { pub fn p() -> isize { 2 } } - - pub mod baz { - use crate::test1::bar::p; - - pub fn my_main() { assert_eq!(p(), 2); } - } -} - -mod test2 { - - mod foo { pub fn p() -> isize { 1 } } - mod bar { pub fn p() -> isize { 2 } } - - pub mod baz { - use crate::test2::bar::p; - - pub fn my_main() { assert_eq!(p(), 2); } - } -} - -fn main() { - test1::baz::my_main(); - test2::baz::my_main(); -} diff --git a/tests/ui/resolve/unit-like-struct-masks-constant-7044.rs b/tests/ui/resolve/unit-like-struct-masks-constant-7044.rs new file mode 100644 index 00000000000..f48dd695f01 --- /dev/null +++ b/tests/ui/resolve/unit-like-struct-masks-constant-7044.rs @@ -0,0 +1,5 @@ +// https://github.com/rust-lang/rust/issues/7044 +static X: isize = 0; +struct X; //~ ERROR the name `X` is defined multiple times + +fn main() {} diff --git a/tests/ui/resolve/unit-like-struct-masks-constant-7044.stderr b/tests/ui/resolve/unit-like-struct-masks-constant-7044.stderr new file mode 100644 index 00000000000..48aa6fce455 --- /dev/null +++ b/tests/ui/resolve/unit-like-struct-masks-constant-7044.stderr @@ -0,0 +1,13 @@ +error[E0428]: the name `X` is defined multiple times + --> $DIR/unit-like-struct-masks-constant-7044.rs:3:1 + | +LL | static X: isize = 0; + | -------------------- previous definition of the value `X` here +LL | struct X; + | ^^^^^^^^^ `X` redefined here + | + = note: `X` must be defined only once in the value namespace of this module + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0428`. diff --git a/tests/ui/specialization/trait-specialization-default-methods-55380.rs b/tests/ui/specialization/trait-specialization-default-methods-55380.rs new file mode 100644 index 00000000000..b3d79fb5ffb --- /dev/null +++ b/tests/ui/specialization/trait-specialization-default-methods-55380.rs @@ -0,0 +1,29 @@ +// https://github.com/rust-lang/rust/issues/55380 +//@ run-pass +#![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete + +pub trait Foo { + fn abc() -> u32; + fn def() -> u32; +} + +pub trait Marker {} + +impl Marker for () {} + +impl Foo for T { + default fn abc() -> u32 { 16 } + default fn def() -> u32 { 42 } +} + +impl Foo for T { + fn def() -> u32 { + Self::abc() + } +} + +fn main() { + assert_eq!(<()>::def(), 16); + assert_eq!(::def(), 42); +} diff --git a/tests/ui/specialization/trait-specialization-default-methods-55380.stderr b/tests/ui/specialization/trait-specialization-default-methods-55380.stderr new file mode 100644 index 00000000000..f7c1903da62 --- /dev/null +++ b/tests/ui/specialization/trait-specialization-default-methods-55380.stderr @@ -0,0 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-specialization-default-methods-55380.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/static/global-variable-promotion-error-7364.rs b/tests/ui/static/global-variable-promotion-error-7364.rs new file mode 100644 index 00000000000..dba4a484d61 --- /dev/null +++ b/tests/ui/static/global-variable-promotion-error-7364.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust/issues/7364 +use std::cell::RefCell; + +// Regression test for issue 7364 +static boxed: Box> = Box::new(RefCell::new(0)); +//~^ ERROR `RefCell` cannot be shared between threads safely [E0277] +//~| ERROR cannot call non-const associated function + +fn main() { } diff --git a/tests/ui/static/global-variable-promotion-error-7364.stderr b/tests/ui/static/global-variable-promotion-error-7364.stderr new file mode 100644 index 00000000000..b9d75676bef --- /dev/null +++ b/tests/ui/static/global-variable-promotion-error-7364.stderr @@ -0,0 +1,26 @@ +error[E0277]: `RefCell` cannot be shared between threads safely + --> $DIR/global-variable-promotion-error-7364.rs:5:15 + | +LL | static boxed: Box> = Box::new(RefCell::new(0)); + | ^^^^^^^^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `RefCell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead + = note: required for `Unique>` to implement `Sync` +note: required because it appears within the type `Box>` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + = note: shared static variables must have a type that implements `Sync` + +error[E0015]: cannot call non-const associated function `Box::>::new` in statics + --> $DIR/global-variable-promotion-error-7364.rs:5:37 + | +LL | static boxed: Box> = Box::new(RefCell::new(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/structs-enums/auxiliary/aux-8044.rs b/tests/ui/structs-enums/auxiliary/aux-8044.rs deleted file mode 100644 index 2ec25f51cde..00000000000 --- a/tests/ui/structs-enums/auxiliary/aux-8044.rs +++ /dev/null @@ -1,15 +0,0 @@ -pub struct BTree { - pub node: TreeItem, -} - -pub enum TreeItem { - TreeLeaf { value: V }, -} - -pub fn leaf(value: V) -> TreeItem { - TreeItem::TreeLeaf { value: value } -} - -fn main() { - BTree:: { node: leaf(1) }; -} diff --git a/tests/ui/structs-enums/struct-and-enum-usage-8044.rs b/tests/ui/structs-enums/struct-and-enum-usage-8044.rs deleted file mode 100644 index 9b544f33f1c..00000000000 --- a/tests/ui/structs-enums/struct-and-enum-usage-8044.rs +++ /dev/null @@ -1,10 +0,0 @@ -// https://github.com/rust-lang/rust/issues/8044 -//@ run-pass -//@ aux-build:aux-8044.rs - -extern crate aux_8044 as minimal; -use minimal::{BTree, leaf}; - -pub fn main() { - BTree:: { node: leaf(1) }; -} diff --git a/tests/ui/structs/auxiliary/aux-8044.rs b/tests/ui/structs/auxiliary/aux-8044.rs new file mode 100644 index 00000000000..2ec25f51cde --- /dev/null +++ b/tests/ui/structs/auxiliary/aux-8044.rs @@ -0,0 +1,15 @@ +pub struct BTree { + pub node: TreeItem, +} + +pub enum TreeItem { + TreeLeaf { value: V }, +} + +pub fn leaf(value: V) -> TreeItem { + TreeItem::TreeLeaf { value: value } +} + +fn main() { + BTree:: { node: leaf(1) }; +} diff --git a/tests/ui/structs/btree-struct-usage-8044.rs b/tests/ui/structs/btree-struct-usage-8044.rs new file mode 100644 index 00000000000..9b544f33f1c --- /dev/null +++ b/tests/ui/structs/btree-struct-usage-8044.rs @@ -0,0 +1,10 @@ +// https://github.com/rust-lang/rust/issues/8044 +//@ run-pass +//@ aux-build:aux-8044.rs + +extern crate aux_8044 as minimal; +use minimal::{BTree, leaf}; + +pub fn main() { + BTree:: { node: leaf(1) }; +} diff --git a/tests/ui/traits/nll-ice-custom-type-ops-53568.rs b/tests/ui/traits/nll-ice-custom-type-ops-53568.rs new file mode 100644 index 00000000000..9b240cdc190 --- /dev/null +++ b/tests/ui/traits/nll-ice-custom-type-ops-53568.rs @@ -0,0 +1,48 @@ +// https://github.com/rust-lang/rust/issues/53568 +// Regression test for an NLL-related ICE (#53568) -- we failed to +// resolve inference variables in "custom type-ops". +// +//@ check-pass + +trait Future { + type Item; +} + +impl Future for F +where F: Fn() -> T +{ + type Item = T; +} + +trait Connect {} + +struct Connector { + handler: H, +} + +impl Connect for Connector +where + T: 'static, + H: Future +{ +} + +struct Client { + connector: C, +} + +fn build(_connector: C) -> Client { + unimplemented!() +} + +fn client(handler: H) -> Client +where H: Fn() + Copy +{ + let connector = Connector { + handler, + }; + let client = build(connector); + client +} + +fn main() { } diff --git a/tests/ui/traits/self-implements-kinds-in-default-methods-8171.rs b/tests/ui/traits/self-implements-kinds-in-default-methods-8171.rs deleted file mode 100644 index 59ea62c7690..00000000000 --- a/tests/ui/traits/self-implements-kinds-in-default-methods-8171.rs +++ /dev/null @@ -1,19 +0,0 @@ -// https://github.com/rust-lang/rust/issues/8171 -//@ check-pass -#![allow(dead_code)] - -/* - -#8171 Self is not recognised as implementing kinds in default method implementations - -*/ - -fn require_send(_: T){} - -trait TragicallySelfIsNotSend: Send + Sized { - fn x(self) { - require_send(self); - } -} - -pub fn main(){} diff --git a/tests/ui/traits/self-not-send-in-default-method-8171.rs b/tests/ui/traits/self-not-send-in-default-method-8171.rs new file mode 100644 index 00000000000..59ea62c7690 --- /dev/null +++ b/tests/ui/traits/self-not-send-in-default-method-8171.rs @@ -0,0 +1,19 @@ +// https://github.com/rust-lang/rust/issues/8171 +//@ check-pass +#![allow(dead_code)] + +/* + +#8171 Self is not recognised as implementing kinds in default method implementations + +*/ + +fn require_send(_: T){} + +trait TragicallySelfIsNotSend: Send + Sized { + fn x(self) { + require_send(self); + } +} + +pub fn main(){} diff --git a/tests/ui/traits/trait-implementation-and-usage-7563.rs b/tests/ui/traits/trait-implementation-and-usage-7563.rs deleted file mode 100644 index 8cfc7a14ffe..00000000000 --- a/tests/ui/traits/trait-implementation-and-usage-7563.rs +++ /dev/null @@ -1,29 +0,0 @@ -// https://github.com/rust-lang/rust/issues/7563 -//@ run-pass -#![allow(dead_code)] -trait IDummy { - fn do_nothing(&self); -} - -#[derive(Debug)] -struct A { a: isize } -#[derive(Debug)] -struct B<'a> { b: isize, pa: &'a A } - - impl IDummy for A { - fn do_nothing(&self) { - println!("A::do_nothing() is called"); - } - } - -impl<'a> B<'a> { - fn get_pa(&self) -> &'a dyn IDummy { self.pa as &'a dyn IDummy } -} - -pub fn main() { - let sa = A { a: 100 }; - let sb = B { b: 200, pa: &sa }; - - println!("sa is {:?}", sa); - println!("sb is {:?}", sb); -} diff --git a/tests/ui/traits/trait-object-lifetime-bounds-7563.rs b/tests/ui/traits/trait-object-lifetime-bounds-7563.rs new file mode 100644 index 00000000000..8cfc7a14ffe --- /dev/null +++ b/tests/ui/traits/trait-object-lifetime-bounds-7563.rs @@ -0,0 +1,29 @@ +// https://github.com/rust-lang/rust/issues/7563 +//@ run-pass +#![allow(dead_code)] +trait IDummy { + fn do_nothing(&self); +} + +#[derive(Debug)] +struct A { a: isize } +#[derive(Debug)] +struct B<'a> { b: isize, pa: &'a A } + + impl IDummy for A { + fn do_nothing(&self) { + println!("A::do_nothing() is called"); + } + } + +impl<'a> B<'a> { + fn get_pa(&self) -> &'a dyn IDummy { self.pa as &'a dyn IDummy } +} + +pub fn main() { + let sa = A { a: 100 }; + let sb = B { b: 200, pa: &sa }; + + println!("sa is {:?}", sa); + println!("sb is {:?}", sb); +} diff --git a/tests/ui/unreachable-code/boolean-negation-in-unreachable-code-7344.rs b/tests/ui/unreachable-code/boolean-negation-in-unreachable-code-7344.rs new file mode 100644 index 00000000000..8fd091872c3 --- /dev/null +++ b/tests/ui/unreachable-code/boolean-negation-in-unreachable-code-7344.rs @@ -0,0 +1,22 @@ +// https://github.com/rust-lang/rust/issues/7344 +//@ run-pass +#![allow(unused_must_use)] + +#![allow(unreachable_code)] + +fn foo() -> bool { false } + +fn bar() { + return; + !foo(); +} + +fn baz() { + return; + if "" == "" {} +} + +pub fn main() { + bar(); + baz(); +} -- cgit 1.4.1-3-g733a5 From b4c8fe2b4bdbf8ff3e0b6a38e6027a431d1aca32 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 Aug 2025 08:08:40 +1000 Subject: Remove unnecessary `[dependencies.unicode-properties]` entries. The Cargo style guide says to put dependencies on a single line if they fit. --- compiler/rustc_data_structures/Cargo.toml | 4 +--- compiler/rustc_lexer/Cargo.toml | 6 +----- compiler/rustc_target/Cargo.toml | 7 +------ 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index aa964806a87..0ac9e02508a 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -13,6 +13,7 @@ ena = "0.14.3" indexmap = "2.4.0" jobserver_crate = { version = "0.1.28", package = "jobserver" } measureme = "12.0.1" +parking_lot = "0.12" rustc-hash = "2.0.0" rustc-stable-hash = { version = "0.1.0", features = ["nightly"] } rustc_arena = { path = "../rustc_arena" } @@ -34,9 +35,6 @@ version = "0.15.2" default-features = false features = ["nightly"] # for may_dangle -[dependencies.parking_lot] -version = "0.12" - [target.'cfg(windows)'.dependencies.windows] version = "0.61.0" features = [ diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml index b46f395a132..e0019fb1821 100644 --- a/compiler/rustc_lexer/Cargo.toml +++ b/compiler/rustc_lexer/Cargo.toml @@ -15,12 +15,8 @@ Rust lexer used by rustc. No stability guarantees are provided. # Note that this crate purposefully does not depend on other rustc crates [dependencies] memchr.workspace = true +unicode-properties = { version = "0.1.0", default-features = false, features = ["emoji"] } unicode-xid = "0.2.0" -[dependencies.unicode-properties] -version = "0.1.0" -default-features = false -features = ["emoji"] - [dev-dependencies] expect-test = "1.4.0" diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index 7ad2a332761..3c257bf38a5 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags.workspace = true +object = { version = "0.37.0", default-features = false, features = ["elf", "macho"] } rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_messages = { path = "../rustc_error_messages" } @@ -20,9 +21,3 @@ serde_path_to_error = "0.1.17" tracing.workspace = true # tidy-alphabetical-end -[dependencies.object] -# tidy-alphabetical-start -default-features = false -features = ["elf", "macho"] -version = "0.37.0" -# tidy-alphabetical-end -- cgit 1.4.1-3-g733a5 From 202eb0b375d1e5cfcf19a51f5a6b40d34d5fc0d1 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Thu, 28 Aug 2025 04:11:40 +0000 Subject: Prepare for merging from rust-lang/rust This updates the rust-version file to d36f964125163c2e698de5559efefb8217b8b7f0. --- library/compiler-builtins/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version index 3928504c857..8489eacfcda 100644 --- a/library/compiler-builtins/rust-version +++ b/library/compiler-builtins/rust-version @@ -1 +1 @@ -ffb9d94dcf4ade0d534842be3672d5e9f47e1333 +d36f964125163c2e698de5559efefb8217b8b7f0 -- cgit 1.4.1-3-g733a5 From d82a20e025701be09e87fbfa3a49bc4c2ae5662c Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Thu, 28 Aug 2025 09:09:15 +0000 Subject: Bump icu_list to 2.0 --- Cargo.lock | 232 +++++---------------- compiler/rustc_baked_icu_data/Cargo.toml | 9 +- compiler/rustc_baked_icu_data/src/data/any.rs | 2 - .../src/data/list_and_v1.rs.data | 55 +++++ .../data/locale_likely_subtags_language_v1.rs.data | 95 +++++++++ .../src/data/locale_parents_v1.rs.data | 85 ++++++++ compiler/rustc_baked_icu_data/src/data/macros.rs | 46 ---- .../data/macros/fallback_likelysubtags_v1.data.rs | 40 ---- .../src/data/macros/fallback_parents_v1.data.rs | 28 --- .../data/macros/fallback_supplement_co_v1.data.rs | 32 --- .../src/data/macros/list_and_v1.data.rs | 35 ---- compiler/rustc_baked_icu_data/src/data/mod.rs | 62 +++--- compiler/rustc_baked_icu_data/src/lib.rs | 41 ++-- compiler/rustc_error_messages/Cargo.toml | 6 +- compiler/rustc_error_messages/src/lib.rs | 27 +-- src/tools/tidy/src/deps.rs | 10 +- 16 files changed, 371 insertions(+), 434 deletions(-) delete mode 100644 compiler/rustc_baked_icu_data/src/data/any.rs create mode 100644 compiler/rustc_baked_icu_data/src/data/list_and_v1.rs.data create mode 100644 compiler/rustc_baked_icu_data/src/data/locale_likely_subtags_language_v1.rs.data create mode 100644 compiler/rustc_baked_icu_data/src/data/locale_parents_v1.rs.data delete mode 100644 compiler/rustc_baked_icu_data/src/data/macros.rs delete mode 100644 compiler/rustc_baked_icu_data/src/data/macros/fallback_likelysubtags_v1.data.rs delete mode 100644 compiler/rustc_baked_icu_data/src/data/macros/fallback_parents_v1.data.rs delete mode 100644 compiler/rustc_baked_icu_data/src/data/macros/fallback_supplement_co_v1.data.rs delete mode 100644 compiler/rustc_baked_icu_data/src/data/macros/list_and_v1.data.rs diff --git a/Cargo.lock b/Cargo.lock index af7c24abd13..1e4fbd952a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1674,77 +1674,53 @@ checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", "potential_utf", - "yoke 0.8.0", + "yoke", "zerofrom", - "zerovec 0.11.4", + "zerovec", ] [[package]] name = "icu_list" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfeda1d7775b6548edd4e8b7562304a559a91ed56ab56e18961a053f367c365" -dependencies = [ - "displaydoc", - "icu_list_data", - "icu_locid_transform", - "icu_provider 1.5.0", - "regex-automata 0.2.0", - "writeable 0.5.5", -] - -[[package]] -name = "icu_list_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52b1a7fbdbf3958f1be8354cb59ac73f165b7b7082d447ff2090355c9a069120" - -[[package]] -name = "icu_locale_core" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "e26f94ec776bb8b28cedc7dcf91033b822c5cb4c1783cf7a3f796fc168aa0c8b" dependencies = [ "displaydoc", - "litemap 0.8.0", - "tinystr 0.8.1", - "writeable 0.6.1", - "zerovec 0.11.4", + "icu_provider", + "regex-automata 0.4.9", + "serde", + "writeable", + "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "6ae5921528335e91da1b6c695dbf1ec37df5ac13faa3f91e5640be93aa2fbefd" dependencies = [ "displaydoc", - "litemap 0.7.5", - "tinystr 0.7.6", - "writeable 0.5.5", - "zerovec 0.10.4", + "icu_collections", + "icu_locale_core", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", ] [[package]] -name = "icu_locid_transform" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider 1.5.0", - "tinystr 0.7.6", - "zerovec 0.10.4", + "litemap", + "tinystr", + "writeable", + "zerovec", ] -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" version = "2.0.0" @@ -1755,9 +1731,9 @@ dependencies = [ "icu_collections", "icu_normalizer_data", "icu_properties", - "icu_provider 2.0.0", + "icu_provider", "smallvec", - "zerovec 0.11.4", + "zerovec", ] [[package]] @@ -1776,10 +1752,10 @@ dependencies = [ "icu_collections", "icu_locale_core", "icu_properties_data", - "icu_provider 2.0.0", + "icu_provider", "potential_utf", "zerotrie", - "zerovec 0.11.4", + "zerovec", ] [[package]] @@ -1788,23 +1764,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr 0.7.6", - "writeable 0.5.5", - "yoke 0.7.5", - "zerofrom", - "zerovec 0.10.4", -] - [[package]] name = "icu_provider" version = "2.0.0" @@ -1814,36 +1773,24 @@ dependencies = [ "displaydoc", "icu_locale_core", "stable_deref_trait", - "tinystr 0.8.1", - "writeable 0.6.1", - "yoke 0.8.0", + "tinystr", + "writeable", + "yoke", "zerofrom", "zerotrie", - "zerovec 0.11.4", + "zerovec", ] [[package]] name = "icu_provider_adapters" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6324dfd08348a8e0374a447ebd334044d766b1839bb8d5ccf2482a99a77c0bc" -dependencies = [ - "icu_locid", - "icu_locid_transform", - "icu_provider 1.5.0", - "tinystr 0.7.6", - "zerovec 0.10.4", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +checksum = "85c260e90e962088d46a1605687f78d3293cc3a34ba66b08ff7361084bc7895e" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", + "icu_locale", + "icu_provider", + "tinystr", + "zerovec", ] [[package]] @@ -2243,12 +2190,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" -[[package]] -name = "litemap" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" - [[package]] name = "litemap" version = "0.8.0" @@ -2959,7 +2900,8 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" dependencies = [ - "zerovec 0.11.4", + "serde", + "zerovec", ] [[package]] @@ -3205,15 +3147,6 @@ dependencies = [ "regex-syntax 0.6.29", ] -[[package]] -name = "regex-automata" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9368763f5a9b804326f3af749e16f9abf378d227bcdee7634b13d8f17793782" -dependencies = [ - "memchr", -] - [[package]] name = "regex-automata" version = "0.4.9" @@ -3488,10 +3421,9 @@ name = "rustc_baked_icu_data" version = "0.0.0" dependencies = [ "icu_list", - "icu_locid", - "icu_locid_transform", - "icu_provider 1.5.0", - "zerovec 0.10.4", + "icu_locale", + "icu_provider", + "zerovec", ] [[package]] @@ -3764,7 +3696,7 @@ dependencies = [ "fluent-bundle", "fluent-syntax", "icu_list", - "icu_locid", + "icu_locale", "icu_provider_adapters", "intl-memoizer", "rustc_ast", @@ -5497,16 +5429,6 @@ dependencies = [ "libc", ] -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec 0.10.4", -] - [[package]] name = "tinystr" version = "0.8.1" @@ -5514,7 +5436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", - "zerovec 0.11.4", + "zerovec", ] [[package]] @@ -5779,7 +5701,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658" dependencies = [ - "tinystr 0.8.1", + "tinystr", ] [[package]] @@ -5789,7 +5711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5957eb82e346d7add14182a3315a7e298f04e1ba4baac36f7f0dbfedba5fc25" dependencies = [ "proc-macro-hack", - "tinystr 0.8.1", + "tinystr", "unic-langid-impl", "unic-langid-macros-impl", ] @@ -6683,12 +6605,6 @@ dependencies = [ "wasmparser 0.237.0", ] -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - [[package]] name = "writeable" version = "0.6.1" @@ -6727,18 +6643,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive 0.7.5", - "zerofrom", -] - [[package]] name = "yoke" version = "0.8.0" @@ -6747,22 +6651,10 @@ checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", - "yoke-derive 0.8.0", + "yoke-derive", "zerofrom", ] -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", - "synstructure", -] - [[package]] name = "yoke-derive" version = "0.8.0" @@ -6823,19 +6715,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" dependencies = [ "displaydoc", - "yoke 0.8.0", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke 0.7.5", + "yoke", "zerofrom", - "zerovec-derive 0.10.3", ] [[package]] @@ -6844,20 +6725,9 @@ version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ - "yoke 0.8.0", + "yoke", "zerofrom", - "zerovec-derive 0.11.1", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", + "zerovec-derive", ] [[package]] diff --git a/compiler/rustc_baked_icu_data/Cargo.toml b/compiler/rustc_baked_icu_data/Cargo.toml index cb0e145386b..11bd079da0a 100644 --- a/compiler/rustc_baked_icu_data/Cargo.toml +++ b/compiler/rustc_baked_icu_data/Cargo.toml @@ -5,9 +5,8 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -icu_list = "1.2" -icu_locid = "1.2" -icu_locid_transform = "1.3.2" -icu_provider = { version = "1.2", features = ["sync"] } -zerovec = "0.10.0" +icu_list = { version = "2.0", default-features = false } +icu_locale = { version = "2.0", default-features = false } +icu_provider = { version = "2.0", features = ["baked", "sync"] } +zerovec = "0.11.0" # tidy-alphabetical-end diff --git a/compiler/rustc_baked_icu_data/src/data/any.rs b/compiler/rustc_baked_icu_data/src/data/any.rs deleted file mode 100644 index 23028876676..00000000000 --- a/compiler/rustc_baked_icu_data/src/data/any.rs +++ /dev/null @@ -1,2 +0,0 @@ -// @generated -impl_any_provider!(BakedDataProvider); diff --git a/compiler/rustc_baked_icu_data/src/data/list_and_v1.rs.data b/compiler/rustc_baked_icu_data/src/data/list_and_v1.rs.data new file mode 100644 index 00000000000..9d9137cc6e3 --- /dev/null +++ b/compiler/rustc_baked_icu_data/src/data/list_and_v1.rs.data @@ -0,0 +1,55 @@ +// @generated +/// Implement `DataProvider` on the given struct using the data +/// hardcoded in this file. This allows the struct to be used with +/// `icu`'s `_unstable` constructors. +/// +/// Using this implementation will embed the following data in the binary's data segment: +/// * 179B for the lookup data structure (33 data identifiers) +/// * 4183B[^1] for the actual data (11 unique structs) +/// +/// [^1]: these numbers can be smaller in practice due to linker deduplication +/// +/// This macro requires the following crates: +/// * `icu_list` +/// * `icu_provider` +/// * `icu_provider/baked` +/// * `zerovec` +#[doc(hidden)] +#[macro_export] +macro_rules! __impl_list_and_v1 { + ($ provider : ty) => { + #[clippy::msrv = "1.82"] + const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; + #[clippy::msrv = "1.82"] + impl $provider { + const DATA_LIST_AND_V1: icu_provider::baked::zerotrie::Data = { + const TRIE: icu_provider::baked::zerotrie::ZeroTrieSimpleAscii<&'static [u8]> = icu_provider::baked::zerotrie::ZeroTrieSimpleAscii { store: b"\xC8efijprtz\x18#.9DOZ\xC2ns\n\x1E\xC3NSW\x01\x02\x80\x85\x8A\x1E\xC3NSW\x01\x02\x81\x81\x81r\x1E\xC3NSW\x01\x02\x80\x86\x86t\x1E\xC3NSW\x01\x02\x82\x82\x82a\x1E\xC3NSW\x01\x02\x83\x83\x83t\x1E\xC3NSW\x01\x02\x80\x82\x82u\x1E\xC3NSW\x01\x02\x80\x87\x87r\x1E\xC3NSW\x01\x02\x80\x88\x88h\xC2\x1E-\t\xC3NSW\x01\x02\x83\x89\x89Han\xC2st\n\x1E\xC3NSW\x01\x02\x83\x89\x89\x1E\xC3NSW\x01\x02\x84\x89\x89" }; + const VALUES: &'static [::DataStruct] = &[icu_list::provider::ListFormatterPatterns { start: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, 2u8), middle: unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, end: icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, 2u8), special_case: None }, pair: None }, icu_list::provider::ListFormatterPatterns { start: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, 2u8), middle: unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, end: icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b" y ") }, 3u8), special_case: Some(icu_list::provider::SpecialCasePattern { condition: unsafe { icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(if cfg!(target_endian = "little") { b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x02\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\0\0\0\0\0\0\0\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\0\0\0\0\x01\0\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x06\0\0\0\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\x12\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" } else { b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x02\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x80\x01\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\x05\x05\x05\x06\x06\x0C\x0C\r\r\0\0\0\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\x02\0\x1B\0\0\0\0\0\x12\0\0\0\x12\0\0\x03\x06\x06\r\r\0\0\0\0\0h\0\0\0h\0\0\0\0\0\0\x0E\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\x01\n\0\0\x01\x19\0\0\0\x12\0\0\x02\x0F\x11\0\0\0\0\0D\0\0\0\0\0\0\x02\x11\x11\0\0\0\0\0\xBF\0\0\0\0\0\0\x02\x0F\x11\0\0\0\0\0\xBF\0\0\0\0\0\0\x02\x0F\x10\0\0\0\0\0\xBF\0\0\0\0\0\0\x02\x10\x11\0\0\0\0\0\xDD\0\0\0\0\0\0\x02\x0F\x11\0\0\0\0\0\xDD\0\0\0\0\0\0\x02\x0F\x0F\0\0\0\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\x03\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\0\0\0\0\0\0\0\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\0\0\0\0\x01\0\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x06\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\x12\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" }) }, pattern: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b" e ") }, 3u8) }) }, pair: None }, icu_list::provider::ListFormatterPatterns { start: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, 2u8), middle: unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, end: icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b" e ") }, 3u8), special_case: None }, pair: None }, icu_list::provider::ListFormatterPatterns { start: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b"\xE3\x80\x81") }, 3u8), middle: unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b"\xE3\x80\x81") }, end: icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b"\xE3\x80\x81") }, 3u8), special_case: None }, pair: None }, icu_list::provider::ListFormatterPatterns { start: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b"\xE3\x80\x81") }, 3u8), middle: unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b"\xE3\x80\x81") }, end: icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b"\xE5\x92\x8C") }, 3u8), special_case: None }, pair: Some(icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b"\xE3\x80\x81") }, 3u8), special_case: None }) }, icu_list::provider::ListFormatterPatterns { start: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, 2u8), middle: unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, end: icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", & ") }, 4u8), special_case: None }, pair: Some(icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b" & ") }, 3u8), special_case: None }) }, icu_list::provider::ListFormatterPatterns { start: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, 2u8), middle: unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, end: icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b" et ") }, 4u8), special_case: None }, pair: None }, icu_list::provider::ListFormatterPatterns { start: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, 2u8), middle: unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, end: icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b" \xD0\xB8 ") }, 4u8), special_case: None }, pair: None }, icu_list::provider::ListFormatterPatterns { start: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, 2u8), middle: unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, end: icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b" ve ") }, 4u8), special_case: None }, pair: None }, icu_list::provider::ListFormatterPatterns { start: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b"\xE3\x80\x81") }, 3u8), middle: unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b"\xE3\x80\x81") }, end: icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b"\xE5\x92\x8C") }, 3u8), special_case: None }, pair: None }, icu_list::provider::ListFormatterPatterns { start: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, 2u8), middle: unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") }, end: icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", and ") }, 6u8), special_case: None }, pair: Some(icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b" and ") }, 5u8), special_case: None }) }]; + unsafe { icu_provider::baked::zerotrie::Data::from_trie_and_values_unchecked(TRIE, VALUES) } + }; + } + #[clippy::msrv = "1.82"] + impl icu_provider::DataProvider for $provider { + fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { + let metadata = icu_provider::DataResponseMetadata::default(); + let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LIST_AND_V1, req.id, req.metadata.attributes_prefix_match) else { return Err(icu_provider::DataErrorKind::IdentifierNotFound.with_req(::INFO, req)) }; + Ok(icu_provider::DataResponse { payload, metadata }) + } + } + }; + ($ provider : ty , ITER) => { + __impl_list_and_v1!($provider); + #[clippy::msrv = "1.82"] + impl icu_provider::IterableDataProvider for $provider { + fn iter_ids(&self) -> Result>, icu_provider::DataError> { + Ok(icu_provider::baked::DataStore::iter(&Self::DATA_LIST_AND_V1).collect()) + } + } + }; + ($ provider : ty , DRY) => {}; + ($ provider : ty , DRY , ITER) => { + __impl_list_and_v1!($provider, ITER); + }; +} +#[doc(inline)] +pub use __impl_list_and_v1 as impl_list_and_v1; diff --git a/compiler/rustc_baked_icu_data/src/data/locale_likely_subtags_language_v1.rs.data b/compiler/rustc_baked_icu_data/src/data/locale_likely_subtags_language_v1.rs.data new file mode 100644 index 00000000000..0fbace0865d --- /dev/null +++ b/compiler/rustc_baked_icu_data/src/data/locale_likely_subtags_language_v1.rs.data @@ -0,0 +1,95 @@ +// @generated +/// Implement `DataProvider` on the given struct using the data +/// hardcoded in this file. This allows the struct to be used with +/// `icu`'s `_unstable` constructors. +/// +/// Using this implementation will embed the following data in the binary's data segment: +/// * 2310B[^1] for the singleton data struct +/// +/// [^1]: these numbers can be smaller in practice due to linker deduplication +/// +/// This macro requires the following crates: +/// * `icu_locale` +/// * `icu_locale_core` +/// * `icu_provider` +/// * `zerovec` +#[doc(hidden)] +#[macro_export] +macro_rules! __impl_locale_likely_subtags_language_v1 { + ($ provider : ty) => { + #[clippy::msrv = "1.82"] + const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; + #[clippy::msrv = "1.82"] + impl $provider { + #[doc(hidden)] + pub const SINGLETON_LOCALE_LIKELY_SUBTAGS_LANGUAGE_V1: &'static ::DataStruct = &icu_locale::provider::LikelySubtagsForLanguage { + language_script: unsafe { + #[allow(unused_unsafe)] + zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"az\0Araben\0Shawff\0Adlmkk\0Arabku\0Arabku\0Yeziky\0Arabky\0Latnmn\0Mongpa\0Arabsd\0Devasd\0Khojsd\0Sindtg\0Arabug\0Cyrluz\0ArabyueHanszh\0Bopozh\0Hanbzh\0Hant") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"IR\0GB\0GN\0CN\0IQ\0GE\0CN\0TR\0CN\0PK\0IN\0IN\0IN\0PK\0KZ\0AF\0CN\0TW\0TW\0TW\0") }) + }, + language_region: unsafe { + #[allow(unused_unsafe)] + zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"az\0IQ\0az\0IR\0az\0RU\0ha\0CM\0ha\0SD\0kk\0AF\0kk\0CN\0kk\0IR\0kk\0MN\0ku\0LB\0ky\0CN\0ky\0TR\0mn\0CN\0ms\0CC\0pa\0PK\0sd\0IN\0sr\0ME\0sr\0RO\0sr\0TR\0tg\0PK\0ug\0KZ\0ug\0MN\0uz\0AF\0uz\0CN\0yueCN\0zh\0AU\0zh\0BN\0zh\0GB\0zh\0GF\0zh\0HK\0zh\0ID\0zh\0MO\0zh\0PA\0zh\0PF\0zh\0PH\0zh\0SR\0zh\0TH\0zh\0TW\0zh\0US\0zh\0VN\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"ArabArabCyrlArabArabArabArabArabArabArabArabLatnMongArabArabDevaLatnLatnLatnArabCyrlCyrlArabCyrlHansHantHantHantHantHantHantHantHantHantHantHantHantHantHantHant") }) + }, + language: unsafe { + #[allow(unused_unsafe)] + zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"af\0ak\0am\0ar\0as\0astaz\0balbe\0bg\0bgcbhoblobn\0br\0brxbs\0ca\0cebchrcs\0cswcv\0cy\0da\0de\0doidsbee\0el\0en\0eo\0es\0et\0eu\0fa\0ff\0fi\0filfo\0fr\0fy\0ga\0gaagd\0gl\0gu\0ha\0he\0hi\0hr\0hsbhu\0hy\0ia\0id\0ie\0ig\0ii\0is\0it\0ja\0jv\0ka\0keakgpkk\0km\0kn\0ko\0kokks\0ku\0kxvky\0lb\0lijlmolo\0lt\0lv\0maimi\0mk\0ml\0mn\0mnimr\0ms\0mt\0my\0ndsne\0nl\0nn\0no\0nqonsooc\0om\0or\0pa\0pcmpl\0ps\0pt\0qu\0rajrm\0ro\0ru\0rw\0sa\0sahsatsc\0sd\0si\0sk\0sl\0so\0sq\0sr\0st\0su\0sv\0sw\0syrszlta\0te\0tg\0th\0ti\0tk\0tn\0to\0tr\0tt\0ug\0uk\0ur\0uz\0vecvi\0vmwwo\0xh\0xnryo\0yrlyueza\0zh\0zu\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"LatnZA\0LatnGH\0EthiET\0ArabEG\0BengIN\0LatnES\0LatnAZ\0ArabPK\0CyrlBY\0CyrlBG\0DevaIN\0DevaIN\0LatnBJ\0BengBD\0LatnFR\0DevaIN\0LatnBA\0LatnES\0LatnPH\0CherUS\0LatnCZ\0CansCA\0CyrlRU\0LatnGB\0LatnDK\0LatnDE\0DevaIN\0LatnDE\0LatnGH\0GrekGR\0LatnUS\0Latn001LatnES\0LatnEE\0LatnES\0ArabIR\0LatnSN\0LatnFI\0LatnPH\0LatnFO\0LatnFR\0LatnNL\0LatnIE\0LatnGH\0LatnGB\0LatnES\0GujrIN\0LatnNG\0HebrIL\0DevaIN\0LatnHR\0LatnDE\0LatnHU\0ArmnAM\0Latn001LatnID\0LatnEE\0LatnNG\0YiiiCN\0LatnIS\0LatnIT\0JpanJP\0LatnID\0GeorGE\0LatnCV\0LatnBR\0CyrlKZ\0KhmrKH\0KndaIN\0KoreKR\0DevaIN\0ArabIN\0LatnTR\0LatnIN\0CyrlKG\0LatnLU\0LatnIT\0LatnIT\0LaooLA\0LatnLT\0LatnLV\0DevaIN\0LatnNZ\0CyrlMK\0MlymIN\0CyrlMN\0BengIN\0DevaIN\0LatnMY\0LatnMT\0MymrMM\0LatnDE\0DevaNP\0LatnNL\0LatnNO\0LatnNO\0NkooGN\0LatnZA\0LatnFR\0LatnET\0OryaIN\0GuruIN\0LatnNG\0LatnPL\0ArabAF\0LatnBR\0LatnPE\0DevaIN\0LatnCH\0LatnRO\0CyrlRU\0LatnRW\0DevaIN\0CyrlRU\0OlckIN\0LatnIT\0ArabPK\0SinhLK\0LatnSK\0LatnSI\0LatnSO\0LatnAL\0CyrlRS\0LatnZA\0LatnID\0LatnSE\0LatnTZ\0SyrcIQ\0LatnPL\0TamlIN\0TeluIN\0CyrlTJ\0ThaiTH\0EthiET\0LatnTM\0LatnZA\0LatnTO\0LatnTR\0CyrlRU\0ArabCN\0CyrlUA\0ArabPK\0LatnUZ\0LatnIT\0LatnVN\0LatnMZ\0LatnSN\0LatnZA\0DevaIN\0LatnNG\0LatnBR\0HantHK\0LatnCN\0HansCN\0LatnZA\0") }) + }, + und: (icu_locale_core::subtags::language!("en"), icu_locale_core::subtags::script!("Latn"), icu_locale_core::subtags::region!("US")), + }; + } + #[clippy::msrv = "1.82"] + impl icu_provider::DataProvider for $provider { + fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { + if req.id.locale.is_unknown() { + Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_LOCALE_LIKELY_SUBTAGS_LANGUAGE_V1), metadata: icu_provider::DataResponseMetadata::default() }) + } else { + Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) + } + } + } + }; + ($ provider : ty , ITER) => { + __impl_locale_likely_subtags_language_v1!($provider); + #[clippy::msrv = "1.82"] + impl icu_provider::IterableDataProvider for $provider { + fn iter_ids(&self) -> Result>, icu_provider::DataError> { + Ok([Default::default()].into_iter().collect()) + } + } + }; + ($ provider : ty , DRY) => { + __impl_locale_likely_subtags_language_v1!($provider); + #[clippy::msrv = "1.82"] + impl icu_provider::DryDataProvider for $provider { + fn dry_load(&self, req: icu_provider::DataRequest) -> Result { + if req.id.locale.is_unknown() { + Ok(icu_provider::DataResponseMetadata::default()) + } else { + Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) + } + } + } + }; + ($ provider : ty , DRY , ITER) => { + __impl_locale_likely_subtags_language_v1!($provider); + #[clippy::msrv = "1.82"] + impl icu_provider::DryDataProvider for $provider { + fn dry_load(&self, req: icu_provider::DataRequest) -> Result { + if req.id.locale.is_unknown() { + Ok(icu_provider::DataResponseMetadata::default()) + } else { + Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) + } + } + } + #[clippy::msrv = "1.82"] + impl icu_provider::IterableDataProvider for $provider { + fn iter_ids(&self) -> Result>, icu_provider::DataError> { + Ok([Default::default()].into_iter().collect()) + } + } + }; +} +#[doc(inline)] +pub use __impl_locale_likely_subtags_language_v1 as impl_locale_likely_subtags_language_v1; diff --git a/compiler/rustc_baked_icu_data/src/data/locale_parents_v1.rs.data b/compiler/rustc_baked_icu_data/src/data/locale_parents_v1.rs.data new file mode 100644 index 00000000000..52527d90885 --- /dev/null +++ b/compiler/rustc_baked_icu_data/src/data/locale_parents_v1.rs.data @@ -0,0 +1,85 @@ +// @generated +/// Implement `DataProvider` on the given struct using the data +/// hardcoded in this file. This allows the struct to be used with +/// `icu`'s `_unstable` constructors. +/// +/// Using this implementation will embed the following data in the binary's data segment: +/// * 2846B[^1] for the singleton data struct +/// +/// [^1]: these numbers can be smaller in practice due to linker deduplication +/// +/// This macro requires the following crates: +/// * `icu_locale` +/// * `icu_provider` +/// * `zerovec` +#[doc(hidden)] +#[macro_export] +macro_rules! __impl_locale_parents_v1 { + ($ provider : ty) => { + #[clippy::msrv = "1.82"] + const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; + #[clippy::msrv = "1.82"] + impl $provider { + #[doc(hidden)] + pub const SINGLETON_LOCALE_PARENTS_V1: &'static ::DataStruct = &icu_locale::provider::Parents { + parents: unsafe { + #[allow(unused_unsafe)] + zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x93\0\x06\0\x0B\0\x10\0\x15\0\x1A\0\x1F\0$\0)\0.\x003\08\0=\0B\0G\0L\0Q\0V\0[\0`\0e\0j\0o\0t\0y\0~\0\x83\0\x88\0\x8D\0\x92\0\x97\0\x9C\0\xA1\0\xA6\0\xAB\0\xB0\0\xB5\0\xBA\0\xBF\0\xC4\0\xC9\0\xCE\0\xD3\0\xD8\0\xDD\0\xE2\0\xE7\0\xEC\0\xF1\0\xF6\0\xFB\0\0\x01\x05\x01\n\x01\x0F\x01\x14\x01\x19\x01\x1E\x01#\x01(\x01-\x012\x017\x01<\x01A\x01F\x01K\x01P\x01U\x01Z\x01_\x01d\x01i\x01n\x01s\x01x\x01}\x01\x82\x01\x87\x01\x8C\x01\x91\x01\x96\x01\x9B\x01\xA0\x01\xA5\x01\xAA\x01\xAF\x01\xB4\x01\xB9\x01\xBE\x01\xC3\x01\xC8\x01\xCD\x01\xD2\x01\xD7\x01\xDC\x01\xE1\x01\xE6\x01\xEB\x01\xF0\x01\xF5\x01\xFA\x01\xFF\x01\x04\x02\t\x02\x0E\x02\x13\x02\x18\x02\x1D\x02\"\x02'\x02,\x021\x026\x02;\x02@\x02E\x02J\x02O\x02T\x02Y\x02^\x02c\x02h\x02m\x02r\x02w\x02|\x02\x81\x02\x88\x02\x8A\x02\x8C\x02\x8E\x02\x93\x02\x98\x02\x9D\x02\xA2\x02\xA7\x02\xAC\x02\xB1\x02\xB6\x02\xBB\x02\xC0\x02\xC5\x02\xCA\x02\xD2\x02\xDA\x02en-150en-AGen-AIen-ATen-AUen-BBen-BEen-BMen-BSen-BWen-BZen-CCen-CHen-CKen-CMen-CXen-CYen-CZen-DEen-DGen-DKen-DMen-ERen-ESen-FIen-FJen-FKen-FMen-FRen-GBen-GDen-GGen-GHen-GIen-GMen-GSen-GYen-HKen-HUen-IDen-IEen-ILen-IMen-INen-IOen-ITen-JEen-JMen-KEen-KIen-KNen-KYen-LCen-LRen-LSen-MGen-MOen-MSen-MTen-MUen-MVen-MWen-MYen-NAen-NFen-NGen-NLen-NOen-NRen-NUen-NZen-PGen-PKen-PLen-PNen-PTen-PWen-ROen-RWen-SBen-SCen-SDen-SEen-SGen-SHen-SIen-SKen-SLen-SSen-SXen-SZen-TCen-TKen-TOen-TTen-TVen-TZen-UGen-VCen-VGen-VUen-WSen-ZAen-ZMen-ZWes-ARes-BOes-BRes-BZes-CLes-COes-CRes-CUes-DOes-ECes-GTes-HNes-JPes-MXes-NIes-PAes-PEes-PRes-PYes-SVes-USes-UYes-VEhi-Latnhtnbnnno-NOpt-AOpt-CHpt-CVpt-FRpt-GQpt-GWpt-LUpt-MOpt-MZpt-STpt-TLund-Hansund-Hantzh-Hant-MO") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419en\0\0\0\0\0\0\x01IN\0fr\0\0\0\0\0\0\x01HT\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0und\x01Hani\0\0\0\0und\x01Hani\0\0\0\0zh\0\x01Hant\x01HK\0") }) + }, + }; + } + #[clippy::msrv = "1.82"] + impl icu_provider::DataProvider for $provider { + fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { + if req.id.locale.is_unknown() { + Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_LOCALE_PARENTS_V1), metadata: icu_provider::DataResponseMetadata::default() }) + } else { + Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) + } + } + } + }; + ($ provider : ty , ITER) => { + __impl_locale_parents_v1!($provider); + #[clippy::msrv = "1.82"] + impl icu_provider::IterableDataProvider for $provider { + fn iter_ids(&self) -> Result>, icu_provider::DataError> { + Ok([Default::default()].into_iter().collect()) + } + } + }; + ($ provider : ty , DRY) => { + __impl_locale_parents_v1!($provider); + #[clippy::msrv = "1.82"] + impl icu_provider::DryDataProvider for $provider { + fn dry_load(&self, req: icu_provider::DataRequest) -> Result { + if req.id.locale.is_unknown() { + Ok(icu_provider::DataResponseMetadata::default()) + } else { + Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) + } + } + } + }; + ($ provider : ty , DRY , ITER) => { + __impl_locale_parents_v1!($provider); + #[clippy::msrv = "1.82"] + impl icu_provider::DryDataProvider for $provider { + fn dry_load(&self, req: icu_provider::DataRequest) -> Result { + if req.id.locale.is_unknown() { + Ok(icu_provider::DataResponseMetadata::default()) + } else { + Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) + } + } + } + #[clippy::msrv = "1.82"] + impl icu_provider::IterableDataProvider for $provider { + fn iter_ids(&self) -> Result>, icu_provider::DataError> { + Ok([Default::default()].into_iter().collect()) + } + } + }; +} +#[doc(inline)] +pub use __impl_locale_parents_v1 as impl_locale_parents_v1; diff --git a/compiler/rustc_baked_icu_data/src/data/macros.rs b/compiler/rustc_baked_icu_data/src/data/macros.rs deleted file mode 100644 index bee309f9b81..00000000000 --- a/compiler/rustc_baked_icu_data/src/data/macros.rs +++ /dev/null @@ -1,46 +0,0 @@ -// @generated -/// Marks a type as a data provider. You can then use macros like -/// `impl_core_helloworld_v1` to add implementations. -/// -/// ```ignore -/// struct MyProvider; -/// const _: () = { -/// include!("path/to/generated/macros.rs"); -/// make_provider!(MyProvider); -/// impl_core_helloworld_v1!(MyProvider); -/// } -/// ``` -#[doc(hidden)] -#[macro_export] -macro_rules! __make_provider { - ($ name : ty) => { - #[clippy::msrv = "1.66"] - impl $name { - #[doc(hidden)] - #[allow(dead_code)] - pub const MUST_USE_MAKE_PROVIDER_MACRO: () = (); - } - }; -} -#[doc(inline)] -pub use __make_provider as make_provider; -#[macro_use] -#[path = "macros/fallback_likelysubtags_v1.data.rs"] -mod fallback_likelysubtags_v1; -#[doc(inline)] -pub use __impl_fallback_likelysubtags_v1 as impl_fallback_likelysubtags_v1; -#[macro_use] -#[path = "macros/fallback_parents_v1.data.rs"] -mod fallback_parents_v1; -#[doc(inline)] -pub use __impl_fallback_parents_v1 as impl_fallback_parents_v1; -#[macro_use] -#[path = "macros/fallback_supplement_co_v1.data.rs"] -mod fallback_supplement_co_v1; -#[doc(inline)] -pub use __impl_fallback_supplement_co_v1 as impl_fallback_supplement_co_v1; -#[macro_use] -#[path = "macros/list_and_v1.data.rs"] -mod list_and_v1; -#[doc(inline)] -pub use __impl_list_and_v1 as impl_list_and_v1; diff --git a/compiler/rustc_baked_icu_data/src/data/macros/fallback_likelysubtags_v1.data.rs b/compiler/rustc_baked_icu_data/src/data/macros/fallback_likelysubtags_v1.data.rs deleted file mode 100644 index 1adb58743f7..00000000000 --- a/compiler/rustc_baked_icu_data/src/data/macros/fallback_likelysubtags_v1.data.rs +++ /dev/null @@ -1,40 +0,0 @@ -// @generated -/// Implement `DataProvider` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_fallback_likelysubtags_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.66"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.66"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_FALLBACK_LIKELYSUBTAGS_V1: &'static ::Yokeable = &icu_locid_transform::provider::LocaleFallbackLikelySubtagsV1 { - l2s: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"am\0ar\0as\0be\0bg\0bgcbhobn\0brxchrcv\0doiel\0fa\0gu\0he\0hi\0hy\0ja\0ka\0kk\0km\0kn\0ko\0kokks\0ky\0lo\0maimk\0ml\0mn\0mnimr\0my\0ne\0or\0pa\0ps\0rajru\0sa\0satsd\0si\0sr\0ta\0te\0tg\0th\0ti\0tt\0uk\0ur\0yuezh\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"EthiArabBengCyrlCyrlDevaDevaBengDevaCherCyrlDevaGrekArabGujrHebrDevaArmnJpanGeorCyrlKhmrKndaKoreDevaArabCyrlLaooDevaCyrlMlymCyrlBengDevaMymrDevaOryaGuruArabDevaCyrlDevaOlckArabSinhCyrlTamlTeluCyrlThaiEthiCyrlCyrlArabHantHans") }) - }, - lr2s: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap2d::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"az\0ha\0kk\0ky\0mn\0ms\0pa\0sd\0sr\0tg\0uz\0yuezh\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x03\0\0\0\x05\0\0\0\t\0\0\0\x0B\0\0\0\x0C\0\0\0\r\0\0\0\x0E\0\0\0\x0F\0\0\0\x13\0\0\0\x14\0\0\0\x16\0\0\0\x17\0\0\0&\0\0\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"IQ\0IR\0RU\0CM\0SD\0AF\0CN\0IR\0MN\0CN\0TR\0CN\0CC\0PK\0IN\0ME\0RO\0RU\0TR\0PK\0AF\0CN\0CN\0AU\0BN\0GB\0GF\0HK\0ID\0MO\0PA\0PF\0PH\0SR\0TH\0TW\0US\0VN\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"ArabArabCyrlArabArabArabArabArabArabArabLatnMongArabArabDevaLatnLatnLatnLatnArabArabCyrlHansHantHantHantHantHantHantHantHantHantHantHantHantHantHantHant") }) - }, - l2r: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"af\0am\0ar\0as\0astaz\0be\0bg\0bgcbhobn\0br\0brxbs\0ca\0cebchrcs\0cv\0cy\0da\0de\0doidsbel\0en\0es\0et\0eu\0fa\0ff\0fi\0filfo\0fr\0ga\0gd\0gl\0gu\0ha\0he\0hi\0hr\0hsbhu\0hy\0ia\0id\0ig\0is\0it\0ja\0jv\0ka\0keakgpkk\0km\0kn\0ko\0kokks\0ky\0lo\0lt\0lv\0maimi\0mk\0ml\0mn\0mnimr\0ms\0my\0ne\0nl\0nn\0no\0or\0pa\0pcmpl\0ps\0pt\0qu\0rajrm\0ro\0ru\0sa\0satsc\0sd\0si\0sk\0sl\0so\0sq\0sr\0su\0sv\0sw\0ta\0te\0tg\0th\0ti\0tk\0to\0tr\0tt\0uk\0ur\0uz\0vi\0wo\0xh\0yo\0yrlyuezh\0zu\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"ZA\0ET\0EG\0IN\0ES\0AZ\0BY\0BG\0IN\0IN\0BD\0FR\0IN\0BA\0ES\0PH\0US\0CZ\0RU\0GB\0DK\0DE\0IN\0DE\0GR\0US\0ES\0EE\0ES\0IR\0SN\0FI\0PH\0FO\0FR\0IE\0GB\0ES\0IN\0NG\0IL\0IN\0HR\0DE\0HU\0AM\x00001ID\0NG\0IS\0IT\0JP\0ID\0GE\0CV\0BR\0KZ\0KH\0IN\0KR\0IN\0IN\0KG\0LA\0LT\0LV\0IN\0NZ\0MK\0IN\0MN\0IN\0IN\0MY\0MM\0NP\0NL\0NO\0NO\0IN\0IN\0NG\0PL\0AF\0BR\0PE\0IN\0CH\0RO\0RU\0IN\0IN\0IT\0PK\0LK\0SK\0SI\0SO\0AL\0RS\0ID\0SE\0TZ\0IN\0IN\0TJ\0TH\0ET\0TM\0TO\0TR\0RU\0UA\0PK\0UZ\0VN\0SN\0ZA\0NG\0BR\0HK\0CN\0ZA\0") }) - }, - ls2r: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap2d::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"az\0en\0ff\0kk\0ky\0mn\0pa\0sd\0tg\0uz\0yuezh\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\0\0\0\x02\0\0\0\x03\0\0\0\x04\0\0\0\x06\0\0\0\x07\0\0\0\x08\0\0\0\x0B\0\0\0\x0C\0\0\0\r\0\0\0\x0E\0\0\0\x11\0\0\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"ArabShawAdlmArabArabLatnMongArabDevaKhojSindArabArabHansBopoHanbHant") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"IR\0GB\0GN\0CN\0CN\0TR\0CN\0PK\0IN\0IN\0IN\0PK\0AF\0CN\0TW\0TW\0TW\0") }) - }, - }; - } - #[clippy::msrv = "1.66"] - impl icu_provider::DataProvider for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - if req.locale.is_empty() { Ok(icu_provider::DataResponse { payload: Some(icu_provider::DataPayload::from_static_ref(Self::SINGLETON_FALLBACK_LIKELYSUBTAGS_V1)), metadata: Default::default() }) } else { Err(icu_provider::DataErrorKind::ExtraneousLocale.with_req(::KEY, req)) } - } - } - }; -} diff --git a/compiler/rustc_baked_icu_data/src/data/macros/fallback_parents_v1.data.rs b/compiler/rustc_baked_icu_data/src/data/macros/fallback_parents_v1.data.rs deleted file mode 100644 index 6f8d6590b08..00000000000 --- a/compiler/rustc_baked_icu_data/src/data/macros/fallback_parents_v1.data.rs +++ /dev/null @@ -1,28 +0,0 @@ -// @generated -/// Implement `DataProvider` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_fallback_parents_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.66"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.66"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_FALLBACK_PARENTS_V1: &'static ::Yokeable = &icu_locid_transform::provider::LocaleFallbackParentsV1 { - parents: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::VarZeroVec::from_bytes_unchecked(b"\x84\0\0\0\0\0\x06\0\x0B\0\x10\0\x15\0\x1A\0\x1F\0$\0)\0.\x003\08\0=\0B\0G\0L\0Q\0V\0[\0`\0e\0j\0o\0t\0y\0~\0\x83\0\x88\0\x8D\0\x92\0\x97\0\x9C\0\xA1\0\xA6\0\xAB\0\xB0\0\xB5\0\xBA\0\xBF\0\xC4\0\xC9\0\xCE\0\xD3\0\xD8\0\xDD\0\xE2\0\xE7\0\xEC\0\xF1\0\xF6\0\xFB\0\0\x01\x05\x01\n\x01\x0F\x01\x14\x01\x19\x01\x1E\x01#\x01(\x01-\x012\x017\x01<\x01A\x01F\x01K\x01P\x01U\x01Z\x01_\x01d\x01i\x01n\x01s\x01x\x01}\x01\x82\x01\x87\x01\x8C\x01\x91\x01\x96\x01\x9B\x01\xA0\x01\xA5\x01\xAA\x01\xAF\x01\xB4\x01\xB9\x01\xBE\x01\xC3\x01\xC8\x01\xCD\x01\xD2\x01\xD7\x01\xDC\x01\xE1\x01\xE6\x01\xEB\x01\xF0\x01\xF5\x01\xFA\x01\xFF\x01\x04\x02\t\x02\x0E\x02\x13\x02\x18\x02\x1D\x02\"\x02'\x02,\x021\x026\x02;\x02@\x02G\x02I\x02K\x02M\x02R\x02W\x02\\\x02a\x02f\x02k\x02p\x02u\x02z\x02\x7F\x02\x84\x02\x89\x02en-150en-AGen-AIen-ATen-AUen-BBen-BEen-BMen-BSen-BWen-BZen-CCen-CHen-CKen-CMen-CXen-CYen-DEen-DGen-DKen-DMen-ERen-FIen-FJen-FKen-FMen-GBen-GDen-GGen-GHen-GIen-GMen-GYen-HKen-IEen-ILen-IMen-INen-IOen-JEen-JMen-KEen-KIen-KNen-KYen-LCen-LRen-LSen-MGen-MOen-MSen-MTen-MUen-MVen-MWen-MYen-NAen-NFen-NGen-NLen-NRen-NUen-NZen-PGen-PKen-PNen-PWen-RWen-SBen-SCen-SDen-SEen-SGen-SHen-SIen-SLen-SSen-SXen-SZen-TCen-TKen-TOen-TTen-TVen-TZen-UGen-VCen-VGen-VUen-WSen-ZAen-ZMen-ZWes-ARes-BOes-BRes-BZes-CLes-COes-CRes-CUes-DOes-ECes-GTes-HNes-MXes-NIes-PAes-PEes-PRes-PYes-SVes-USes-UYes-VEhi-Latnhtnbnnno-NOpt-AOpt-CHpt-CVpt-FRpt-GQpt-GWpt-LUpt-MOpt-MZpt-STpt-TLzh-Hant-MO") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419en\0\0\0\0\0\0\x01IN\0fr\0\0\0\0\0\0\x01HT\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0zh\0\x01Hant\x01HK\0") }) - }, - }; - } - #[clippy::msrv = "1.66"] - impl icu_provider::DataProvider for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - if req.locale.is_empty() { Ok(icu_provider::DataResponse { payload: Some(icu_provider::DataPayload::from_static_ref(Self::SINGLETON_FALLBACK_PARENTS_V1)), metadata: Default::default() }) } else { Err(icu_provider::DataErrorKind::ExtraneousLocale.with_req(::KEY, req)) } - } - } - }; -} diff --git a/compiler/rustc_baked_icu_data/src/data/macros/fallback_supplement_co_v1.data.rs b/compiler/rustc_baked_icu_data/src/data/macros/fallback_supplement_co_v1.data.rs deleted file mode 100644 index 02eec37ee09..00000000000 --- a/compiler/rustc_baked_icu_data/src/data/macros/fallback_supplement_co_v1.data.rs +++ /dev/null @@ -1,32 +0,0 @@ -// @generated -/// Implement `DataProvider` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_fallback_supplement_co_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.66"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.66"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_FALLBACK_SUPPLEMENT_CO_V1: &'static ::Yokeable = &icu_locid_transform::provider::LocaleFallbackSupplementV1 { - parents: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::VarZeroVec::from_bytes_unchecked(b"\x01\0\0\0\0\0yue") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"zh\0\x01Hant\0\0\0\0") }) - }, - unicode_extension_defaults: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap2d::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"co") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x02\0\0\0") }, unsafe { zerovec::VarZeroVec::from_bytes_unchecked(b"\x02\0\0\0\0\0\x02\0zhzh-Hant") }, unsafe { zerovec::VarZeroVec::from_bytes_unchecked(b"\x02\0\0\0\0\0\x06\0pinyinstroke") }) - }, - }; - } - #[clippy::msrv = "1.66"] - impl icu_provider::DataProvider for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - if req.locale.is_empty() { Ok(icu_provider::DataResponse { payload: Some(icu_provider::DataPayload::from_static_ref(Self::SINGLETON_FALLBACK_SUPPLEMENT_CO_V1)), metadata: Default::default() }) } else { Err(icu_provider::DataErrorKind::ExtraneousLocale.with_req(::KEY, req)) } - } - } - }; -} diff --git a/compiler/rustc_baked_icu_data/src/data/macros/list_and_v1.data.rs b/compiler/rustc_baked_icu_data/src/data/macros/list_and_v1.data.rs deleted file mode 100644 index 186f706cdb2..00000000000 --- a/compiler/rustc_baked_icu_data/src/data/macros/list_and_v1.data.rs +++ /dev/null @@ -1,35 +0,0 @@ -// @generated -/// Implement `DataProvider` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_list_and_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.66"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.66"] - impl icu_provider::DataProvider for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - static EN_001: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static EN_IN: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", and ", 6u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static IT: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }]); - static PT: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static FR: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" et ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" et ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" et ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" et ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static TR: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" ve ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" ve ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" ve ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" ve ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static ES: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8), special_case: Some(icu_list::provider::SpecialCasePattern { condition: unsafe { icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(if cfg!(target_endian = "little") { b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" } else { b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" }) }, pattern: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8) }) }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8), special_case: Some(icu_list::provider::SpecialCasePattern { condition: unsafe { icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(if cfg!(target_endian = "little") { b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" } else { b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" }) }, pattern: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8) }) }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8), special_case: Some(icu_list::provider::SpecialCasePattern { condition: unsafe { icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(if cfg!(target_endian = "little") { b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" } else { b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" }) }, pattern: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8) }) }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8), special_case: Some(icu_list::provider::SpecialCasePattern { condition: unsafe { icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(if cfg!(target_endian = "little") { b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" } else { b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" }) }, pattern: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8) }) }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8), special_case: Some(icu_list::provider::SpecialCasePattern { condition: unsafe { icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(if cfg!(target_endian = "little") { b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" } else { b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" }) }, pattern: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8) }) }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8), special_case: Some(icu_list::provider::SpecialCasePattern { condition: unsafe { icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(if cfg!(target_endian = "little") { b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" } else { b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" }) }, pattern: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8) }) }]); - static RU: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" и ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" и ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" и ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" и ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static UND: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static EN: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", and ", 6u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", & ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" & ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static HI_LATN: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", aur ", 6u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" aur ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", aur ", 6u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" aur ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" aur ", 5u8), special_case: None }]); - static JA: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }]); - static ZH_HK: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("及", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("及", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("及", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("及", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("及", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("及", 3u8), special_case: None }]); - static ZH: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }]); - static ZH_HANT: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }]); - static VALUES: [&::Yokeable; 215usize] = [&EN, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_IN, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN, &EN_001, &EN, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &HI_LATN, &IT, &IT, &IT, &IT, &JA, &PT, &PT, &PT, &PT, &PT, &PT, &PT, &PT, &PT, &PT, &PT, &PT, &RU, &RU, &RU, &RU, &RU, &RU, &TR, &TR, &UND, &ZH, &ZH_HK, &ZH, &ZH, &ZH, &ZH_HANT, &ZH_HK, &ZH]; - static KEYS: [&str; 215usize] = ["en", "en-001", "en-150", "en-AE", "en-AG", "en-AI", "en-AS", "en-AT", "en-AU", "en-BB", "en-BE", "en-BI", "en-BM", "en-BS", "en-BW", "en-BZ", "en-CA", "en-CC", "en-CH", "en-CK", "en-CM", "en-CX", "en-CY", "en-DE", "en-DG", "en-DK", "en-DM", "en-ER", "en-FI", "en-FJ", "en-FK", "en-FM", "en-GB", "en-GD", "en-GG", "en-GH", "en-GI", "en-GM", "en-GU", "en-GY", "en-HK", "en-IE", "en-IL", "en-IM", "en-IN", "en-IO", "en-JE", "en-JM", "en-KE", "en-KI", "en-KN", "en-KY", "en-LC", "en-LR", "en-LS", "en-MG", "en-MH", "en-MO", "en-MP", "en-MS", "en-MT", "en-MU", "en-MV", "en-MW", "en-MY", "en-NA", "en-NF", "en-NG", "en-NL", "en-NR", "en-NU", "en-NZ", "en-PG", "en-PH", "en-PK", "en-PN", "en-PR", "en-PW", "en-RW", "en-SB", "en-SC", "en-SD", "en-SE", "en-SG", "en-SH", "en-SI", "en-SL", "en-SS", "en-SX", "en-SZ", "en-TC", "en-TK", "en-TO", "en-TT", "en-TV", "en-TZ", "en-UG", "en-UM", "en-VC", "en-VG", "en-VI", "en-VU", "en-WS", "en-ZA", "en-ZM", "en-ZW", "es", "es-419", "es-AR", "es-BO", "es-BR", "es-BZ", "es-CL", "es-CO", "es-CR", "es-CU", "es-DO", "es-EA", "es-EC", "es-GQ", "es-GT", "es-HN", "es-IC", "es-MX", "es-NI", "es-PA", "es-PE", "es-PH", "es-PR", "es-PY", "es-SV", "es-US", "es-UY", "es-VE", "fr", "fr-BE", "fr-BF", "fr-BI", "fr-BJ", "fr-BL", "fr-CA", "fr-CD", "fr-CF", "fr-CG", "fr-CH", "fr-CI", "fr-CM", "fr-DJ", "fr-DZ", "fr-GA", "fr-GF", "fr-GN", "fr-GP", "fr-GQ", "fr-HT", "fr-KM", "fr-LU", "fr-MA", "fr-MC", "fr-MF", "fr-MG", "fr-ML", "fr-MQ", "fr-MR", "fr-MU", "fr-NC", "fr-NE", "fr-PF", "fr-PM", "fr-RE", "fr-RW", "fr-SC", "fr-SN", "fr-SY", "fr-TD", "fr-TG", "fr-TN", "fr-VU", "fr-WF", "fr-YT", "hi-Latn", "it", "it-CH", "it-SM", "it-VA", "ja", "pt", "pt-AO", "pt-CH", "pt-CV", "pt-GQ", "pt-GW", "pt-LU", "pt-MO", "pt-MZ", "pt-PT", "pt-ST", "pt-TL", "ru", "ru-BY", "ru-KG", "ru-KZ", "ru-MD", "ru-UA", "tr", "tr-CY", "und", "zh", "zh-HK", "zh-Hans", "zh-Hans-HK", "zh-Hans-MO", "zh-Hant", "zh-MO", "zh-SG"]; - if let Ok(payload) = KEYS.binary_search_by(|k| req.locale.strict_cmp(k.as_bytes()).reverse()).map(|i| *unsafe { VALUES.get_unchecked(i) }) { Ok(icu_provider::DataResponse { payload: Some(icu_provider::DataPayload::from_static_ref(payload)), metadata: Default::default() }) } else { Err(icu_provider::DataErrorKind::MissingLocale.with_req(::KEY, req)) } - } - } - }; -} diff --git a/compiler/rustc_baked_icu_data/src/data/mod.rs b/compiler/rustc_baked_icu_data/src/data/mod.rs index 465689f0cb8..e8194680b01 100644 --- a/compiler/rustc_baked_icu_data/src/data/mod.rs +++ b/compiler/rustc_baked_icu_data/src/data/mod.rs @@ -1,31 +1,45 @@ // @generated -include!("macros.rs"); -macro_rules! impl_data_provider { - ($ provider : ty) => { - make_provider!($provider); - impl_fallback_likelysubtags_v1!($provider); - impl_fallback_parents_v1!($provider); - impl_fallback_supplement_co_v1!($provider); - impl_list_and_v1!($provider); +include!("locale_likely_subtags_language_v1.rs.data"); +include!("locale_parents_v1.rs.data"); +include!("list_and_v1.rs.data"); +/// Marks a type as a data provider. You can then use macros like +/// `impl_core_helloworld_v1` to add implementations. +/// +/// ```ignore +/// struct MyProvider; +/// const _: () = { +/// include!("path/to/generated/macros.rs"); +/// make_provider!(MyProvider); +/// impl_core_helloworld_v1!(MyProvider); +/// } +/// ``` +#[doc(hidden)] +#[macro_export] +macro_rules! __make_provider { + ($ name : ty) => { + #[clippy::msrv = "1.82"] + impl $name { + #[allow(dead_code)] + pub(crate) const MUST_USE_MAKE_PROVIDER_MACRO: () = (); + } + icu_provider::marker::impl_data_provider_never_marker!($name); }; } +#[doc(inline)] +pub use __make_provider as make_provider; +/// This macro requires the following crates: +/// * `icu_list` +/// * `icu_locale` +/// * `icu_locale_core` +/// * `icu_provider` +/// * `icu_provider/baked` +/// * `zerovec` #[allow(unused_macros)] -macro_rules! impl_any_provider { +macro_rules! impl_data_provider { ($ provider : ty) => { - #[clippy::msrv = "1.66"] - impl icu_provider::AnyProvider for $provider { - fn load_any(&self, key: icu_provider::DataKey, req: icu_provider::DataRequest) -> Result { - match key.hashed() { - h if h == ::KEY.hashed() => icu_provider::DataProvider::::load(self, req).map(icu_provider::DataResponse::wrap_into_any_response), - h if h == ::KEY.hashed() => icu_provider::DataProvider::::load(self, req).map(icu_provider::DataResponse::wrap_into_any_response), - h if h == ::KEY.hashed() => icu_provider::DataProvider::::load(self, req).map(icu_provider::DataResponse::wrap_into_any_response), - h if h == ::KEY.hashed() => icu_provider::DataProvider::::load(self, req).map(icu_provider::DataResponse::wrap_into_any_response), - _ => Err(icu_provider::DataErrorKind::MissingDataKey.with_req(key, req)), - } - } - } + make_provider!($provider); + impl_locale_likely_subtags_language_v1!($provider); + impl_locale_parents_v1!($provider); + impl_list_and_v1!($provider); }; } -#[clippy::msrv = "1.66"] -pub struct BakedDataProvider; -impl_data_provider!(BakedDataProvider); diff --git a/compiler/rustc_baked_icu_data/src/lib.rs b/compiler/rustc_baked_icu_data/src/lib.rs index f3f6522f575..5d40c32023f 100644 --- a/compiler/rustc_baked_icu_data/src/lib.rs +++ b/compiler/rustc_baked_icu_data/src/lib.rs @@ -14,10 +14,10 @@ //! To regenerate the data, run this command: //! //! ```text -//! icu4x-datagen -W --pretty --fingerprint --use-separate-crates \ -//! --format mod -l en es fr it ja pt ru tr zh zh-Hans zh-Hant \ -//! -k list/and@1 fallback/likelysubtags@1 fallback/parents@1 fallback/supplement/co@1 \ -//! --cldr-tag latest --icuexport-tag latest -o src/data +//! icu4x-datagen -W --pretty --use-separate-crates \ +//! --format baked --locales @en @es @fr @it @ja @pt @ru @tr @zh @zh-Hans @zh-Hant \ +//! -m ListAndV1 LocaleLikelySubtagsLanguageV1 LocaleParentsV1 \ +//! --no-internal-fallback --deduplication maximal -o src/data //! ``` // tidy-alphabetical-start @@ -29,26 +29,27 @@ // #![warn(unreachable_pub)] // don't use because this crate is mostly generated code // tidy-alphabetical-end -mod data { - include!("data/mod.rs"); - include!("data/any.rs"); -} +pub struct BakedDataProvider; -pub use data::BakedDataProvider; +include!("data/mod.rs"); +const _: () = { + use icu_provider::prelude::icu_locale_core; + impl_data_provider!(BakedDataProvider); +}; pub const fn baked_data_provider() -> BakedDataProvider { - data::BakedDataProvider + BakedDataProvider } pub mod supported_locales { - pub const EN: icu_locid::Locale = icu_locid::locale!("en"); - pub const ES: icu_locid::Locale = icu_locid::locale!("es"); - pub const FR: icu_locid::Locale = icu_locid::locale!("fr"); - pub const IT: icu_locid::Locale = icu_locid::locale!("it"); - pub const JA: icu_locid::Locale = icu_locid::locale!("ja"); - pub const PT: icu_locid::Locale = icu_locid::locale!("pt"); - pub const RU: icu_locid::Locale = icu_locid::locale!("ru"); - pub const TR: icu_locid::Locale = icu_locid::locale!("tr"); - pub const ZH_HANS: icu_locid::Locale = icu_locid::locale!("zh-Hans"); - pub const ZH_HANT: icu_locid::Locale = icu_locid::locale!("zh-Hant"); + pub const EN: icu_locale::Locale = icu_locale::locale!("en"); + pub const ES: icu_locale::Locale = icu_locale::locale!("es"); + pub const FR: icu_locale::Locale = icu_locale::locale!("fr"); + pub const IT: icu_locale::Locale = icu_locale::locale!("it"); + pub const JA: icu_locale::Locale = icu_locale::locale!("ja"); + pub const PT: icu_locale::Locale = icu_locale::locale!("pt"); + pub const RU: icu_locale::Locale = icu_locale::locale!("ru"); + pub const TR: icu_locale::Locale = icu_locale::locale!("tr"); + pub const ZH_HANS: icu_locale::Locale = icu_locale::locale!("zh-Hans"); + pub const ZH_HANT: icu_locale::Locale = icu_locale::locale!("zh-Hant"); } diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml index ce5106aae0a..b9f97a60fc3 100644 --- a/compiler/rustc_error_messages/Cargo.toml +++ b/compiler/rustc_error_messages/Cargo.toml @@ -7,9 +7,9 @@ edition = "2024" # tidy-alphabetical-start fluent-bundle = "0.16" fluent-syntax = "0.12" -icu_list = "1.2" -icu_locid = "1.2" -icu_provider_adapters = "1.2" +icu_list = { version = "2.0", default-features = false, features = ["alloc"] } +icu_locale = { version = "2.0", default-features = false } +icu_provider_adapters = "2.0" intl-memoizer = "0.5.1" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index d8bacbe762b..abc298ed4a3 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -15,7 +15,6 @@ use fluent_bundle::FluentResource; pub use fluent_bundle::types::FluentType; pub use fluent_bundle::{self, FluentArgs, FluentError, FluentValue}; use fluent_syntax::parser::ParserError; -use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker}; use intl_memoizer::concurrent::IntlLangMemoizer; use rustc_data_structures::sync::{DynSend, IntoDynSyncSend}; use rustc_macros::{Decodable, Encodable}; @@ -515,8 +514,8 @@ impl From> for MultiSpan { } } -fn icu_locale_from_unic_langid(lang: LanguageIdentifier) -> Option { - icu_locid::Locale::try_from_bytes(lang.to_string().as_bytes()).ok() +fn icu_locale_from_unic_langid(lang: LanguageIdentifier) -> Option { + icu_locale::Locale::try_from_str(&lang.to_string()).ok() } pub fn fluent_value_from_str_list_sep_by_and(l: Vec>) -> FluentValue<'_> { @@ -570,19 +569,21 @@ pub fn fluent_value_from_str_list_sep_by_and(l: Vec>) -> FluentValu { let baked_data_provider = rustc_baked_icu_data::baked_data_provider(); let locale_fallbacker = - LocaleFallbacker::try_new_with_any_provider(&baked_data_provider) + icu_locale::LocaleFallbacker::try_new_unstable(&baked_data_provider) .expect("Failed to create fallback provider"); - let data_provider = - LocaleFallbackProvider::new_with_fallbacker(baked_data_provider, locale_fallbacker); + let data_provider = icu_provider_adapters::fallback::LocaleFallbackProvider::new( + baked_data_provider, + locale_fallbacker, + ); let locale = icu_locale_from_unic_langid(lang) .unwrap_or_else(|| rustc_baked_icu_data::supported_locales::EN); - let list_formatter = - icu_list::ListFormatter::try_new_and_with_length_with_any_provider( - &data_provider, - &locale.into(), - icu_list::ListLength::Wide, - ) - .expect("Failed to create list formatter"); + let list_formatter = icu_list::ListFormatter::try_new_and_unstable( + &data_provider, + locale.into(), + icu_list::options::ListFormatterOptions::default() + .with_length(icu_list::options::ListLength::Wide), + ) + .expect("Failed to create list formatter"); Ok(MemoizableListFormatter(list_formatter)) } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 18d97a748ba..cf4156892e9 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -287,14 +287,12 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "gimli", "gsgdt", "hashbrown", + "icu_collections", "icu_list", - "icu_list_data", - "icu_locid", - "icu_locid_transform", - "icu_locid_transform_data", + "icu_locale", + "icu_locale_core", "icu_provider", "icu_provider_adapters", - "icu_provider_macros", "ident_case", "indexmap", "intl-memoizer", @@ -332,6 +330,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "polonius-engine", "portable-atomic", // dependency for platforms doesn't support `AtomicU64` in std "portable-atomic-util", + "potential_utf", "ppv-lite86", "proc-macro-hack", "proc-macro2", @@ -447,6 +446,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "zerocopy-derive", "zerofrom", "zerofrom-derive", + "zerotrie", "zerovec", "zerovec-derive", // tidy-alphabetical-end -- cgit 1.4.1-3-g733a5 From 359cbd205f4d8a1d4c3f03307fe2ca524c378340 Mon Sep 17 00:00:00 2001 From: Robert Bastian Date: Thu, 28 Aug 2025 09:48:54 +0000 Subject: Use default locale fallback data --- Cargo.lock | 20 ++--- compiler/rustc_baked_icu_data/Cargo.toml | 2 +- .../src/data/list_and_v1.rs.data | 20 ++++- .../data/locale_likely_subtags_language_v1.rs.data | 95 ---------------------- .../src/data/locale_parents_v1.rs.data | 85 ------------------- compiler/rustc_baked_icu_data/src/data/mod.rs | 7 +- compiler/rustc_baked_icu_data/src/lib.rs | 4 +- compiler/rustc_error_messages/Cargo.toml | 1 - compiler/rustc_error_messages/src/lib.rs | 10 +-- src/tools/tidy/src/deps.rs | 2 +- 10 files changed, 30 insertions(+), 216 deletions(-) delete mode 100644 compiler/rustc_baked_icu_data/src/data/locale_likely_subtags_language_v1.rs.data delete mode 100644 compiler/rustc_baked_icu_data/src/data/locale_parents_v1.rs.data diff --git a/Cargo.lock b/Cargo.lock index 1e4fbd952a8..0c4e757539f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1702,6 +1702,7 @@ dependencies = [ "displaydoc", "icu_collections", "icu_locale_core", + "icu_locale_data", "icu_provider", "potential_utf", "tinystr", @@ -1721,6 +1722,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "icu_locale_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fdef0c124749d06a743c69e938350816554eb63ac979166590e2b4ee4252765" + [[package]] name = "icu_normalizer" version = "2.0.0" @@ -1781,18 +1788,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_provider_adapters" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c260e90e962088d46a1605687f78d3293cc3a34ba66b08ff7361084bc7895e" -dependencies = [ - "icu_locale", - "icu_provider", - "tinystr", - "zerovec", -] - [[package]] name = "id-arena" version = "2.2.1" @@ -3697,7 +3692,6 @@ dependencies = [ "fluent-syntax", "icu_list", "icu_locale", - "icu_provider_adapters", "intl-memoizer", "rustc_ast", "rustc_ast_pretty", diff --git a/compiler/rustc_baked_icu_data/Cargo.toml b/compiler/rustc_baked_icu_data/Cargo.toml index 11bd079da0a..2f1ab7df379 100644 --- a/compiler/rustc_baked_icu_data/Cargo.toml +++ b/compiler/rustc_baked_icu_data/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start icu_list = { version = "2.0", default-features = false } -icu_locale = { version = "2.0", default-features = false } +icu_locale = { version = "2.0", default-features = false, features = ["compiled_data"] } icu_provider = { version = "2.0", features = ["baked", "sync"] } zerovec = "0.11.0" # tidy-alphabetical-end diff --git a/compiler/rustc_baked_icu_data/src/data/list_and_v1.rs.data b/compiler/rustc_baked_icu_data/src/data/list_and_v1.rs.data index 9d9137cc6e3..1d60e0085fc 100644 --- a/compiler/rustc_baked_icu_data/src/data/list_and_v1.rs.data +++ b/compiler/rustc_baked_icu_data/src/data/list_and_v1.rs.data @@ -11,6 +11,7 @@ /// /// This macro requires the following crates: /// * `icu_list` +/// * `icu_locale/compiled_data` /// * `icu_provider` /// * `icu_provider/baked` /// * `zerovec` @@ -31,8 +32,23 @@ macro_rules! __impl_list_and_v1 { #[clippy::msrv = "1.82"] impl icu_provider::DataProvider for $provider { fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - let metadata = icu_provider::DataResponseMetadata::default(); - let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LIST_AND_V1, req.id, req.metadata.attributes_prefix_match) else { return Err(icu_provider::DataErrorKind::IdentifierNotFound.with_req(::INFO, req)) }; + let mut metadata = icu_provider::DataResponseMetadata::default(); + let payload = if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LIST_AND_V1, req.id, req.metadata.attributes_prefix_match) { + payload + } else { + const FALLBACKER: icu_locale::fallback::LocaleFallbackerWithConfig<'static> = icu_locale::fallback::LocaleFallbacker::new().for_config(::INFO.fallback_config); + let mut fallback_iterator = FALLBACKER.fallback_for(req.id.locale.clone()); + loop { + if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LIST_AND_V1, icu_provider::DataIdentifierBorrowed::for_marker_attributes_and_locale(req.id.marker_attributes, fallback_iterator.get()), req.metadata.attributes_prefix_match) { + metadata.locale = Some(fallback_iterator.take()); + break payload; + } + if fallback_iterator.get().is_unknown() { + return Err(icu_provider::DataErrorKind::IdentifierNotFound.with_req(::INFO, req)); + } + fallback_iterator.step(); + } + }; Ok(icu_provider::DataResponse { payload, metadata }) } } diff --git a/compiler/rustc_baked_icu_data/src/data/locale_likely_subtags_language_v1.rs.data b/compiler/rustc_baked_icu_data/src/data/locale_likely_subtags_language_v1.rs.data deleted file mode 100644 index 0fbace0865d..00000000000 --- a/compiler/rustc_baked_icu_data/src/data/locale_likely_subtags_language_v1.rs.data +++ /dev/null @@ -1,95 +0,0 @@ -// @generated -/// Implement `DataProvider` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 2310B[^1] for the singleton data struct -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -/// -/// This macro requires the following crates: -/// * `icu_locale` -/// * `icu_locale_core` -/// * `icu_provider` -/// * `zerovec` -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_locale_likely_subtags_language_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.82"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.82"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_LOCALE_LIKELY_SUBTAGS_LANGUAGE_V1: &'static ::DataStruct = &icu_locale::provider::LikelySubtagsForLanguage { - language_script: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"az\0Araben\0Shawff\0Adlmkk\0Arabku\0Arabku\0Yeziky\0Arabky\0Latnmn\0Mongpa\0Arabsd\0Devasd\0Khojsd\0Sindtg\0Arabug\0Cyrluz\0ArabyueHanszh\0Bopozh\0Hanbzh\0Hant") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"IR\0GB\0GN\0CN\0IQ\0GE\0CN\0TR\0CN\0PK\0IN\0IN\0IN\0PK\0KZ\0AF\0CN\0TW\0TW\0TW\0") }) - }, - language_region: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"az\0IQ\0az\0IR\0az\0RU\0ha\0CM\0ha\0SD\0kk\0AF\0kk\0CN\0kk\0IR\0kk\0MN\0ku\0LB\0ky\0CN\0ky\0TR\0mn\0CN\0ms\0CC\0pa\0PK\0sd\0IN\0sr\0ME\0sr\0RO\0sr\0TR\0tg\0PK\0ug\0KZ\0ug\0MN\0uz\0AF\0uz\0CN\0yueCN\0zh\0AU\0zh\0BN\0zh\0GB\0zh\0GF\0zh\0HK\0zh\0ID\0zh\0MO\0zh\0PA\0zh\0PF\0zh\0PH\0zh\0SR\0zh\0TH\0zh\0TW\0zh\0US\0zh\0VN\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"ArabArabCyrlArabArabArabArabArabArabArabArabLatnMongArabArabDevaLatnLatnLatnArabCyrlCyrlArabCyrlHansHantHantHantHantHantHantHantHantHantHantHantHantHantHantHant") }) - }, - language: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"af\0ak\0am\0ar\0as\0astaz\0balbe\0bg\0bgcbhoblobn\0br\0brxbs\0ca\0cebchrcs\0cswcv\0cy\0da\0de\0doidsbee\0el\0en\0eo\0es\0et\0eu\0fa\0ff\0fi\0filfo\0fr\0fy\0ga\0gaagd\0gl\0gu\0ha\0he\0hi\0hr\0hsbhu\0hy\0ia\0id\0ie\0ig\0ii\0is\0it\0ja\0jv\0ka\0keakgpkk\0km\0kn\0ko\0kokks\0ku\0kxvky\0lb\0lijlmolo\0lt\0lv\0maimi\0mk\0ml\0mn\0mnimr\0ms\0mt\0my\0ndsne\0nl\0nn\0no\0nqonsooc\0om\0or\0pa\0pcmpl\0ps\0pt\0qu\0rajrm\0ro\0ru\0rw\0sa\0sahsatsc\0sd\0si\0sk\0sl\0so\0sq\0sr\0st\0su\0sv\0sw\0syrszlta\0te\0tg\0th\0ti\0tk\0tn\0to\0tr\0tt\0ug\0uk\0ur\0uz\0vecvi\0vmwwo\0xh\0xnryo\0yrlyueza\0zh\0zu\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"LatnZA\0LatnGH\0EthiET\0ArabEG\0BengIN\0LatnES\0LatnAZ\0ArabPK\0CyrlBY\0CyrlBG\0DevaIN\0DevaIN\0LatnBJ\0BengBD\0LatnFR\0DevaIN\0LatnBA\0LatnES\0LatnPH\0CherUS\0LatnCZ\0CansCA\0CyrlRU\0LatnGB\0LatnDK\0LatnDE\0DevaIN\0LatnDE\0LatnGH\0GrekGR\0LatnUS\0Latn001LatnES\0LatnEE\0LatnES\0ArabIR\0LatnSN\0LatnFI\0LatnPH\0LatnFO\0LatnFR\0LatnNL\0LatnIE\0LatnGH\0LatnGB\0LatnES\0GujrIN\0LatnNG\0HebrIL\0DevaIN\0LatnHR\0LatnDE\0LatnHU\0ArmnAM\0Latn001LatnID\0LatnEE\0LatnNG\0YiiiCN\0LatnIS\0LatnIT\0JpanJP\0LatnID\0GeorGE\0LatnCV\0LatnBR\0CyrlKZ\0KhmrKH\0KndaIN\0KoreKR\0DevaIN\0ArabIN\0LatnTR\0LatnIN\0CyrlKG\0LatnLU\0LatnIT\0LatnIT\0LaooLA\0LatnLT\0LatnLV\0DevaIN\0LatnNZ\0CyrlMK\0MlymIN\0CyrlMN\0BengIN\0DevaIN\0LatnMY\0LatnMT\0MymrMM\0LatnDE\0DevaNP\0LatnNL\0LatnNO\0LatnNO\0NkooGN\0LatnZA\0LatnFR\0LatnET\0OryaIN\0GuruIN\0LatnNG\0LatnPL\0ArabAF\0LatnBR\0LatnPE\0DevaIN\0LatnCH\0LatnRO\0CyrlRU\0LatnRW\0DevaIN\0CyrlRU\0OlckIN\0LatnIT\0ArabPK\0SinhLK\0LatnSK\0LatnSI\0LatnSO\0LatnAL\0CyrlRS\0LatnZA\0LatnID\0LatnSE\0LatnTZ\0SyrcIQ\0LatnPL\0TamlIN\0TeluIN\0CyrlTJ\0ThaiTH\0EthiET\0LatnTM\0LatnZA\0LatnTO\0LatnTR\0CyrlRU\0ArabCN\0CyrlUA\0ArabPK\0LatnUZ\0LatnIT\0LatnVN\0LatnMZ\0LatnSN\0LatnZA\0DevaIN\0LatnNG\0LatnBR\0HantHK\0LatnCN\0HansCN\0LatnZA\0") }) - }, - und: (icu_locale_core::subtags::language!("en"), icu_locale_core::subtags::script!("Latn"), icu_locale_core::subtags::region!("US")), - }; - } - #[clippy::msrv = "1.82"] - impl icu_provider::DataProvider for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_LOCALE_LIKELY_SUBTAGS_LANGUAGE_V1), metadata: icu_provider::DataResponseMetadata::default() }) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - }; - ($ provider : ty , ITER) => { - __impl_locale_likely_subtags_language_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::IterableDataProvider for $provider { - fn iter_ids(&self) -> Result>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; - ($ provider : ty , DRY) => { - __impl_locale_likely_subtags_language_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::DryDataProvider for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - }; - ($ provider : ty , DRY , ITER) => { - __impl_locale_likely_subtags_language_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::DryDataProvider for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - #[clippy::msrv = "1.82"] - impl icu_provider::IterableDataProvider for $provider { - fn iter_ids(&self) -> Result>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; -} -#[doc(inline)] -pub use __impl_locale_likely_subtags_language_v1 as impl_locale_likely_subtags_language_v1; diff --git a/compiler/rustc_baked_icu_data/src/data/locale_parents_v1.rs.data b/compiler/rustc_baked_icu_data/src/data/locale_parents_v1.rs.data deleted file mode 100644 index 52527d90885..00000000000 --- a/compiler/rustc_baked_icu_data/src/data/locale_parents_v1.rs.data +++ /dev/null @@ -1,85 +0,0 @@ -// @generated -/// Implement `DataProvider` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 2846B[^1] for the singleton data struct -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -/// -/// This macro requires the following crates: -/// * `icu_locale` -/// * `icu_provider` -/// * `zerovec` -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_locale_parents_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.82"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.82"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_LOCALE_PARENTS_V1: &'static ::DataStruct = &icu_locale::provider::Parents { - parents: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x93\0\x06\0\x0B\0\x10\0\x15\0\x1A\0\x1F\0$\0)\0.\x003\08\0=\0B\0G\0L\0Q\0V\0[\0`\0e\0j\0o\0t\0y\0~\0\x83\0\x88\0\x8D\0\x92\0\x97\0\x9C\0\xA1\0\xA6\0\xAB\0\xB0\0\xB5\0\xBA\0\xBF\0\xC4\0\xC9\0\xCE\0\xD3\0\xD8\0\xDD\0\xE2\0\xE7\0\xEC\0\xF1\0\xF6\0\xFB\0\0\x01\x05\x01\n\x01\x0F\x01\x14\x01\x19\x01\x1E\x01#\x01(\x01-\x012\x017\x01<\x01A\x01F\x01K\x01P\x01U\x01Z\x01_\x01d\x01i\x01n\x01s\x01x\x01}\x01\x82\x01\x87\x01\x8C\x01\x91\x01\x96\x01\x9B\x01\xA0\x01\xA5\x01\xAA\x01\xAF\x01\xB4\x01\xB9\x01\xBE\x01\xC3\x01\xC8\x01\xCD\x01\xD2\x01\xD7\x01\xDC\x01\xE1\x01\xE6\x01\xEB\x01\xF0\x01\xF5\x01\xFA\x01\xFF\x01\x04\x02\t\x02\x0E\x02\x13\x02\x18\x02\x1D\x02\"\x02'\x02,\x021\x026\x02;\x02@\x02E\x02J\x02O\x02T\x02Y\x02^\x02c\x02h\x02m\x02r\x02w\x02|\x02\x81\x02\x88\x02\x8A\x02\x8C\x02\x8E\x02\x93\x02\x98\x02\x9D\x02\xA2\x02\xA7\x02\xAC\x02\xB1\x02\xB6\x02\xBB\x02\xC0\x02\xC5\x02\xCA\x02\xD2\x02\xDA\x02en-150en-AGen-AIen-ATen-AUen-BBen-BEen-BMen-BSen-BWen-BZen-CCen-CHen-CKen-CMen-CXen-CYen-CZen-DEen-DGen-DKen-DMen-ERen-ESen-FIen-FJen-FKen-FMen-FRen-GBen-GDen-GGen-GHen-GIen-GMen-GSen-GYen-HKen-HUen-IDen-IEen-ILen-IMen-INen-IOen-ITen-JEen-JMen-KEen-KIen-KNen-KYen-LCen-LRen-LSen-MGen-MOen-MSen-MTen-MUen-MVen-MWen-MYen-NAen-NFen-NGen-NLen-NOen-NRen-NUen-NZen-PGen-PKen-PLen-PNen-PTen-PWen-ROen-RWen-SBen-SCen-SDen-SEen-SGen-SHen-SIen-SKen-SLen-SSen-SXen-SZen-TCen-TKen-TOen-TTen-TVen-TZen-UGen-VCen-VGen-VUen-WSen-ZAen-ZMen-ZWes-ARes-BOes-BRes-BZes-CLes-COes-CRes-CUes-DOes-ECes-GTes-HNes-JPes-MXes-NIes-PAes-PEes-PRes-PYes-SVes-USes-UYes-VEhi-Latnhtnbnnno-NOpt-AOpt-CHpt-CVpt-FRpt-GQpt-GWpt-LUpt-MOpt-MZpt-STpt-TLund-Hansund-Hantzh-Hant-MO") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419en\0\0\0\0\0\0\x01IN\0fr\0\0\0\0\0\0\x01HT\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0und\x01Hani\0\0\0\0und\x01Hani\0\0\0\0zh\0\x01Hant\x01HK\0") }) - }, - }; - } - #[clippy::msrv = "1.82"] - impl icu_provider::DataProvider for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_LOCALE_PARENTS_V1), metadata: icu_provider::DataResponseMetadata::default() }) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - }; - ($ provider : ty , ITER) => { - __impl_locale_parents_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::IterableDataProvider for $provider { - fn iter_ids(&self) -> Result>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; - ($ provider : ty , DRY) => { - __impl_locale_parents_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::DryDataProvider for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - }; - ($ provider : ty , DRY , ITER) => { - __impl_locale_parents_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::DryDataProvider for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - #[clippy::msrv = "1.82"] - impl icu_provider::IterableDataProvider for $provider { - fn iter_ids(&self) -> Result>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; -} -#[doc(inline)] -pub use __impl_locale_parents_v1 as impl_locale_parents_v1; diff --git a/compiler/rustc_baked_icu_data/src/data/mod.rs b/compiler/rustc_baked_icu_data/src/data/mod.rs index e8194680b01..3146188a8e7 100644 --- a/compiler/rustc_baked_icu_data/src/data/mod.rs +++ b/compiler/rustc_baked_icu_data/src/data/mod.rs @@ -1,6 +1,4 @@ // @generated -include!("locale_likely_subtags_language_v1.rs.data"); -include!("locale_parents_v1.rs.data"); include!("list_and_v1.rs.data"); /// Marks a type as a data provider. You can then use macros like /// `impl_core_helloworld_v1` to add implementations. @@ -29,8 +27,7 @@ macro_rules! __make_provider { pub use __make_provider as make_provider; /// This macro requires the following crates: /// * `icu_list` -/// * `icu_locale` -/// * `icu_locale_core` +/// * `icu_locale/compiled_data` /// * `icu_provider` /// * `icu_provider/baked` /// * `zerovec` @@ -38,8 +35,6 @@ pub use __make_provider as make_provider; macro_rules! impl_data_provider { ($ provider : ty) => { make_provider!($provider); - impl_locale_likely_subtags_language_v1!($provider); - impl_locale_parents_v1!($provider); impl_list_and_v1!($provider); }; } diff --git a/compiler/rustc_baked_icu_data/src/lib.rs b/compiler/rustc_baked_icu_data/src/lib.rs index 5d40c32023f..ea4c8242c62 100644 --- a/compiler/rustc_baked_icu_data/src/lib.rs +++ b/compiler/rustc_baked_icu_data/src/lib.rs @@ -16,8 +16,7 @@ //! ```text //! icu4x-datagen -W --pretty --use-separate-crates \ //! --format baked --locales @en @es @fr @it @ja @pt @ru @tr @zh @zh-Hans @zh-Hant \ -//! -m ListAndV1 LocaleLikelySubtagsLanguageV1 LocaleParentsV1 \ -//! --no-internal-fallback --deduplication maximal -o src/data +//! -m ListAndV1 -o src/data //! ``` // tidy-alphabetical-start @@ -33,7 +32,6 @@ pub struct BakedDataProvider; include!("data/mod.rs"); const _: () = { - use icu_provider::prelude::icu_locale_core; impl_data_provider!(BakedDataProvider); }; diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml index b9f97a60fc3..7d2dc20e136 100644 --- a/compiler/rustc_error_messages/Cargo.toml +++ b/compiler/rustc_error_messages/Cargo.toml @@ -9,7 +9,6 @@ fluent-bundle = "0.16" fluent-syntax = "0.12" icu_list = { version = "2.0", default-features = false, features = ["alloc"] } icu_locale = { version = "2.0", default-features = false } -icu_provider_adapters = "2.0" intl-memoizer = "0.5.1" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index abc298ed4a3..7b7843f6cf3 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -567,18 +567,10 @@ pub fn fluent_value_from_str_list_sep_by_and(l: Vec>) -> FluentValu where Self: Sized, { - let baked_data_provider = rustc_baked_icu_data::baked_data_provider(); - let locale_fallbacker = - icu_locale::LocaleFallbacker::try_new_unstable(&baked_data_provider) - .expect("Failed to create fallback provider"); - let data_provider = icu_provider_adapters::fallback::LocaleFallbackProvider::new( - baked_data_provider, - locale_fallbacker, - ); let locale = icu_locale_from_unic_langid(lang) .unwrap_or_else(|| rustc_baked_icu_data::supported_locales::EN); let list_formatter = icu_list::ListFormatter::try_new_and_unstable( - &data_provider, + &rustc_baked_icu_data::BakedDataProvider, locale.into(), icu_list::options::ListFormatterOptions::default() .with_length(icu_list::options::ListLength::Wide), diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index cf4156892e9..6974ede624a 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -291,8 +291,8 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "icu_list", "icu_locale", "icu_locale_core", + "icu_locale_data", "icu_provider", - "icu_provider_adapters", "ident_case", "indexmap", "intl-memoizer", -- cgit 1.4.1-3-g733a5 From 75060001c0acb03f4febebb81909175cd2798bca Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Aug 2025 20:00:19 +1000 Subject: Add an overlooked `tracing` to `[workspace.dependencies]`. --- compiler/rustc_ast/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 0b8ab7c391c..7f948a65220 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -16,5 +16,5 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec.workspace = true -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end -- cgit 1.4.1-3-g733a5 From 12dc789bc657b1f0b695c39f81de9269f8c709b4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Aug 2025 19:50:53 +1000 Subject: Add `libc` to `[workspace.dependencies]`. --- Cargo.toml | 3 +++ compiler/rustc_codegen_llvm/Cargo.toml | 2 +- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_driver_impl/Cargo.toml | 2 +- compiler/rustc_llvm/Cargo.toml | 2 +- compiler/rustc_metadata/Cargo.toml | 2 +- compiler/rustc_session/Cargo.toml | 4 +--- compiler/rustc_thread_pool/Cargo.toml | 2 +- src/tools/compiletest/Cargo.toml | 2 +- src/tools/run-make-support/Cargo.toml | 2 +- 11 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5003e107cc8..e9a030e7de1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,6 +63,9 @@ exclude = [ # tidy-alphabetical-start bitflags = "2.9.3" itertools = "0.12.1" +# FIXME: Remove this pin once this rustix issue is resolved +# https://github.com/bytecodealliance/rustix/issues/1496 +libc = "=0.2.174" memchr = "2.7.5" rustc-literal-escaper = "0.0.5" thin-vec = "0.2.14" diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 26d20acbe28..9cfa23ecd43 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -13,7 +13,7 @@ bitflags.workspace = true # by `rustc_codegen_ssa` via its `thorin-dwp` dependency. gimli = "0.31" itertools.workspace = true -libc = "0.2" +libc.workspace = true measureme = "12.0.1" object = { version = "0.37.0", default-features = false, features = ["std", "read"] } rustc-demangle = "0.1.21" diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 6b989a96488..123c7ba1f30 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -48,7 +48,7 @@ wasm-encoder = "0.219" [target.'cfg(unix)'.dependencies] # tidy-alphabetical-start -libc = "0.2.50" +libc.workspace = true # tidy-alphabetical-end [dependencies.object] diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 0ac9e02508a..c9e2d050c1b 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -47,7 +47,7 @@ features = [ [target.'cfg(unix)'.dependencies] # tidy-alphabetical-start -libc = "0.2" +libc.workspace = true # tidy-alphabetical-end [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 7e9af054aff..b4729d2871e 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -56,7 +56,7 @@ tracing.workspace = true [target.'cfg(all(unix, any(target_env = "gnu", target_os = "macos")))'.dependencies] # tidy-alphabetical-start -libc = "0.2" +libc.workspace = true # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index cd352ce3d0f..e74de453be2 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -libc = "0.2.73" +libc.workspace = true # tidy-alphabetical-end [build-dependencies] diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 4bb9e49ccce..019e951fa62 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -36,5 +36,5 @@ tracing.workspace = true [target.'cfg(target_os = "aix")'.dependencies] # tidy-alphabetical-start -libc = "0.2" +libc.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 97789b198a4..5870fb29ae8 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -27,10 +27,8 @@ tracing.workspace = true # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] -# FIXME: Remove this pin once this rustix issue is resolved -# https://github.com/bytecodealliance/rustix/issues/1496 # tidy-alphabetical-start -libc = "=0.2.174" +libc.workspace = true # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] diff --git a/compiler/rustc_thread_pool/Cargo.toml b/compiler/rustc_thread_pool/Cargo.toml index c92984470b7..3eafb308192 100644 --- a/compiler/rustc_thread_pool/Cargo.toml +++ b/compiler/rustc_thread_pool/Cargo.toml @@ -23,7 +23,7 @@ rand_xorshift = "0.4" scoped-tls = "1.0" [target.'cfg(unix)'.dev-dependencies] -libc = "0.2" +libc.workspace = true [[test]] name = "stack_overflow_crash" diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 220c29cec49..4b932c7cbd2 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -35,7 +35,7 @@ walkdir = "2" # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] -libc = "0.2" +libc.workspace = true [target.'cfg(windows)'.dependencies] miow = "0.6" diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 250e0f65a9f..a87089d12b6 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -12,7 +12,7 @@ edition = "2024" # tidy-alphabetical-start bstr = "1.12" gimli = "0.32" -libc = "0.2" +libc.workspace = true object = "0.37" regex = "1.11" serde_json = "1.0" -- cgit 1.4.1-3-g733a5 From daf6fe2c1b51877d027453191ec648f52fc0ea8c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Aug 2025 19:58:21 +1000 Subject: Add `serde_json` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_codegen_llvm/Cargo.toml | 2 +- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- compiler/rustc_driver_impl/Cargo.toml | 2 +- compiler/rustc_errors/Cargo.toml | 2 +- compiler/rustc_feature/Cargo.toml | 2 +- compiler/rustc_monomorphize/Cargo.toml | 2 +- compiler/rustc_target/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 2 +- src/tools/build-manifest/Cargo.toml | 2 +- src/tools/collect-license-metadata/Cargo.toml | 2 +- src/tools/compiletest/Cargo.toml | 2 +- src/tools/features-status-dump/Cargo.toml | 2 +- src/tools/generate-copyright/Cargo.toml | 2 +- src/tools/jsondocck/Cargo.toml | 2 +- src/tools/jsondoclint/Cargo.toml | 2 +- src/tools/lint-docs/Cargo.toml | 2 +- src/tools/opt-dist/Cargo.toml | 2 +- src/tools/run-make-support/Cargo.toml | 2 +- 19 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e9a030e7de1..8d8f3612d64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ itertools = "0.12.1" libc = "=0.2.174" memchr = "2.7.5" rustc-literal-escaper = "0.0.5" +serde_json = "1.0.142" thin-vec = "0.2.14" tracing = "0.1.37" # tidy-alphabetical-end diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 9cfa23ecd43..18c5189a402 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -38,7 +38,7 @@ rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } serde = { version = "1", features = ["derive"] } -serde_json = "1" +serde_json.workspace = true smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 123c7ba1f30..8588b5bf327 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -37,7 +37,7 @@ rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -serde_json = "1.0.59" +serde_json.workspace = true smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tempfile = "3.2" thin-vec.workspace = true diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index b4729d2871e..196c8aa3547 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -49,7 +49,7 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } -serde_json = "1.0.59" +serde_json.workspace = true shlex = "1.0" tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index f5853855673..67a17ce88fa 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -21,7 +21,7 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } serde = { version = "1.0.125", features = ["derive"] } -serde_json = "1.0.59" +serde_json.workspace = true termcolor = "1.2.0" termize = "0.2" tracing.workspace = true diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml index a4746ac455c..b58f2375852 100644 --- a/compiler/rustc_feature/Cargo.toml +++ b/compiler/rustc_feature/Cargo.toml @@ -9,5 +9,5 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_span = { path = "../rustc_span" } serde = { version = "1.0.125", features = ["derive"] } -serde_json = "1.0.59" +serde_json.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index b11084cf169..78266d3c6d8 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -16,6 +16,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } serde = "1" -serde_json = "1" +serde_json.workspace = true tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index 3c257bf38a5..ed59ee2a575 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -16,7 +16,7 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } serde = "1.0.219" serde_derive = "1.0.219" -serde_json = "1.0.59" +serde_json.workspace = true serde_path_to_error = "0.1.17" tracing.workspace = true # tidy-alphabetical-end diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 02a3a4e0de4..d34b4af2d95 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -19,7 +19,7 @@ pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +serde_json.workspace = true smallvec = "1.8.1" stringdex = { version = "0.0.1-alpha4" } tempfile = "3" diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index efa99f181b3..05d5f21c12c 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] toml = "0.7" serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +serde_json.workspace = true anyhow = "1.0.32" flate2 = "1.0.26" xz2 = "0.1.7" diff --git a/src/tools/collect-license-metadata/Cargo.toml b/src/tools/collect-license-metadata/Cargo.toml index edf9e5c5393..7f2e57ced05 100644 --- a/src/tools/collect-license-metadata/Cargo.toml +++ b/src/tools/collect-license-metadata/Cargo.toml @@ -8,5 +8,5 @@ license = "MIT OR Apache-2.0" [dependencies] anyhow = "1.0.65" serde = { version = "1.0.147", features = ["derive"] } -serde_json = "1.0.85" +serde_json.workspace = true spdx-rs = "0.5.1" diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 4b932c7cbd2..6f21c7db487 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -27,7 +27,7 @@ regex = "1.0" rustfix = "0.8.1" semver = { version = "1.0.23", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +serde_json.workspace = true tracing-subscriber = { version = "0.3.3", default-features = false, features = ["ansi", "env-filter", "fmt", "parking_lot", "smallvec"] } tracing.workspace = true unified-diff = "0.2.1" diff --git a/src/tools/features-status-dump/Cargo.toml b/src/tools/features-status-dump/Cargo.toml index b2976f14a01..d72555da486 100644 --- a/src/tools/features-status-dump/Cargo.toml +++ b/src/tools/features-status-dump/Cargo.toml @@ -8,5 +8,5 @@ edition = "2021" anyhow = { version = "1" } clap = { version = "4", features = ["derive"] } serde = { version = "1.0.125", features = [ "derive" ] } -serde_json = "1.0.59" +serde_json.workspace = true tidy = { path = "../tidy", features = ["build-metrics"] } diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml index bcb3165de45..5edf1f3d88b 100644 --- a/src/tools/generate-copyright/Cargo.toml +++ b/src/tools/generate-copyright/Cargo.toml @@ -11,5 +11,5 @@ anyhow = "1.0.65" askama = "0.14.0" cargo_metadata = "0.21" serde = { version = "1.0.147", features = ["derive"] } -serde_json = "1.0.85" +serde_json.workspace = true thiserror = "1" diff --git a/src/tools/jsondocck/Cargo.toml b/src/tools/jsondocck/Cargo.toml index 80fc26cbe66..92fde363882 100644 --- a/src/tools/jsondocck/Cargo.toml +++ b/src/tools/jsondocck/Cargo.toml @@ -8,5 +8,5 @@ jsonpath-rust = "1.0.0" getopts = "0.2" regex = "1.4" shlex = "1.0" -serde_json = "1.0" +serde_json.workspace = true fs-err = "2.5.0" diff --git a/src/tools/jsondoclint/Cargo.toml b/src/tools/jsondoclint/Cargo.toml index cc8ecefd530..d8cd59f7b42 100644 --- a/src/tools/jsondoclint/Cargo.toml +++ b/src/tools/jsondoclint/Cargo.toml @@ -12,4 +12,4 @@ fs-err = "2.8.1" rustc-hash = "2.0.0" rustdoc-json-types = { version = "0.1.0", path = "../../rustdoc-json-types" } serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0.85" +serde_json.workspace = true diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml index 6e1ab84ed18..7af4b72e5b4 100644 --- a/src/tools/lint-docs/Cargo.toml +++ b/src/tools/lint-docs/Cargo.toml @@ -8,6 +8,6 @@ description = "A script to extract the lint documentation for the rustc book." [dependencies] rustc-literal-escaper = "0.0.5" -serde_json = "1.0.57" +serde_json.workspace = true tempfile = "3.1.0" walkdir = "2.3.1" diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index f4051ae67d7..e419a75f5f2 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -15,7 +15,7 @@ fs_extra = "1" camino = "1" tar = "0.4" xz = { version = "0.1", package = "xz2" } -serde_json = "1" +serde_json.workspace = true glob = "0.3" tempfile = "3.5" derive_builder = "0.20" diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index a87089d12b6..86ac4b9d7b4 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -15,7 +15,7 @@ gimli = "0.32" libc.workspace = true object = "0.37" regex = "1.11" -serde_json = "1.0" +serde_json.workspace = true similar = "2.7" wasmparser = { version = "0.236", default-features = false, features = ["std", "features", "validate"] } # tidy-alphabetical-end -- cgit 1.4.1-3-g733a5 From d263d3a88ce2d339a16587fdb60d60a208ea4f6b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Aug 2025 20:03:15 +1000 Subject: Add `either` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_borrowck/Cargo.toml | 2 +- compiler/rustc_const_eval/Cargo.toml | 2 +- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_mir_transform/Cargo.toml | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8d8f3612d64..d7408cd48ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ exclude = [ [workspace.dependencies] # tidy-alphabetical-start bitflags = "2.9.3" +either = "1.15.0" itertools = "0.12.1" # FIXME: Remove this pin once this rustix issue is resolved # https://github.com/bytecodealliance/rustix/issues/1496 diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index 3162e9da1ba..c0311ff414d 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -either = "1.5.0" +either.workspace = true itertools.workspace = true polonius-engine = "0.13.0" rustc_abi = { path = "../rustc_abi" } diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index 88dfc83f7fc..4f5e5eaa74c 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -either = "1" +either.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index c9e2d050c1b..d8d9d35cfc1 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start arrayvec = { version = "0.7", default-features = false } bitflags.workspace = true -either = "1.0" +either.workspace = true elsa = "1.11.0" ena = "0.14.3" indexmap = "2.4.0" diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 782066981c9..b6e20017bbf 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags.workspace = true -either = "1.5.0" +either.workspace = true gsgdt = "0.1.2" polonius-engine = "0.13.0" rustc_abi = { path = "../rustc_abi" } diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index 16acec15e92..99ef67e2625 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -either = "1" +either.workspace = true itertools.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } -- cgit 1.4.1-3-g733a5 From 1ed566026633c20f7bbb2d1d5edcf558dcb7ef37 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Aug 2025 20:07:35 +1000 Subject: Add `proc-macro2` and `quote` to `[workspace.dependencies]`. --- Cargo.toml | 2 ++ compiler/rustc_fluent_macro/Cargo.toml | 4 ++-- compiler/rustc_index_macros/Cargo.toml | 4 ++-- compiler/rustc_macros/Cargo.toml | 4 ++-- compiler/rustc_type_ir_macros/Cargo.toml | 4 ++-- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d7408cd48ae..68c4ad46587 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,8 @@ itertools = "0.12.1" # https://github.com/bytecodealliance/rustix/issues/1496 libc = "=0.2.174" memchr = "2.7.5" +proc-macro2 = "1.0.101" +quote = "1.0.40" rustc-literal-escaper = "0.0.5" serde_json = "1.0.142" thin-vec = "0.2.14" diff --git a/compiler/rustc_fluent_macro/Cargo.toml b/compiler/rustc_fluent_macro/Cargo.toml index d7ef4280aef..60afd9aca87 100644 --- a/compiler/rustc_fluent_macro/Cargo.toml +++ b/compiler/rustc_fluent_macro/Cargo.toml @@ -11,8 +11,8 @@ proc-macro = true annotate-snippets = "0.11" fluent-bundle = "0.16" fluent-syntax = "0.12" -proc-macro2 = "1" -quote = "1" +proc-macro2.workspace = true +quote.workspace = true syn = { version = "2", features = ["full"] } unic-langid = { version = "0.9.0", features = ["macros"] } # tidy-alphabetical-end diff --git a/compiler/rustc_index_macros/Cargo.toml b/compiler/rustc_index_macros/Cargo.toml index 34f3109a526..8593bde2615 100644 --- a/compiler/rustc_index_macros/Cargo.toml +++ b/compiler/rustc_index_macros/Cargo.toml @@ -8,8 +8,8 @@ proc-macro = true [dependencies] # tidy-alphabetical-start -proc-macro2 = "1" -quote = "1" +proc-macro2.workspace = true +quote.workspace = true syn = { version = "2.0.9", features = ["full", "extra-traits"] } # tidy-alphabetical-end diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml index f9d3b758359..5add2691b88 100644 --- a/compiler/rustc_macros/Cargo.toml +++ b/compiler/rustc_macros/Cargo.toml @@ -8,8 +8,8 @@ proc-macro = true [dependencies] # tidy-alphabetical-start -proc-macro2 = "1" -quote = "1" +proc-macro2.workspace = true +quote.workspace = true syn = { version = "2.0.9", features = ["full"] } synstructure = "0.13.0" # tidy-alphabetical-end diff --git a/compiler/rustc_type_ir_macros/Cargo.toml b/compiler/rustc_type_ir_macros/Cargo.toml index 15a55575099..29a2cc89033 100644 --- a/compiler/rustc_type_ir_macros/Cargo.toml +++ b/compiler/rustc_type_ir_macros/Cargo.toml @@ -8,8 +8,8 @@ proc-macro = true [dependencies] # tidy-alphabetical-start -proc-macro2 = "1" -quote = "1" +proc-macro2.workspace = true +quote.workspace = true syn = { version = "2.0.9", features = ["full"] } synstructure = "0.13.0" # tidy-alphabetical-end -- cgit 1.4.1-3-g733a5 From ce02d34b2faa2f4b43bb438bf4f7021d54e79c92 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Aug 2025 20:11:34 +1000 Subject: Add `rustc_apfloat` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_const_eval/Cargo.toml | 2 +- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_mir_build/Cargo.toml | 2 +- compiler/rustc_pattern_analysis/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 68c4ad46587..d0949510384 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,6 +71,7 @@ memchr = "2.7.5" proc-macro2 = "1.0.101" quote = "1.0.40" rustc-literal-escaper = "0.0.5" +rustc_apfloat = "0.2.3" serde_json = "1.0.142" thin-vec = "0.2.14" tracing = "0.1.37" diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index 4f5e5eaa74c..acf19b0f2fc 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start either.workspace = true rustc_abi = { path = "../rustc_abi" } -rustc_apfloat = "0.2.0" +rustc_apfloat.workspace = true rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index b6e20017bbf..ae27c3bbf67 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -10,7 +10,7 @@ either.workspace = true gsgdt = "0.1.2" polonius-engine = "0.13.0" rustc_abi = { path = "../rustc_abi" } -rustc_apfloat = "0.2.0" +rustc_apfloat.workspace = true rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_ast_ir = { path = "../rustc_ast_ir" } diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index c3f7fdfcb00..440cb0bdbf3 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start itertools.workspace = true rustc_abi = { path = "../rustc_abi" } -rustc_apfloat = "0.2.0" +rustc_apfloat.workspace = true rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index 39f660c8771..45f43822b5c 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start rustc-hash = "2.0.0" rustc_abi = { path = "../rustc_abi", optional = true } -rustc_apfloat = "0.2.0" +rustc_apfloat.workspace = true rustc_arena = { path = "../rustc_arena", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_errors = { path = "../rustc_errors", optional = true } -- cgit 1.4.1-3-g733a5 From 77d2f0c16e0c3957052a3ecaccd9479be8efed87 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Aug 2025 20:15:19 +1000 Subject: Add `tempfile` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_codegen_ssa/Cargo.toml | 2 +- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_fs_util/Cargo.toml | 2 +- compiler/rustc_metadata/Cargo.toml | 2 +- compiler/rustc_serialize/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 2 +- src/tools/lint-docs/Cargo.toml | 2 +- src/tools/opt-dist/Cargo.toml | 2 +- 9 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d0949510384..9938d419033 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,6 +73,7 @@ quote = "1.0.40" rustc-literal-escaper = "0.0.5" rustc_apfloat = "0.2.3" serde_json = "1.0.142" +tempfile = "3.20.0" thin-vec = "0.2.14" tracing = "0.1.37" # tidy-alphabetical-end diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 8588b5bf327..57e1fee2c0a 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -39,7 +39,7 @@ rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } serde_json.workspace = true smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tempfile = "3.2" +tempfile.workspace = true thin-vec.workspace = true thorin-dwp = "0.9" tracing.workspace = true diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index d8d9d35cfc1..580bbde1b10 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -25,7 +25,7 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_thread_pool = { path = "../rustc_thread_pool" } smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] } stacker = "0.1.17" -tempfile = "3.2" +tempfile.workspace = true thin-vec.workspace = true tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_fs_util/Cargo.toml b/compiler/rustc_fs_util/Cargo.toml index 90a6acade8b..37970e81fea 100644 --- a/compiler/rustc_fs_util/Cargo.toml +++ b/compiler/rustc_fs_util/Cargo.toml @@ -5,5 +5,5 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -tempfile = "3.7.1" +tempfile.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 019e951fa62..ce65a71acad 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -30,7 +30,7 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -tempfile = "3.7.1" +tempfile.workspace = true tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index e9959735f9f..7d81ef996c8 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -14,5 +14,5 @@ thin-vec.workspace = true [dev-dependencies] # tidy-alphabetical-start rustc_macros = { path = "../rustc_macros" } -tempfile = "3.2" +tempfile.workspace = true # tidy-alphabetical-end diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index d34b4af2d95..63ac9ba6aa9 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -22,7 +22,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json.workspace = true smallvec = "1.8.1" stringdex = { version = "0.0.1-alpha4" } -tempfile = "3" +tempfile.workspace = true threadpool = "1.8.1" tracing-tree = "0.3.0" tracing.workspace = true diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml index 7af4b72e5b4..acafe17cb0c 100644 --- a/src/tools/lint-docs/Cargo.toml +++ b/src/tools/lint-docs/Cargo.toml @@ -9,5 +9,5 @@ description = "A script to extract the lint documentation for the rustc book." [dependencies] rustc-literal-escaper = "0.0.5" serde_json.workspace = true -tempfile = "3.1.0" +tempfile.workspace = true walkdir = "2.3.1" diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index e419a75f5f2..b2833a9d7f1 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -17,7 +17,7 @@ tar = "0.4" xz = { version = "0.1", package = "xz2" } serde_json.workspace = true glob = "0.3" -tempfile = "3.5" +tempfile.workspace = true derive_builder = "0.20" clap = { version = "4", features = ["derive"] } tabled = { version = "0.15", default-features = false, features = ["std"] } -- cgit 1.4.1-3-g733a5 From 77b047aaab6de9ec20b3c4f2fa57743c16d8789c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Aug 2025 20:20:12 +1000 Subject: Add `indexmap` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_resolve/Cargo.toml | 2 +- compiler/rustc_serialize/Cargo.toml | 2 +- compiler/rustc_span/Cargo.toml | 2 +- compiler/rustc_type_ir/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 2 +- src/tools/compiletest/Cargo.toml | 2 +- 8 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9938d419033..4f4dd83f415 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,6 +63,7 @@ exclude = [ # tidy-alphabetical-start bitflags = "2.9.3" either = "1.15.0" +indexmap = "2.10.0" itertools = "0.12.1" # FIXME: Remove this pin once this rustix issue is resolved # https://github.com/bytecodealliance/rustix/issues/1496 diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 580bbde1b10..949a5a9ac80 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -10,7 +10,7 @@ bitflags.workspace = true either.workspace = true elsa = "1.11.0" ena = "0.14.3" -indexmap = "2.4.0" +indexmap.workspace = true jobserver_crate = { version = "0.1.28", package = "jobserver" } measureme = "12.0.1" parking_lot = "0.12" diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 7c5332c1662..4da4c0840df 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags.workspace = true -indexmap = "2.4.0" +indexmap.workspace = true itertools.workspace = true pulldown-cmark = { version = "0.11", features = ["html"], default-features = false } rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index 7d81ef996c8..853f87ebed9 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -indexmap = "2.0.0" +indexmap.workspace = true rustc_hashes = { path = "../rustc_hashes" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec.workspace = true diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 2e45177e3b7..8368c9656e2 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start blake3 = "1.5.2" derive-where = "1.2.7" -indexmap = { version = "2.0.0" } +indexmap.workspace = true itoa = "1.0" md5 = { package = "md-5", version = "0.10.0" } rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 1dba7fe4269..bcd321d0c5f 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -8,7 +8,7 @@ edition = "2024" bitflags.workspace = true derive-where = "1.2.7" ena = "0.14.3" -indexmap = "2.0.0" +indexmap.workspace = true rustc-hash = "2.0.0" rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_data_structures = { path = "../rustc_data_structures", optional = true } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 63ac9ba6aa9..2985971a053 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -12,7 +12,7 @@ path = "lib.rs" arrayvec = { version = "0.7", default-features = false } askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] } base64 = "0.21.7" -indexmap = "2" +indexmap.workspace = true itertools.workspace = true minifier = { version = "0.3.5", default-features = false } pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] } diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 6f21c7db487..fb71275b03c 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -20,7 +20,7 @@ diff = "0.1.10" getopts = "0.2" glob = "0.3.0" home = "0.5.5" -indexmap = "2.0.0" +indexmap.workspace = true miropt-test-tools = { path = "../miropt-test-tools" } rayon = "1.10.0" regex = "1.0" -- cgit 1.4.1-3-g733a5 From 2b26476ccd8c5a6c03ba513b37381ebb6532c980 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Aug 2025 20:24:41 +1000 Subject: Add `rustc-hash` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_pattern_analysis/Cargo.toml | 2 +- compiler/rustc_type_ir/Cargo.toml | 2 +- src/tools/jsondoclint/Cargo.toml | 2 +- src/tools/tidy/Cargo.toml | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4f4dd83f415..fc161df5b2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,6 +71,7 @@ libc = "=0.2.174" memchr = "2.7.5" proc-macro2 = "1.0.101" quote = "1.0.40" +rustc-hash = "2.1.1" rustc-literal-escaper = "0.0.5" rustc_apfloat = "0.2.3" serde_json = "1.0.142" diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 949a5a9ac80..c4011f59a1e 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -14,7 +14,7 @@ indexmap.workspace = true jobserver_crate = { version = "0.1.28", package = "jobserver" } measureme = "12.0.1" parking_lot = "0.12" -rustc-hash = "2.0.0" +rustc-hash.workspace = true rustc-stable-hash = { version = "0.1.0", features = ["nightly"] } rustc_arena = { path = "../rustc_arena" } rustc_graphviz = { path = "../rustc_graphviz" } diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index 45f43822b5c..e4909ab6d16 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-hash = "2.0.0" +rustc-hash.workspace = true rustc_abi = { path = "../rustc_abi", optional = true } rustc_apfloat.workspace = true rustc_arena = { path = "../rustc_arena", optional = true } diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index bcd321d0c5f..ac7a5329448 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -9,7 +9,7 @@ bitflags.workspace = true derive-where = "1.2.7" ena = "0.14.3" indexmap.workspace = true -rustc-hash = "2.0.0" +rustc-hash.workspace = true rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_error_messages = { path = "../rustc_error_messages", optional = true } diff --git a/src/tools/jsondoclint/Cargo.toml b/src/tools/jsondoclint/Cargo.toml index d8cd59f7b42..44beaf2ddfd 100644 --- a/src/tools/jsondoclint/Cargo.toml +++ b/src/tools/jsondoclint/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" anyhow = "1.0.62" clap = { version = "4.0.15", features = ["derive"] } fs-err = "2.8.1" -rustc-hash = "2.0.0" +rustc-hash.workspace = true rustdoc-json-types = { version = "0.1.0", path = "../../rustdoc-json-types" } serde = { version = "1.0", features = ["derive"] } serde_json.workspace = true diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index c1f27de7ed4..f43733665ed 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -14,7 +14,7 @@ ignore = "0.4.18" semver = "1.0" serde = { version = "1.0.125", features = ["derive"], optional = true } termcolor = "1.1.3" -rustc-hash = "2.0.0" +rustc-hash.workspace = true fluent-syntax = "0.12" similar = "2.5.0" toml = "0.7.8" -- cgit 1.4.1-3-g733a5 From e692c97ad3f6beb59617b9720f30f616e5fbc431 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Aug 2025 22:08:35 +1000 Subject: Add `derive-where` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_next_trait_solver/Cargo.toml | 2 +- compiler/rustc_span/Cargo.toml | 2 +- compiler/rustc_type_ir/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fc161df5b2b..171138481c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ exclude = [ [workspace.dependencies] # tidy-alphabetical-start bitflags = "2.9.3" +derive-where = "1.6.0" either = "1.15.0" indexmap = "2.10.0" itertools = "0.12.1" diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 8b66f30cf0e..43db90c08f3 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -derive-where = "1.2.7" +derive-where.workspace = true rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 8368c9656e2..6283e47e1fe 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start blake3 = "1.5.2" -derive-where = "1.2.7" +derive-where.workspace = true indexmap.workspace = true itoa = "1.0" md5 = { package = "md-5", version = "0.10.0" } diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index ac7a5329448..42860fa2d88 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags.workspace = true -derive-where = "1.2.7" +derive-where.workspace = true ena = "0.14.3" indexmap.workspace = true rustc-hash.workspace = true -- cgit 1.4.1-3-g733a5 From 8fc0813e292e9772f28462a57f51f79a24c63774 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Aug 2025 22:10:04 +1000 Subject: Add `measureme` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_codegen_llvm/Cargo.toml | 2 +- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_query_impl/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 171138481c3..94464439df8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ itertools = "0.12.1" # FIXME: Remove this pin once this rustix issue is resolved # https://github.com/bytecodealliance/rustix/issues/1496 libc = "=0.2.174" +measureme = "12.0.3" memchr = "2.7.5" proc-macro2 = "1.0.101" quote = "1.0.40" diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 18c5189a402..5961cbb1033 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -14,7 +14,7 @@ bitflags.workspace = true gimli = "0.31" itertools.workspace = true libc.workspace = true -measureme = "12.0.1" +measureme.workspace = true object = { version = "0.37.0", default-features = false, features = ["std", "read"] } rustc-demangle = "0.1.21" rustc_abi = { path = "../rustc_abi" } diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index c4011f59a1e..852fc11350b 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -12,7 +12,7 @@ elsa = "1.11.0" ena = "0.14.3" indexmap.workspace = true jobserver_crate = { version = "0.1.28", package = "jobserver" } -measureme = "12.0.1" +measureme.workspace = true parking_lot = "0.12" rustc-hash.workspace = true rustc-stable-hash = { version = "0.1.0", features = ["nightly"] } diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index 2005b8b9eca..3d5cf0eb72d 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -measureme = "12.0.1" +measureme.workspace = true rustc_data_structures = { path = "../rustc_data_structures" } rustc_hashes = { path = "../rustc_hashes" } rustc_hir = { path = "../rustc_hir" } -- cgit 1.4.1-3-g733a5 From 42359b7026dbb4b68b3415582fabd8def56d6a8e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Aug 2025 22:13:29 +1000 Subject: Add `scoped-tls` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_public/Cargo.toml | 2 +- compiler/rustc_span/Cargo.toml | 2 +- compiler/rustc_thread_pool/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 94464439df8..378aa5ada2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,6 +76,7 @@ quote = "1.0.40" rustc-hash = "2.1.1" rustc-literal-escaper = "0.0.5" rustc_apfloat = "0.2.3" +scoped-tls = "1.0.1" serde_json = "1.0.142" tempfile = "3.20.0" thin-vec = "0.2.14" diff --git a/compiler/rustc_public/Cargo.toml b/compiler/rustc_public/Cargo.toml index 71d339b5792..e67e4fe6739 100644 --- a/compiler/rustc_public/Cargo.toml +++ b/compiler/rustc_public/Cargo.toml @@ -12,7 +12,7 @@ rustc_public_bridge = { path = "../rustc_public_bridge" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -scoped-tls = "1.0" +scoped-tls.workspace = true serde = { version = "1.0.125", features = [ "derive" ] } tracing.workspace = true # tidy-alphabetical-end diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 6283e47e1fe..da6f2101d23 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -16,7 +16,7 @@ rustc_hashes = { path = "../rustc_hashes" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } -scoped-tls = "1.0" +scoped-tls.workspace = true sha1 = "0.10.0" sha2 = "0.10.1" tracing.workspace = true diff --git a/compiler/rustc_thread_pool/Cargo.toml b/compiler/rustc_thread_pool/Cargo.toml index 3eafb308192..8e8c6469512 100644 --- a/compiler/rustc_thread_pool/Cargo.toml +++ b/compiler/rustc_thread_pool/Cargo.toml @@ -20,7 +20,7 @@ smallvec = "1.8.1" [dev-dependencies] rand = "0.9" rand_xorshift = "0.4" -scoped-tls = "1.0" +scoped-tls.workspace = true [target.'cfg(unix)'.dev-dependencies] libc.workspace = true -- cgit 1.4.1-3-g733a5 From 20d03752c5a1c6ea4f81fcb09505977a6c945d8b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 Aug 2025 07:33:35 +1000 Subject: Add `odht` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_hir/Cargo.toml | 2 +- compiler/rustc_metadata/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 378aa5ada2f..69d93b7985e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,6 +71,7 @@ itertools = "0.12.1" libc = "=0.2.174" measureme = "12.0.3" memchr = "2.7.5" +odht = { version = "0.3.1", features = ["nightly"] } proc-macro2 = "1.0.101" quote = "1.0.40" rustc-hash = "2.1.1" diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index ea72ed68c5e..e74fcfe7455 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags.workspace = true -odht = { version = "0.3.1", features = ["nightly"] } +odht.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index ce65a71acad..a8f3dd18353 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start bitflags.workspace = true libloading = "0.8.0" -odht = { version = "0.3.1", features = ["nightly"] } +odht.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } -- cgit 1.4.1-3-g733a5 From b16c66ee838ba77331cefa3e1747899978b76ff7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 Aug 2025 07:43:31 +1000 Subject: Add `polonius-engine` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_borrowck/Cargo.toml | 2 +- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_mir_dataflow/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 69d93b7985e..01935b7daff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,6 +72,7 @@ libc = "=0.2.174" measureme = "12.0.3" memchr = "2.7.5" odht = { version = "0.3.1", features = ["nightly"] } +polonius-engine = "0.13.0" proc-macro2 = "1.0.101" quote = "1.0.40" rustc-hash = "2.1.1" diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index c0311ff414d..5f9dc41766b 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start either.workspace = true itertools.workspace = true -polonius-engine = "0.13.0" +polonius-engine.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index ae27c3bbf67..f0832405567 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -8,7 +8,7 @@ edition = "2024" bitflags.workspace = true either.workspace = true gsgdt = "0.1.2" -polonius-engine = "0.13.0" +polonius-engine.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_apfloat.workspace = true rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml index e422f69c7ca..11713bb77f1 100644 --- a/compiler/rustc_mir_dataflow/Cargo.toml +++ b/compiler/rustc_mir_dataflow/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -polonius-engine = "0.13.0" +polonius-engine.workspace = true regex = "1" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -- cgit 1.4.1-3-g733a5 From 475c29d30f7d31c63fad132908fa325a4fc30efe Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 Aug 2025 07:46:26 +1000 Subject: Add `rustc-demangle` to `[workspace.dependencies]`. --- Cargo.toml | 1 + compiler/rustc_codegen_llvm/Cargo.toml | 2 +- compiler/rustc_symbol_mangling/Cargo.toml | 2 +- src/tools/coverage-dump/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 01935b7daff..2c5044f6a35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,6 +75,7 @@ odht = { version = "0.3.1", features = ["nightly"] } polonius-engine = "0.13.0" proc-macro2 = "1.0.101" quote = "1.0.40" +rustc-demangle = "0.1.26" rustc-hash = "2.1.1" rustc-literal-escaper = "0.0.5" rustc_apfloat = "0.2.3" diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 5961cbb1033..b04310f3d54 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -16,7 +16,7 @@ itertools.workspace = true libc.workspace = true measureme.workspace = true object = { version = "0.37.0", default-features = false, features = ["std", "read"] } -rustc-demangle = "0.1.21" +rustc-demangle.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 48e02dabdde..0ceac4b3e1b 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start punycode = "0.4.0" -rustc-demangle = "0.1.21" +rustc-demangle.workspace = true rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/src/tools/coverage-dump/Cargo.toml b/src/tools/coverage-dump/Cargo.toml index 2f703537b59..e491804c257 100644 --- a/src/tools/coverage-dump/Cargo.toml +++ b/src/tools/coverage-dump/Cargo.toml @@ -12,4 +12,4 @@ leb128 = "0.2.5" md5 = { package = "md-5" , version = "0.10.5" } miniz_oxide = "0.8.8" regex = "1.8.4" -rustc-demangle = "0.1.23" +rustc-demangle.workspace = true -- cgit 1.4.1-3-g733a5 From ab0ee84eac9732e4e81e559c688846b4c1bd400a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 13 Jun 2025 21:01:59 +0200 Subject: Add new `doc(attribute = "...")` attribute --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_passes/messages.ftl | 14 +++--- compiler/rustc_passes/src/check_attr.rs | 50 ++++++++++++++++++---- compiler/rustc_passes/src/errors.rs | 19 ++++++-- compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_resolve/src/rustdoc.rs | 6 +-- compiler/rustc_span/src/symbol.rs | 1 + src/librustdoc/clean/types.rs | 38 +++++++++++++--- src/librustdoc/clean/utils.rs | 4 ++ src/librustdoc/fold.rs | 3 +- src/librustdoc/formats/cache.rs | 3 +- src/librustdoc/formats/item_type.rs | 3 ++ src/librustdoc/html/render/context.rs | 2 +- src/librustdoc/html/render/mod.rs | 5 +++ src/librustdoc/html/render/print_item.rs | 9 ++-- src/librustdoc/html/static/css/noscript.css | 2 + src/librustdoc/html/static/css/rustdoc.css | 7 +++ src/librustdoc/html/static/js/main.js | 1 + src/librustdoc/html/static/js/search.js | 5 ++- src/librustdoc/json/conversions.rs | 14 +++--- src/librustdoc/passes/check_doc_test_visibility.rs | 1 + src/librustdoc/passes/collect_intra_doc_links.rs | 4 +- src/librustdoc/passes/propagate_stability.rs | 3 +- src/librustdoc/passes/stripper.rs | 2 + src/librustdoc/visit.rs | 3 +- src/rustdoc-json-types/lib.rs | 9 +++- src/tools/jsondoclint/src/item_kind.rs | 4 ++ 27 files changed, 168 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index e763c9d69fc..9ab5b0b3547 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -188,6 +188,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { notable_trait => doc_notable_trait } "meant for internal use only" { + attribute => rustdoc_internals keyword => rustdoc_internals fake_variadic => rustdoc_internals search_unbox => rustdoc_internals diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 3be06a3704c..498d9a405fa 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -145,6 +145,10 @@ passes_doc_alias_start_end = passes_doc_attr_not_crate_level = `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute +passes_doc_attribute_not_attribute = + nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` + .help = only existing builtin attributes are allowed in core/std + passes_doc_cfg_hide_takes_list = `#[doc(cfg_hide(...))]` takes a list of attributes @@ -173,16 +177,16 @@ passes_doc_inline_only_use = passes_doc_invalid = invalid `doc` attribute -passes_doc_keyword_empty_mod = - `#[doc(keyword = "...")]` should be used on empty modules +passes_doc_keyword_attribute_empty_mod = + `#[doc({$attr_name} = "...")]` should be used on empty modules + +passes_doc_keyword_attribute_not_mod = + `#[doc({$attr_name} = "...")]` should be used on modules passes_doc_keyword_not_keyword = nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]` .help = only existing keywords are allowed in core/std -passes_doc_keyword_not_mod = - `#[doc(keyword = "...")]` should be used on modules - passes_doc_keyword_only_impl = `#[doc(keyword = "...")]` should be used on impl blocks diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3a79176f914..fa7591b5113 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -851,7 +851,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_doc_keyword(&self, meta: &MetaItemInner, hir_id: HirId) { + fn check_doc_keyword_and_attribute( + &self, + meta: &MetaItemInner, + hir_id: HirId, + is_keyword: bool, + ) { fn is_doc_keyword(s: Symbol) -> bool { // FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we // can remove the `SelfTy` case here, remove `sym::SelfTy`, and update the @@ -859,9 +864,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() || s == sym::SelfTy } - let doc_keyword = match meta.value_str() { + fn is_builtin_attr(s: Symbol) -> bool { + rustc_feature::BUILTIN_ATTRIBUTE_MAP.contains_key(&s) + } + + fn get_attr_name(is_keyword: bool) -> &'static str { + if is_keyword { "keyword" } else { "attribute" } + } + + let value = match meta.value_str() { Some(value) if value != sym::empty => value, - _ => return self.doc_attr_str_error(meta, "keyword"), + _ => return self.doc_attr_str_error(meta, get_attr_name(is_keyword)), }; let item_kind = match self.tcx.hir_node(hir_id) { @@ -871,19 +884,32 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match item_kind { Some(ItemKind::Mod(_, module)) => { if !module.item_ids.is_empty() { - self.dcx().emit_err(errors::DocKeywordEmptyMod { span: meta.span() }); + self.dcx().emit_err(errors::DocKeywordAttributeEmptyMod { + span: meta.span(), + attr_name: get_attr_name(is_keyword), + }); return; } } _ => { - self.dcx().emit_err(errors::DocKeywordNotMod { span: meta.span() }); + self.dcx().emit_err(errors::DocKeywordAttributeNotMod { + span: meta.span(), + attr_name: get_attr_name(is_keyword), + }); return; } } - if !is_doc_keyword(doc_keyword) { - self.dcx().emit_err(errors::DocKeywordNotKeyword { + if is_keyword { + if !is_doc_keyword(value) { + self.dcx().emit_err(errors::DocKeywordNotKeyword { + span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + keyword: value, + }); + } + } else if !is_builtin_attr(value) { + self.dcx().emit_err(errors::DocAttributeNotAttribute { span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - keyword: doc_keyword, + attribute: value, }); } } @@ -1144,7 +1170,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Some(sym::keyword) => { if self.check_attr_not_crate_level(meta, hir_id, "keyword") { - self.check_doc_keyword(meta, hir_id); + self.check_doc_keyword_and_attribute(meta, hir_id, true); + } + } + + Some(sym::attribute) => { + if self.check_attr_not_crate_level(meta, hir_id, "attribute") { + self.check_doc_keyword_and_attribute(meta, hir_id, false); } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 01972067978..680e2a26d84 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -195,10 +195,11 @@ pub(crate) struct DocAliasMalformed { } #[derive(Diagnostic)] -#[diag(passes_doc_keyword_empty_mod)] -pub(crate) struct DocKeywordEmptyMod { +#[diag(passes_doc_keyword_attribute_empty_mod)] +pub(crate) struct DocKeywordAttributeEmptyMod { #[primary_span] pub span: Span, + pub attr_name: &'static str, } #[derive(Diagnostic)] @@ -211,10 +212,20 @@ pub(crate) struct DocKeywordNotKeyword { } #[derive(Diagnostic)] -#[diag(passes_doc_keyword_not_mod)] -pub(crate) struct DocKeywordNotMod { +#[diag(passes_doc_attribute_not_attribute)] +#[help] +pub(crate) struct DocAttributeNotAttribute { + #[primary_span] + pub span: Span, + pub attribute: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes_doc_keyword_attribute_not_mod)] +pub(crate) struct DocKeywordAttributeNotMod { #[primary_span] pub span: Span, + pub attr_name: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 679e663f886..d4f7fb276a9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -5016,7 +5016,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } ResolveDocLinks::Exported if !maybe_exported.eval(self.r) - && !rustdoc::has_primitive_or_keyword_docs(attrs) => + && !rustdoc::has_primitive_or_keyword_or_attribute_docs(attrs) => { return; } diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index f9f2f84bc50..804792c6f28 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -373,8 +373,8 @@ pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool { true } -/// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`. -pub fn has_primitive_or_keyword_docs(attrs: &[impl AttributeExt]) -> bool { +/// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]` or `#[doc(attribute)]`. +pub fn has_primitive_or_keyword_or_attribute_docs(attrs: &[impl AttributeExt]) -> bool { for attr in attrs { if attr.has_name(sym::rustc_doc_primitive) { return true; @@ -382,7 +382,7 @@ pub fn has_primitive_or_keyword_docs(attrs: &[impl AttributeExt]) -> bool { && let Some(items) = attr.meta_item_list() { for item in items { - if item.has_name(sym::keyword) { + if item.has_name(sym::keyword) || item.has_name(sym::attribute) { return true; } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 585968044bf..db20f201a8a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -540,6 +540,7 @@ symbols! { att_syntax, attr, attr_literals, + attribute, attributes, audit_that, augmented_assignments, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 92bd4a498ca..1502ec9bd78 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -226,15 +226,28 @@ impl ExternalCrate { } pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> impl Iterator { - fn as_keyword(did: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, Symbol)> { + self.retrieve_keywords_or_documented_attributes(tcx, sym::keyword) + } + pub(crate) fn documented_attributes( + &self, + tcx: TyCtxt<'_>, + ) -> impl Iterator { + self.retrieve_keywords_or_documented_attributes(tcx, sym::attribute) + } + + fn retrieve_keywords_or_documented_attributes( + &self, + tcx: TyCtxt<'_>, + name: Symbol, + ) -> impl Iterator { + let as_target = move |did: DefId, tcx: TyCtxt<'_>| -> Option<(DefId, Symbol)> { tcx.get_attrs(did, sym::doc) .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) - .filter(|meta| meta.has_name(sym::keyword)) + .filter(|meta| meta.has_name(name)) .find_map(|meta| meta.value_str()) .map(|value| (did, value)) - } - - self.mapped_root_modules(tcx, as_keyword) + }; + self.mapped_root_modules(tcx, as_target) } pub(crate) fn primitives( @@ -592,6 +605,9 @@ impl Item { pub(crate) fn is_keyword(&self) -> bool { self.type_() == ItemType::Keyword } + pub(crate) fn is_attribute(&self) -> bool { + self.type_() == ItemType::Attribute + } pub(crate) fn is_stripped(&self) -> bool { match self.kind { StrippedItem(..) => true, @@ -735,7 +751,9 @@ impl Item { // Primitives and Keywords are written in the source code as private modules. // The modules need to be private so that nobody actually uses them, but the // keywords and primitives that they are documenting are public. - ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) => return Some(Visibility::Public), + ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) | ItemKind::AttributeItem => { + return Some(Visibility::Public); + } // Variant fields inherit their enum's visibility. StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => { return None; @@ -942,7 +960,12 @@ pub(crate) enum ItemKind { AssocTypeItem(Box, Vec), /// An item that has been stripped by a rustdoc pass StrippedItem(Box), + /// This item represents a module with a `#[doc(keyword = "...")]` attribute which is used + /// to generate documentation for Rust keywords. KeywordItem, + /// This item represents a module with a `#[doc(attribute = "...")]` attribute which is used + /// to generate documentation for Rust builtin attributes. + AttributeItem, } impl ItemKind { @@ -983,7 +1006,8 @@ impl ItemKind { | RequiredAssocTypeItem(..) | AssocTypeItem(..) | StrippedItem(_) - | KeywordItem => [].iter(), + | KeywordItem + | AttributeItem => [].iter(), } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 813fdee57e1..6fc1e43c724 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -60,6 +60,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { let local_crate = ExternalCrate { crate_num: LOCAL_CRATE }; let primitives = local_crate.primitives(cx.tcx); let keywords = local_crate.keywords(cx.tcx); + let documented_attributes = local_crate.documented_attributes(cx.tcx); { let ItemKind::ModuleItem(m) = &mut module.inner.kind else { unreachable!() }; m.items.extend(primitives.map(|(def_id, prim)| { @@ -73,6 +74,9 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { m.items.extend(keywords.map(|(def_id, kw)| { Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::KeywordItem, cx) })); + m.items.extend(documented_attributes.into_iter().map(|(def_id, kw)| { + Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::AttributeItem, cx) + })); } Crate { module, external_traits: Box::new(mem::take(&mut cx.external_traits)) } diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index c03d16ad081..ee5f260615d 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -96,7 +96,8 @@ pub(crate) trait DocFolder: Sized { | ImplAssocConstItem(..) | RequiredAssocTypeItem(..) | AssocTypeItem(..) - | KeywordItem => kind, + | KeywordItem + | AttributeItem => kind, } } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index cb6837dd614..29b4c4caaf8 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -372,7 +372,8 @@ impl DocFolder for CacheBuilder<'_, '_> { | clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) | clean::StrippedItem(..) - | clean::KeywordItem => { + | clean::KeywordItem + | clean::AttributeItem => { // FIXME: Do these need handling? // The person writing this comment doesn't know. // So would rather leave them to an expert, diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index 142a9d7d8af..e94ef517309 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -57,6 +57,7 @@ pub(crate) enum ItemType { TraitAlias = 25, // This number is reserved for use in JavaScript // Generic = 26, + Attribute = 27, } impl Serialize for ItemType { @@ -148,6 +149,7 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType, clean::ForeignTypeItem => ItemType::ForeignType, clean::KeywordItem => ItemType::Keyword, + clean::AttributeItem => ItemType::Attribute, clean::TraitAliasItem(..) => ItemType::TraitAlias, clean::ProcMacroItem(mac) => match mac.kind { MacroKind::Bang => ItemType::Macro, @@ -236,6 +238,7 @@ impl ItemType { ItemType::ProcAttribute => "attr", ItemType::ProcDerive => "derive", ItemType::TraitAlias => "traitalias", + ItemType::Attribute => "attribute", } } pub(crate) fn is_method(&self) -> bool { diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index faaecaf0cbb..cafbcf7e8dd 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -218,7 +218,7 @@ impl<'tcx> Context<'tcx> { } else { it.name.as_ref().unwrap().as_str() }; - if !it.is_primitive() && !it.is_keyword() { + if !it.is_primitive() && !it.is_keyword() && !it.is_attribute() { if !is_module { title.push_str(" in "); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 673947ad308..6db90c9bf2a 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2535,6 +2535,7 @@ pub(crate) enum ItemSection { AssociatedConstants, ForeignTypes, Keywords, + Attributes, AttributeMacros, DeriveMacros, TraitAliases, @@ -2567,6 +2568,7 @@ impl ItemSection { AssociatedConstants, ForeignTypes, Keywords, + Attributes, AttributeMacros, DeriveMacros, TraitAliases, @@ -2596,6 +2598,7 @@ impl ItemSection { Self::AssociatedConstants => "associated-consts", Self::ForeignTypes => "foreign-types", Self::Keywords => "keywords", + Self::Attributes => "attributes", Self::AttributeMacros => "attributes", Self::DeriveMacros => "derives", Self::TraitAliases => "trait-aliases", @@ -2625,6 +2628,7 @@ impl ItemSection { Self::AssociatedConstants => "Associated Constants", Self::ForeignTypes => "Foreign Types", Self::Keywords => "Keywords", + Self::Attributes => "Attributes", Self::AttributeMacros => "Attribute Macros", Self::DeriveMacros => "Derive Macros", Self::TraitAliases => "Trait Aliases", @@ -2655,6 +2659,7 @@ fn item_ty_to_section(ty: ItemType) -> ItemSection { ItemType::AssocConst => ItemSection::AssociatedConstants, ItemType::ForeignType => ItemSection::ForeignTypes, ItemType::Keyword => ItemSection::Keywords, + ItemType::Attribute => ItemSection::Attributes, ItemType::ProcAttribute => ItemSection::AttributeMacros, ItemType::ProcDerive => ItemSection::DeriveMacros, ItemType::TraitAlias => ItemSection::TraitAliases, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index b86a2c94697..530e6da4ee3 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -173,6 +173,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item) -> impl fmt::Disp clean::ConstantItem(..) => "Constant ", clean::ForeignTypeItem => "Foreign Type ", clean::KeywordItem => "Keyword ", + clean::AttributeItem => "Attribute ", clean::TraitAliasItem(..) => "Trait Alias ", _ => { // We don't generate pages for any other type. @@ -193,7 +194,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item) -> impl fmt::Disp let src_href = if cx.info.include_sources && !item.is_primitive() { cx.src_href(item) } else { None }; - let path_components = if item.is_primitive() || item.is_keyword() { + let path_components = if item.is_primitive() || item.is_keyword() || item.is_attribute() { vec![] } else { let cur = &cx.current; @@ -252,7 +253,9 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item) -> impl fmt::Disp clean::ForeignTypeItem => { write!(buf, "{}", item_foreign_type(cx, item)) } - clean::KeywordItem => write!(buf, "{}", item_keyword(cx, item)), + clean::KeywordItem | clean::AttributeItem => { + write!(buf, "{}", item_keyword_or_attribute(cx, item)) + } clean::TraitAliasItem(ta) => { write!(buf, "{}", item_trait_alias(cx, item, ta)) } @@ -2151,7 +2154,7 @@ fn item_foreign_type(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display { }) } -fn item_keyword(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display { +fn item_keyword_or_attribute(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display { document(cx, it, None, HeadingOffset::H2) } diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index a3c6bf98161..5c02e2eb26a 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -75,6 +75,7 @@ nav.sub { --function-link-color: #ad7c37; --macro-link-color: #068000; --keyword-link-color: #3873ad; + --attribute-link-color: #3873ad; --mod-link-color: #3873ad; --link-color: #3873ad; --sidebar-link-color: #356da4; @@ -180,6 +181,7 @@ nav.sub { --function-link-color: #2bab63; --macro-link-color: #09bd00; --keyword-link-color: #d2991d; + --attribute-link-color: #d2991d; --mod-link-color: #d2991d; --link-color: #d2991d; --sidebar-link-color: #fdbf35; diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 86f1a42bc01..09d289d570c 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -400,6 +400,10 @@ span.keyword, a.keyword { color: var(--keyword-link-color); } +span.attribute, a.attribute { + color: var(--attribute-link-color); +} + a { color: var(--link-color); text-decoration: none; @@ -3190,6 +3194,7 @@ by default. --function-link-color: #ad7c37; --macro-link-color: #068000; --keyword-link-color: #3873ad; + --attribute-link-color: #3873ad; --mod-link-color: #3873ad; --link-color: #3873ad; --sidebar-link-color: #356da4; @@ -3294,6 +3299,7 @@ by default. --function-link-color: #2bab63; --macro-link-color: #09bd00; --keyword-link-color: #d2991d; + --attribute-link-color: #d2991d; --mod-link-color: #d2991d; --link-color: #d2991d; --sidebar-link-color: #fdbf35; @@ -3407,6 +3413,7 @@ Original by Dempfi (https://github.com/dempfi/ayu) --function-link-color: #fdd687; --macro-link-color: #a37acc; --keyword-link-color: #39afd7; + --attribute-link-color: #39afd7; --mod-link-color: #39afd7; --link-color: #39afd7; --sidebar-link-color: #53b1db; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 4fcba5f120b..75febd6f737 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -790,6 +790,7 @@ function preLoadCss(cssUrl) { //block("associatedconstant", "associated-consts", "Associated Constants"); block("foreigntype", "foreign-types", "Foreign Types"); block("keyword", "keywords", "Keywords"); + block("attribute", "attributes", "Attributes"); block("attr", "attributes", "Attribute Macros"); block("derive", "derives", "Derive Macros"); block("traitalias", "trait-aliases", "Trait Aliases"); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 3fb4db3a89c..b003bcc7bf9 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -119,6 +119,7 @@ const itemTypes = [ "derive", "traitalias", // 25 "generic", + "attribute", ]; // used for special search precedence @@ -2058,7 +2059,7 @@ class DocSearch { displayPath = item.modulePath + "::"; href = this.rootPath + item.modulePath.replace(/::/g, "/") + "/index.html#reexport." + name; - } else if (type === "primitive" || type === "keyword") { + } else if (type === "primitive" || type === "keyword" || type === "attribute") { displayPath = ""; exactPath = ""; href = this.rootPath + path.replace(/::/g, "/") + @@ -4560,6 +4561,8 @@ const longItemTypes = [ "attribute macro", "derive macro", "trait alias", + "", + "attribute", ]; // @ts-expect-error let currentResults; diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 5fab8ad2a4b..f0520716228 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -52,7 +52,7 @@ impl JsonRenderer<'_> { let clean::ItemInner { name, item_id, .. } = *item.inner; let id = self.id_from_item(item); let inner = match item.kind { - clean::KeywordItem => return None, + clean::KeywordItem | clean::AttributeItem => return None, clean::StrippedItem(ref inner) => { match &**inner { // We document stripped modules as with `Module::is_stripped` set to @@ -85,7 +85,7 @@ impl JsonRenderer<'_> { fn ids(&self, items: &[clean::Item]) -> Vec { items .iter() - .filter(|i| !i.is_stripped() && !i.is_keyword()) + .filter(|i| !i.is_stripped() && !i.is_keyword() && !i.is_attribute()) .map(|i| self.id_from_item(i)) .collect() } @@ -93,7 +93,10 @@ impl JsonRenderer<'_> { fn ids_keeping_stripped(&self, items: &[clean::Item]) -> Vec> { items .iter() - .map(|i| (!i.is_stripped() && !i.is_keyword()).then(|| self.id_from_item(i))) + .map(|i| { + (!i.is_stripped() && !i.is_keyword() && !i.is_attribute()) + .then(|| self.id_from_item(i)) + }) .collect() } } @@ -332,8 +335,8 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum bounds: b.into_json(renderer), type_: Some(t.item_type.as_ref().unwrap_or(&t.type_).into_json(renderer)), }, - // `convert_item` early returns `None` for stripped items and keywords. - KeywordItem => unreachable!(), + // `convert_item` early returns `None` for stripped items, keywords and attributes. + KeywordItem | AttributeItem => unreachable!(), StrippedItem(inner) => { match inner.as_ref() { ModuleItem(m) => ItemEnum::Module(Module { @@ -887,6 +890,7 @@ impl FromClean for ItemKind { AssocType => ItemKind::AssocType, ForeignType => ItemKind::ExternType, Keyword => ItemKind::Keyword, + Attribute => ItemKind::Attribute, TraitAlias => ItemKind::TraitAlias, ProcAttribute => ItemKind::ProcAttribute, ProcDerive => ItemKind::ProcDerive, diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 8028afea363..e0ea760cf3b 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -67,6 +67,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) - | clean::ImportItem(_) | clean::PrimitiveItem(_) | clean::KeywordItem + | clean::AttributeItem | clean::ModuleItem(_) | clean::TraitAliasItem(_) | clean::ForeignFunctionItem(..) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index bad51d7f5b2..719b7c6ab89 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -19,7 +19,7 @@ use rustc_hir::{Mutability, Safety}; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; use rustc_resolve::rustdoc::{ - MalformedGenerics, has_primitive_or_keyword_docs, prepare_to_doc_link_resolution, + MalformedGenerics, has_primitive_or_keyword_or_attribute_docs, prepare_to_doc_link_resolution, source_span_for_markdown_range, strip_generics_from_path, }; use rustc_session::config::CrateType; @@ -1073,7 +1073,7 @@ impl LinkCollector<'_, '_> { && let Some(def_id) = item.item_id.as_def_id() && let Some(def_id) = def_id.as_local() && !self.cx.tcx.effective_visibilities(()).is_exported(def_id) - && !has_primitive_or_keyword_docs(&item.attrs.other_attrs) + && !has_primitive_or_keyword_or_attribute_docs(&item.attrs.other_attrs) { // Skip link resolution for non-exported items. return; diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs index 14ec58702e3..5139ca301dd 100644 --- a/src/librustdoc/passes/propagate_stability.rs +++ b/src/librustdoc/passes/propagate_stability.rs @@ -106,7 +106,8 @@ impl DocFolder for StabilityPropagator<'_, '_> { | ItemKind::RequiredAssocTypeItem(..) | ItemKind::AssocTypeItem(..) | ItemKind::PrimitiveItem(..) - | ItemKind::KeywordItem => own_stability, + | ItemKind::KeywordItem + | ItemKind::AttributeItem => own_stability, ItemKind::StrippedItem(..) => unreachable!(), } diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index eedbbca0f8d..99d22526f85 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -133,6 +133,8 @@ impl DocFolder for Stripper<'_, '_> { // Keywords are never stripped clean::KeywordItem => {} + // Attributes are never stripped + clean::AttributeItem => {} } let fastreturn = match i.kind { diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index b8b619514aa..4d31409afe8 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -49,7 +49,8 @@ pub(crate) trait DocVisitor<'a>: Sized { | ImplAssocConstItem(..) | RequiredAssocTypeItem(..) | AssocTypeItem(..) - | KeywordItem => {} + | KeywordItem + | AttributeItem => {} } } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 40f89009a43..658d3791d25 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -37,8 +37,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: Add Attribute::MacroUse -pub const FORMAT_VERSION: u32 = 55; +// Latest feature: Add `ItemKind::Attribute`. +pub const FORMAT_VERSION: u32 = 56; /// The root of the emitted JSON blob. /// @@ -552,6 +552,11 @@ pub enum ItemKind { /// [`Item`]s of this kind only come from the come library and exist solely /// to carry documentation for the respective keywords. Keyword, + /// An attribute declaration. + /// + /// [`Item`]s of this kind only come from the core library and exist solely + /// to carry documentation for the respective builtin attributes. + Attribute, } /// Specific fields of an item. diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs index 51146831efa..e2738636a14 100644 --- a/src/tools/jsondoclint/src/item_kind.rs +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -26,6 +26,7 @@ pub(crate) enum Kind { AssocType, Primitive, Keyword, + Attribute, // Not in ItemKind ProcMacro, } @@ -53,6 +54,7 @@ impl Kind { ExternType => true, // FIXME(adotinthevoid): I'm not sure if these are correct + Attribute => false, Keyword => false, ProcAttribute => false, ProcDerive => false, @@ -109,6 +111,7 @@ impl Kind { Kind::Primitive => false, Kind::Keyword => false, Kind::ProcMacro => false, + Kind::Attribute => false, } } @@ -163,6 +166,7 @@ impl Kind { match s.kind { ItemKind::AssocConst => AssocConst, ItemKind::AssocType => AssocType, + ItemKind::Attribute => Attribute, ItemKind::Constant => Constant, ItemKind::Enum => Enum, ItemKind::ExternCrate => ExternCrate, -- cgit 1.4.1-3-g733a5 From 75cbd05d19a7cfb0819f15a57f2561cd28a956a7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 13 Jun 2025 21:02:26 +0200 Subject: Add tests for `doc(attribute = "...")` attribute --- tests/rustdoc-gui/links-color.goml | 6 +++++- tests/rustdoc-gui/module-items-font.goml | 9 ++++++++ tests/rustdoc-gui/search-result-color.goml | 11 +++++++++- tests/rustdoc-gui/sidebar-links-color.goml | 20 ++++++++++++++++++ tests/rustdoc-gui/src/test_docs/lib.rs | 4 ++++ tests/rustdoc-json/doc_attribute.rs | 18 ++++++++++++++++ tests/rustdoc-ui/invalid-attribute.rs | 10 +++++++++ tests/rustdoc-ui/invalid-attribute.stderr | 18 ++++++++++++++++ tests/rustdoc/doc-attribute.rs | 24 ++++++++++++++++++++++ .../feature-gate-rustdoc_internals.rs | 4 ++++ .../feature-gate-rustdoc_internals.stderr | 16 ++++++++++++--- 11 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 tests/rustdoc-json/doc_attribute.rs create mode 100644 tests/rustdoc-ui/invalid-attribute.rs create mode 100644 tests/rustdoc-ui/invalid-attribute.stderr create mode 100644 tests/rustdoc/doc-attribute.rs diff --git a/tests/rustdoc-gui/links-color.goml b/tests/rustdoc-gui/links-color.goml index f11920cdd8c..a363175c1dd 100644 --- a/tests/rustdoc-gui/links-color.goml +++ b/tests/rustdoc-gui/links-color.goml @@ -9,7 +9,7 @@ show-text: true define-function: ( "check-colors", [theme, mod, macro, struct, enum, trait, fn, type, union, keyword, - sidebar, sidebar_current, sidebar_current_background], + attribute, sidebar, sidebar_current, sidebar_current_background], block { call-function: ("switch-theme", {"theme": |theme|}) // Checking results colors. @@ -22,6 +22,7 @@ define-function: ( assert-css: (".item-table .type", {"color": |type|}, ALL) assert-css: (".item-table .union", {"color": |union|}, ALL) assert-css: (".item-table .keyword", {"color": |keyword|}, ALL) + assert-css: (".item-table .attribute", {"color": |attribute|}, ALL) // Checking sidebar elements. assert-css: ( ".sidebar-elems li:not(.current) a", @@ -58,6 +59,7 @@ call-function: ( "type": "#ffa0a5", "union": "#ffa0a5", "keyword": "#39afd7", + "attribute": "#39afd7", "sidebar": "#53b1db", "sidebar_current": "#ffb44c", "sidebar_current_background": "transparent", @@ -76,6 +78,7 @@ call-function: ( "type": "#2dbfb8", "union": "#2dbfb8", "keyword": "#d2991d", + "attribute": "#d2991d", "sidebar": "#fdbf35", "sidebar_current": "#fdbf35", "sidebar_current_background": "#444", @@ -94,6 +97,7 @@ call-function: ( "type": "#ad378a", "union": "#ad378a", "keyword": "#3873ad", + "attribute": "#3873ad", "sidebar": "#356da4", "sidebar_current": "#356da4", "sidebar_current_background": "#fff", diff --git a/tests/rustdoc-gui/module-items-font.goml b/tests/rustdoc-gui/module-items-font.goml index 0e6dd81c05b..bed95b378c6 100644 --- a/tests/rustdoc-gui/module-items-font.goml +++ b/tests/rustdoc-gui/module-items-font.goml @@ -65,3 +65,12 @@ assert-css: ( "#keywords + .item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) +// attributes +assert-css: ( + "#attributes + .item-table dt a", + {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, +) +assert-css: ( + "#attributes + .item-table dd", + {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, +) diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml index e136eab6a7d..fe0f6401089 100644 --- a/tests/rustdoc-gui/search-result-color.goml +++ b/tests/rustdoc-gui/search-result-color.goml @@ -7,7 +7,8 @@ define-function: ( [ theme, count_color, desc_color, path_color, bottom_border_color, keyword_color, struct_color, associatedtype_color, tymethod_color, method_color, structfield_color, - structfield_hover_color, macro_color, fn_color, hover_path_color, hover_background, grey + structfield_hover_color, macro_color, fn_color, hover_path_color, hover_background, + attribute_color, grey ], block { call-function: ("switch-theme", {"theme": |theme|}) @@ -46,6 +47,11 @@ define-function: ( "color": |keyword_color|, "hover_color": |keyword_color|, }) + call-function: ("check-result-color", { + "result_kind": "attribute", + "color": |attribute_color|, + "hover_color": |attribute_color|, + }) call-function: ("check-result-color", { "result_kind": "struct", "color": |struct_color|, @@ -155,6 +161,7 @@ call-function: ("check-search-color", { "path_color": "#0096cf", "bottom_border_color": "#aaa3", "keyword_color": "#39afd7", + "attribute_color": "#39afd7", "struct_color": "#ffa0a5", "associatedtype_color": "#39afd7", "tymethod_color": "#fdd687", @@ -176,6 +183,7 @@ call-function: ("check-search-color", { "path_color": "#ddd", "bottom_border_color": "#aaa3", "keyword_color": "#d2991d", + "attribute_color": "#d2991d", "struct_color": "#2dbfb8", "associatedtype_color": "#d2991d", "tymethod_color": "#2bab63", @@ -197,6 +205,7 @@ call-function: ("check-search-color", { "path_color": "#000", "bottom_border_color": "#aaa3", "keyword_color": "#3873ad", + "attribute_color": "#3873ad", "struct_color": "#ad378a", "associatedtype_color": "#3873ad", "tymethod_color": "#ad7c37", diff --git a/tests/rustdoc-gui/sidebar-links-color.goml b/tests/rustdoc-gui/sidebar-links-color.goml index 57c45555a76..9a398655f8f 100644 --- a/tests/rustdoc-gui/sidebar-links-color.goml +++ b/tests/rustdoc-gui/sidebar-links-color.goml @@ -12,6 +12,7 @@ define-function: ( enum_hover_background, union, union_hover, union_hover_background, trait, trait_hover, trait_hover_background, fn, fn_hover, fn_hover_background, type, type_hover, type_hover_background, keyword, keyword_hover, keyword_hover_background, + attribute, attribute_hover, attribute_hover_background, ], block { call-function: ("switch-theme", {"theme": |theme|}) @@ -85,6 +86,16 @@ define-function: ( ".sidebar .block.keyword a:hover", {"color": |keyword_hover|, "background-color": |keyword_hover_background|}, ) + // Attribute + assert-css: ( + ".sidebar .block.attribute a", + {"color": |attribute|, "background-color": "rgba(0, 0, 0, 0)"}, + ) + move-cursor-to: ".sidebar .block.attribute a" + assert-css: ( + ".sidebar .block.attribute a:hover", + {"color": |attribute_hover|, "background-color": |attribute_hover_background|}, + ) } ) @@ -113,6 +124,9 @@ call-function: ( "keyword": "#53b1db", "keyword_hover": "#ffb44c", "keyword_hover_background": "transparent", + "attribute": "#53b1db", + "attribute_hover": "#ffb44c", + "attribute_hover_background": "transparent", } ) call-function: ( @@ -140,6 +154,9 @@ call-function: ( "keyword": "#fdbf35", "keyword_hover": "#fdbf35", "keyword_hover_background": "#444", + "attribute": "#fdbf35", + "attribute_hover": "#fdbf35", + "attribute_hover_background": "#444", } ) call-function: ( @@ -167,5 +184,8 @@ call-function: ( "keyword": "#356da4", "keyword_hover": "#356da4", "keyword_hover_background": "#fff", + "attribute": "#356da4", + "attribute_hover": "#356da4", + "attribute_hover_background": "#fff", } ) diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 623f5b33e9b..42f2fbd93b1 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -161,6 +161,10 @@ pub enum AnEnum { /// Some keyword. pub mod keyword {} +#[doc(attribute = "forbid")] +/// Some attribute. +pub mod repr {} + /// Just some type alias. pub type SomeType = u32; diff --git a/tests/rustdoc-json/doc_attribute.rs b/tests/rustdoc-json/doc_attribute.rs new file mode 100644 index 00000000000..9e1a711f0b7 --- /dev/null +++ b/tests/rustdoc-json/doc_attribute.rs @@ -0,0 +1,18 @@ +// Doc attributes (`#[doc(attribute = "...")]` should not be generated in rustdoc JSON output +// and this test ensures it. + +#![feature(rustdoc_internals)] +#![no_std] + +//@ !has "$.index[?(@.name=='repr')]" +//@ has "$.index[?(@.name=='foo')]" + +#[doc(attribute = "repr")] +/// this is a test! +pub mod foo {} + +//@ !has "$.index[?(@.name=='forbid')]" +//@ !has "$.index[?(@.name=='bar')]" +#[doc(attribute = "forbid")] +/// hello +mod bar {} diff --git a/tests/rustdoc-ui/invalid-attribute.rs b/tests/rustdoc-ui/invalid-attribute.rs new file mode 100644 index 00000000000..2fc7be2cf34 --- /dev/null +++ b/tests/rustdoc-ui/invalid-attribute.rs @@ -0,0 +1,10 @@ +// Testing the output when an invalid builtin attribute is passed as value +// to `doc(attribute = "...")`. + +#![feature(rustdoc_internals)] + +#[doc(attribute = "foo df")] //~ ERROR +mod foo {} + +#[doc(attribute = "fooyi")] //~ ERROR +mod foo2 {} diff --git a/tests/rustdoc-ui/invalid-attribute.stderr b/tests/rustdoc-ui/invalid-attribute.stderr new file mode 100644 index 00000000000..66e68ce44b4 --- /dev/null +++ b/tests/rustdoc-ui/invalid-attribute.stderr @@ -0,0 +1,18 @@ +error: nonexistent builtin attribute `foo df` used in `#[doc(attribute = "...")]` + --> $DIR/invalid-attribute.rs:6:19 + | +LL | #[doc(attribute = "foo df")] + | ^^^^^^^^ + | + = help: only existing builtin attributes are allowed in core/std + +error: nonexistent builtin attribute `fooyi` used in `#[doc(attribute = "...")]` + --> $DIR/invalid-attribute.rs:9:19 + | +LL | #[doc(attribute = "fooyi")] + | ^^^^^^^ + | + = help: only existing builtin attributes are allowed in core/std + +error: aborting due to 2 previous errors + diff --git a/tests/rustdoc/doc-attribute.rs b/tests/rustdoc/doc-attribute.rs new file mode 100644 index 00000000000..92e603ae6e5 --- /dev/null +++ b/tests/rustdoc/doc-attribute.rs @@ -0,0 +1,24 @@ +// Test checking the `#[doc(attribute = "...")]` attribute. + +#![crate_name = "foo"] + +#![feature(rustdoc_internals)] + +//@ has foo/index.html '//h2[@id="attributes"]' 'Attributes' +//@ has foo/index.html '//a[@href="attribute.no_mangle.html"]' 'no_mangle' +//@ has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Attributes' +//@ has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#attributes' +//@ has foo/attribute.no_mangle.html '//h1' 'Attribute no_mangle' +//@ has foo/attribute.no_mangle.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' +//@ has foo/index.html '//a/@href' '../foo/index.html' +//@ !has foo/foo/index.html +//@ !has-dir foo/foo +//@ !has foo/index.html '//span' '🔒' +#[doc(attribute = "no_mangle")] +/// this is a test! +mod foo{} + +//@ has foo/attribute.repr.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' +#[doc(attribute = "repr")] +/// hello +mod bar {} diff --git a/tests/ui/feature-gates/feature-gate-rustdoc_internals.rs b/tests/ui/feature-gates/feature-gate-rustdoc_internals.rs index 57d6b591287..0ad3b2aead4 100644 --- a/tests/ui/feature-gates/feature-gate-rustdoc_internals.rs +++ b/tests/ui/feature-gates/feature-gate-rustdoc_internals.rs @@ -2,6 +2,10 @@ /// wonderful mod foo {} +#[doc(attribute = "repr")] //~ ERROR: `#[doc(attribute)]` is meant for internal use only +/// wonderful +mod foo2 {} + trait Mine {} #[doc(fake_variadic)] //~ ERROR: `#[doc(fake_variadic)]` is meant for internal use only diff --git a/tests/ui/feature-gates/feature-gate-rustdoc_internals.stderr b/tests/ui/feature-gates/feature-gate-rustdoc_internals.stderr index f3c00a2156b..5a6d4d3b45e 100644 --- a/tests/ui/feature-gates/feature-gate-rustdoc_internals.stderr +++ b/tests/ui/feature-gates/feature-gate-rustdoc_internals.stderr @@ -8,8 +8,18 @@ LL | #[doc(keyword = "match")] = help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: `#[doc(attribute)]` is meant for internal use only + --> $DIR/feature-gate-rustdoc_internals.rs:5:1 + | +LL | #[doc(attribute = "repr")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #90418 for more information + = help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: `#[doc(fake_variadic)]` is meant for internal use only - --> $DIR/feature-gate-rustdoc_internals.rs:7:1 + --> $DIR/feature-gate-rustdoc_internals.rs:11:1 | LL | #[doc(fake_variadic)] | ^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +29,7 @@ LL | #[doc(fake_variadic)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[doc(search_unbox)]` is meant for internal use only - --> $DIR/feature-gate-rustdoc_internals.rs:10:1 + --> $DIR/feature-gate-rustdoc_internals.rs:14:1 | LL | #[doc(search_unbox)] | ^^^^^^^^^^^^^^^^^^^^ @@ -28,6 +38,6 @@ LL | #[doc(search_unbox)] = help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0658`. -- cgit 1.4.1-3-g733a5 From 38e8963b148fef9fb9c4263cc49d448985bb9982 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 13 Jun 2025 21:04:07 +0200 Subject: Add documentation for `doc(attribute = "...")` attribute --- src/doc/rustdoc/src/unstable-features.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index bb28e3abbf3..25c929a1dba 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -196,7 +196,7 @@ to enable. ### Document keywords -This is for Rust compiler internal use only. +This is for internal use in the std library. Rust keywords are documented in the standard library (look for `match` for example). @@ -211,6 +211,23 @@ To do so, the `#[doc(keyword = "...")]` attribute is used. Example: mod empty_mod {} ``` +### Document builtin attributes + +This is for internal use in the std library. + +Rust builtin attributes are documented in the standard library (look for `repr` for example). + +To do so, the `#[doc(attribute = "...")]` attribute is used. Example: + +```rust +#![feature(rustdoc_internals)] +#![allow(internal_features)] + +/// Some documentation about the attribute. +#[doc(attribute = "repr")] +mod empty_mod {} +``` + ### Use the Rust logo as the crate logo This is for official Rust project use only. -- cgit 1.4.1-3-g733a5 From 10bd61dcf2e5a7dbe95b4b0588a432a444f907a9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 14 Jun 2025 12:41:30 +0200 Subject: Create new `Item::is_fake_item` method as equivalent to check for `is_primitive`, `is_keyword` and `is_attribute` methods --- compiler/rustc_passes/src/check_attr.rs | 66 ++++++++++++++++++++++---------- src/librustdoc/clean/types.rs | 11 ++++++ src/librustdoc/html/render/context.rs | 2 +- src/librustdoc/html/render/print_item.rs | 2 +- 4 files changed, 58 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index fa7591b5113..410c39fbb41 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -99,6 +99,21 @@ impl IntoDiagArg for ProcMacroKind { } } +#[derive(Clone, Copy)] +enum DocFakeItemKind { + Attribute, + Keyword, +} + +impl DocFakeItemKind { + fn name(self) -> &'static str { + match self { + Self::Attribute => "attribute", + Self::Keyword => "keyword", + } + } +} + struct CheckAttrVisitor<'tcx> { tcx: TyCtxt<'tcx>, @@ -855,7 +870,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &self, meta: &MetaItemInner, hir_id: HirId, - is_keyword: bool, + attr_kind: DocFakeItemKind, ) { fn is_doc_keyword(s: Symbol) -> bool { // FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we @@ -868,13 +883,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { rustc_feature::BUILTIN_ATTRIBUTE_MAP.contains_key(&s) } - fn get_attr_name(is_keyword: bool) -> &'static str { - if is_keyword { "keyword" } else { "attribute" } - } - let value = match meta.value_str() { Some(value) if value != sym::empty => value, - _ => return self.doc_attr_str_error(meta, get_attr_name(is_keyword)), + _ => return self.doc_attr_str_error(meta, attr_kind.name()), }; let item_kind = match self.tcx.hir_node(hir_id) { @@ -886,7 +897,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if !module.item_ids.is_empty() { self.dcx().emit_err(errors::DocKeywordAttributeEmptyMod { span: meta.span(), - attr_name: get_attr_name(is_keyword), + attr_name: attr_kind.name(), }); return; } @@ -894,23 +905,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { self.dcx().emit_err(errors::DocKeywordAttributeNotMod { span: meta.span(), - attr_name: get_attr_name(is_keyword), + attr_name: attr_kind.name(), }); return; } } - if is_keyword { - if !is_doc_keyword(value) { - self.dcx().emit_err(errors::DocKeywordNotKeyword { - span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - keyword: value, - }); + match attr_kind { + DocFakeItemKind::Keyword => { + if !is_doc_keyword(value) { + self.dcx().emit_err(errors::DocKeywordNotKeyword { + span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + keyword: value, + }); + } + } + DocFakeItemKind::Attribute => { + if !is_builtin_attr(value) { + self.dcx().emit_err(errors::DocAttributeNotAttribute { + span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + attribute: value, + }); + } } - } else if !is_builtin_attr(value) { - self.dcx().emit_err(errors::DocAttributeNotAttribute { - span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - attribute: value, - }); } } @@ -1170,13 +1186,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Some(sym::keyword) => { if self.check_attr_not_crate_level(meta, hir_id, "keyword") { - self.check_doc_keyword_and_attribute(meta, hir_id, true); + self.check_doc_keyword_and_attribute( + meta, + hir_id, + DocFakeItemKind::Keyword, + ); } } Some(sym::attribute) => { if self.check_attr_not_crate_level(meta, hir_id, "attribute") { - self.check_doc_keyword_and_attribute(meta, hir_id, false); + self.check_doc_keyword_and_attribute( + meta, + hir_id, + DocFakeItemKind::Attribute, + ); } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 1502ec9bd78..fcff15650ce 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -608,6 +608,17 @@ impl Item { pub(crate) fn is_attribute(&self) -> bool { self.type_() == ItemType::Attribute } + /// Returns `true` if the item kind is one of the following: + /// + /// * `ItemType::Primitive` + /// * `ItemType::Keyword` + /// * `ItemType::Attribute` + /// + /// They are considered fake because they only exist thanks to their + /// `#[doc(primitive|keyword|attribute)]` attribute. + pub(crate) fn is_fake_item(&self) -> bool { + matches!(self.type_(), ItemType::Primitive | ItemType::Keyword | ItemType::Attribute) + } pub(crate) fn is_stripped(&self) -> bool { match self.kind { StrippedItem(..) => true, diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index cafbcf7e8dd..5f92ab2fada 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -218,7 +218,7 @@ impl<'tcx> Context<'tcx> { } else { it.name.as_ref().unwrap().as_str() }; - if !it.is_primitive() && !it.is_keyword() && !it.is_attribute() { + if !it.is_fake_item() { if !is_module { title.push_str(" in "); } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 530e6da4ee3..afa438f2596 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -194,7 +194,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item) -> impl fmt::Disp let src_href = if cx.info.include_sources && !item.is_primitive() { cx.src_href(item) } else { None }; - let path_components = if item.is_primitive() || item.is_keyword() || item.is_attribute() { + let path_components = if item.is_fake_item() { vec![] } else { let cur = &cx.current; -- cgit 1.4.1-3-g733a5 From f3c023433f6e44be208f9e3bb74528449da730c1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 28 Aug 2025 16:27:54 +0200 Subject: Add ui test for unsupported `doc(attribute = "...")` case for attributes with namespace --- compiler/rustc_passes/src/check_attr.rs | 1 + tests/rustdoc-ui/doc-attribute-unsupported.rs | 7 +++++++ tests/rustdoc-ui/doc-attribute-unsupported.stderr | 10 ++++++++++ 3 files changed, 18 insertions(+) create mode 100644 tests/rustdoc-ui/doc-attribute-unsupported.rs create mode 100644 tests/rustdoc-ui/doc-attribute-unsupported.stderr diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 410c39fbb41..962555ada27 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -879,6 +879,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() || s == sym::SelfTy } + // FIXME: This should support attributes with namespace like `diagnostic::do_not_recommend`. fn is_builtin_attr(s: Symbol) -> bool { rustc_feature::BUILTIN_ATTRIBUTE_MAP.contains_key(&s) } diff --git a/tests/rustdoc-ui/doc-attribute-unsupported.rs b/tests/rustdoc-ui/doc-attribute-unsupported.rs new file mode 100644 index 00000000000..3bd153117a9 --- /dev/null +++ b/tests/rustdoc-ui/doc-attribute-unsupported.rs @@ -0,0 +1,7 @@ +// This is currently not supported but should be! + +#![feature(rustdoc_internals)] + +#[doc(attribute = "diagnostic::do_not_recommend")] //~ ERROR +/// bla +mod yup {} diff --git a/tests/rustdoc-ui/doc-attribute-unsupported.stderr b/tests/rustdoc-ui/doc-attribute-unsupported.stderr new file mode 100644 index 00000000000..e2480a548ac --- /dev/null +++ b/tests/rustdoc-ui/doc-attribute-unsupported.stderr @@ -0,0 +1,10 @@ +error: nonexistent builtin attribute `diagnostic::do_not_recommend` used in `#[doc(attribute = "...")]` + --> $DIR/doc-attribute-unsupported.rs:5:19 + | +LL | #[doc(attribute = "diagnostic::do_not_recommend")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: only existing builtin attributes are allowed in core/std + +error: aborting due to 1 previous error + -- cgit 1.4.1-3-g733a5 From 2c7dfa91b5b4dcde136880894a9fd4dae70114db Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 25 Aug 2025 17:53:01 +0200 Subject: Add another case to the bad-lit-suffixes test Signed-off-by: Jonathan Brouwer --- tests/ui/parser/bad-lit-suffixes.rs | 7 +++++++ tests/ui/parser/bad-lit-suffixes.stderr | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/ui/parser/bad-lit-suffixes.rs b/tests/ui/parser/bad-lit-suffixes.rs index 91b32fd4539..792d4a140fc 100644 --- a/tests/ui/parser/bad-lit-suffixes.rs +++ b/tests/ui/parser/bad-lit-suffixes.rs @@ -45,3 +45,10 @@ extern "C" {} //~^ ERROR invalid suffix `suffix` for number literal //~| ERROR malformed `rustc_layout_scalar_valid_range_start` attribute input struct S; + +impl S { + #[rustc_confusables("blah"suffix)] + //~^ ERROR suffixes on string literals are invalid + //~| ERROR malformed `rustc_confusables` attribute input + fn woof() { } +} \ No newline at end of file diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr index 217cc74b8eb..952695ed0a4 100644 --- a/tests/ui/parser/bad-lit-suffixes.stderr +++ b/tests/ui/parser/bad-lit-suffixes.stderr @@ -202,6 +202,21 @@ LL | #[rustc_layout_scalar_valid_range_start(0suffix)] | | expected an integer literal here | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` -error: aborting due to 23 previous errors; 2 warnings emitted +error: suffixes on string literals are invalid + --> $DIR/bad-lit-suffixes.rs:50:25 + | +LL | #[rustc_confusables("blah"suffix)] + | ^^^^^^^^^^^^ invalid suffix `suffix` + +error[E0539]: malformed `rustc_confusables` attribute input + --> $DIR/bad-lit-suffixes.rs:50:5 + | +LL | #[rustc_confusables("blah"suffix)] + | ^^^^^^^^^^^^^^^^^^^^------------^^ + | | | + | | expected a string literal here + | help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` + +error: aborting due to 25 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0539`. -- cgit 1.4.1-3-g733a5 From f32870927604ab4dbf12ff84681b77e65a096940 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Thu, 28 Aug 2025 20:03:58 +0200 Subject: Improve error messages around invalid literals in attribute arguments Signed-off-by: Jonathan Brouwer --- compiler/rustc_attr_parsing/src/parser.rs | 59 +++++++++++++++++++------------ compiler/rustc_parse/src/parser/expr.rs | 4 +-- compiler/rustc_session/src/errors.rs | 24 +++++++------ 3 files changed, 52 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 6d3cf684296..4f903594225 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -10,11 +10,11 @@ use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path}; use rustc_ast_pretty::pprust; -use rustc_errors::PResult; +use rustc_errors::{Diag, PResult}; use rustc_hir::{self as hir, AttrPath}; use rustc_parse::exp; use rustc_parse::parser::{Parser, PathStyle, token_descr}; -use rustc_session::errors::report_lit_error; +use rustc_session::errors::{create_lit_error, report_lit_error}; use rustc_session::parse::ParseSess; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym}; use thin_vec::ThinVec; @@ -379,22 +379,23 @@ struct MetaItemListParserContext<'a, 'sess> { impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'sess, MetaItemLit> { - let uninterpolated_span = self.parser.token_uninterpolated_span(); - let Some(token_lit) = self.parser.eat_token_lit() else { - return self.parser.handle_missing_lit(Parser::mk_meta_item_lit_char); - }; + let Some(token_lit) = self.parser.eat_token_lit() else { return Err(self.expected_lit()) }; + self.unsuffixed_meta_item_from_lit(token_lit) + } + fn unsuffixed_meta_item_from_lit( + &mut self, + token_lit: token::Lit, + ) -> PResult<'sess, MetaItemLit> { let lit = match MetaItemLit::from_token_lit(token_lit, self.parser.prev_token.span) { Ok(lit) => lit, Err(err) => { - let guar = - report_lit_error(&self.parser.psess, err, token_lit, uninterpolated_span); - // Pack possible quotes and prefixes from the original literal into - // the error literal's symbol so they can be pretty-printed faithfully. - let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None); - let symbol = Symbol::intern(&suffixless_lit.to_string()); - let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix); - MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap() + return Err(create_lit_error( + &self.parser.psess, + err, + token_lit, + self.parser.prev_token_uninterpolated_span(), + )); } }; @@ -448,16 +449,28 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { } fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser<'static>> { - match self.parse_unsuffixed_meta_item_lit() { - Ok(lit) => return Ok(MetaItemOrLitParser::Lit(lit)), - Err(err) => err.cancel(), // we provide a better error below - } - - match self.parse_attr_item() { - Ok(mi) => return Ok(MetaItemOrLitParser::MetaItemParser(mi)), - Err(err) => err.cancel(), // we provide a better error below + if let Some(token_lit) = self.parser.eat_token_lit() { + // If a literal token is parsed, we commit to parsing a MetaItemLit for better errors + Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?)) + } else { + let prev_pros = self.parser.approx_token_stream_pos(); + match self.parse_attr_item() { + Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)), + Err(err) => { + // If `parse_attr_item` made any progress, it likely has a more precise error we should prefer + // If it didn't make progress we use the `expected_lit` from below + if self.parser.approx_token_stream_pos() != prev_pros { + Err(err) + } else { + err.cancel(); + Err(self.expected_lit()) + } + } + } } + } + fn expected_lit(&mut self) -> Diag<'sess> { let mut err = InvalidMetaItem { span: self.parser.token.span, descr: token_descr(&self.parser.token), @@ -492,7 +505,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { self.parser.bump(); } - Err(self.parser.dcx().create_err(err)) + self.parser.dcx().create_err(err) } fn parse( diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index f0f58e901a9..7de4f6efd0b 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2077,7 +2077,7 @@ impl<'a> Parser<'a> { (token::Lit { symbol: name, suffix: None, kind: token::Char }, span) } - pub fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit { + fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit { ast::MetaItemLit { symbol: name, suffix: None, @@ -2086,7 +2086,7 @@ impl<'a> Parser<'a> { } } - pub fn handle_missing_lit( + fn handle_missing_lit( &mut self, mk_lit_char: impl FnOnce(Symbol, Span) -> L, ) -> PResult<'a, L> { diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 34da54a20bf..50bc7348dc9 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -384,6 +384,10 @@ pub fn report_lit_error( lit: token::Lit, span: Span, ) -> ErrorGuaranteed { + create_lit_error(psess, err, lit, span).emit() +} + +pub fn create_lit_error(psess: &ParseSess, err: LitError, lit: token::Lit, span: Span) -> Diag<'_> { // Checks if `s` looks like i32 or u1234 etc. fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) @@ -414,32 +418,32 @@ pub fn report_lit_error( let dcx = psess.dcx(); match err { LitError::InvalidSuffix(suffix) => { - dcx.emit_err(InvalidLiteralSuffix { span, kind: lit.kind.descr(), suffix }) + dcx.create_err(InvalidLiteralSuffix { span, kind: lit.kind.descr(), suffix }) } LitError::InvalidIntSuffix(suffix) => { let suf = suffix.as_str(); if looks_like_width_suffix(&['i', 'u'], suf) { // If it looks like a width, try to be helpful. - dcx.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }) + dcx.create_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }) } else if let Some(fixed) = fix_base_capitalisation(lit.symbol.as_str(), suf) { - dcx.emit_err(InvalidNumLiteralBasePrefix { span, fixed }) + dcx.create_err(InvalidNumLiteralBasePrefix { span, fixed }) } else { - dcx.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }) + dcx.create_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }) } } LitError::InvalidFloatSuffix(suffix) => { let suf = suffix.as_str(); if looks_like_width_suffix(&['f'], suf) { // If it looks like a width, try to be helpful. - dcx.emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() }) + dcx.create_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() }) } else { - dcx.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() }) + dcx.create_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() }) } } LitError::NonDecimalFloat(base) => match base { - 16 => dcx.emit_err(HexadecimalFloatLiteralNotSupported { span }), - 8 => dcx.emit_err(OctalFloatLiteralNotSupported { span }), - 2 => dcx.emit_err(BinaryFloatLiteralNotSupported { span }), + 16 => dcx.create_err(HexadecimalFloatLiteralNotSupported { span }), + 8 => dcx.create_err(OctalFloatLiteralNotSupported { span }), + 2 => dcx.create_err(BinaryFloatLiteralNotSupported { span }), _ => unreachable!(), }, LitError::IntTooLarge(base) => { @@ -450,7 +454,7 @@ pub fn report_lit_error( 16 => format!("{max:#x}"), _ => format!("{max}"), }; - dcx.emit_err(IntLiteralTooLarge { span, limit }) + dcx.create_err(IntLiteralTooLarge { span, limit }) } } } -- cgit 1.4.1-3-g733a5 From e0bdc46d949b80f6eebc42a844671b23d7120e38 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Thu, 28 Aug 2025 20:04:07 +0200 Subject: Update uitest stderr Signed-off-by: Jonathan Brouwer --- tests/ui/parser/bad-lit-suffixes.rs | 5 +--- tests/ui/parser/bad-lit-suffixes.stderr | 49 ++------------------------------- 2 files changed, 4 insertions(+), 50 deletions(-) diff --git a/tests/ui/parser/bad-lit-suffixes.rs b/tests/ui/parser/bad-lit-suffixes.rs index 792d4a140fc..0a1ee120730 100644 --- a/tests/ui/parser/bad-lit-suffixes.rs +++ b/tests/ui/parser/bad-lit-suffixes.rs @@ -38,17 +38,14 @@ fn g() {} #[link(name = "string"suffix)] //~^ ERROR suffixes on string literals are invalid -//~| ERROR malformed `link` attribute input extern "C" {} #[rustc_layout_scalar_valid_range_start(0suffix)] //~^ ERROR invalid suffix `suffix` for number literal -//~| ERROR malformed `rustc_layout_scalar_valid_range_start` attribute input struct S; impl S { #[rustc_confusables("blah"suffix)] //~^ ERROR suffixes on string literals are invalid - //~| ERROR malformed `rustc_confusables` attribute input fn woof() { } -} \ No newline at end of file +} diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr index 952695ed0a4..6c3dbbcec64 100644 --- a/tests/ui/parser/bad-lit-suffixes.stderr +++ b/tests/ui/parser/bad-lit-suffixes.stderr @@ -160,63 +160,20 @@ error: suffixes on string literals are invalid LL | #[link(name = "string"suffix)] | ^^^^^^^^^^^^^^ invalid suffix `suffix` -error[E0539]: malformed `link` attribute input - --> $DIR/bad-lit-suffixes.rs:39:1 - | -LL | #[link(name = "string"suffix)] - | ^^^^^^^---------------------^^ - | | - | expected this to be of the form `name = "..."` - | - = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "string"suffix)] -LL + #[link(name = "...")] - | -LL - #[link(name = "string"suffix)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "string"suffix)] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "string"suffix)] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate - error: invalid suffix `suffix` for number literal - --> $DIR/bad-lit-suffixes.rs:44:41 + --> $DIR/bad-lit-suffixes.rs:43:41 | LL | #[rustc_layout_scalar_valid_range_start(0suffix)] | ^^^^^^^ invalid suffix `suffix` | = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) -error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input - --> $DIR/bad-lit-suffixes.rs:44:1 - | -LL | #[rustc_layout_scalar_valid_range_start(0suffix)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^ - | | | - | | expected an integer literal here - | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` - error: suffixes on string literals are invalid - --> $DIR/bad-lit-suffixes.rs:50:25 + --> $DIR/bad-lit-suffixes.rs:48:25 | LL | #[rustc_confusables("blah"suffix)] | ^^^^^^^^^^^^ invalid suffix `suffix` -error[E0539]: malformed `rustc_confusables` attribute input - --> $DIR/bad-lit-suffixes.rs:50:5 - | -LL | #[rustc_confusables("blah"suffix)] - | ^^^^^^^^^^^^^^^^^^^^------------^^ - | | | - | | expected a string literal here - | help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` - -error: aborting due to 25 previous errors; 2 warnings emitted +error: aborting due to 22 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0539`. -- cgit 1.4.1-3-g733a5 From 4edfeb2f60e4c9f871117965070946ff566810d0 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 28 Aug 2025 20:11:07 +0200 Subject: compiler: Include span of too huge enum with -Cdebuginfo=2 We have a ui test to ensure we emit an error if we encounter too big enums. Before this fix, compiling the test with `-Cdebuginfo=2` would not include the span of the instantiation site, because the error is then emitted from a different code path that does not include the span. Propagate the span to the error also in the debuginfo case, so the test passes regardless of debuginfo level. --- compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 14 ++++++++++++-- .../rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs | 5 +++-- compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 6 ++++-- tests/ui/limits/huge-enum.full-debuginfo.stderr | 8 ++++++++ tests/ui/limits/huge-enum.no-debuginfo.stderr | 8 ++++++++ tests/ui/limits/huge-enum.rs | 8 +++++--- tests/ui/limits/huge-enum.stderr | 8 -------- 7 files changed, 40 insertions(+), 17 deletions(-) create mode 100644 tests/ui/limits/huge-enum.full-debuginfo.stderr create mode 100644 tests/ui/limits/huge-enum.no-debuginfo.stderr delete mode 100644 tests/ui/limits/huge-enum.stderr diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 0e9dbfba658..caa3369f413 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -19,7 +19,9 @@ use rustc_middle::ty::{ self, AdtKind, CoroutineArgsExt, ExistentialTraitRef, Instance, Ty, TyCtxt, Visibility, }; use rustc_session::config::{self, DebugInfo, Lto}; -use rustc_span::{DUMMY_SP, FileName, FileNameDisplayPreference, SourceFile, Symbol, hygiene}; +use rustc_span::{ + DUMMY_SP, FileName, FileNameDisplayPreference, SourceFile, Span, Symbol, hygiene, +}; use rustc_symbol_mangling::typeid_for_trait_ref; use rustc_target::spec::DebuginfoKind; use smallvec::smallvec; @@ -423,6 +425,14 @@ fn build_slice_type_di_node<'ll, 'tcx>( /// This function will look up the debuginfo node in the TypeMap. If it can't find it, it /// will create the node by dispatching to the corresponding `build_*_di_node()` function. pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { + spanned_type_di_node(cx, t, DUMMY_SP) +} + +pub(crate) fn spanned_type_di_node<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + t: Ty<'tcx>, + span: Span, +) -> &'ll DIType { let unique_type_id = UniqueTypeId::for_ty(cx.tcx, t); if let Some(existing_di_node) = debug_context(cx).type_map.di_node_for_unique_id(unique_type_id) @@ -460,7 +470,7 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> ty::Adt(def, ..) => match def.adt_kind() { AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id), AdtKind::Union => build_union_type_di_node(cx, unique_type_id), - AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id), + AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id, span), }, ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id), _ => bug!("debuginfo: unexpected type in type_di_node(): {:?}", t), diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 7c701926d2c..caff3586079 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -10,7 +10,7 @@ use rustc_middle::bug; use rustc_middle::mir::CoroutineLayout; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef}; -use rustc_span::Symbol; +use rustc_span::{Span, Symbol}; use super::type_map::{DINodeCreationResult, UniqueTypeId}; use super::{SmallVec, size_and_align_of}; @@ -30,13 +30,14 @@ mod native; pub(super) fn build_enum_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, unique_type_id: UniqueTypeId<'tcx>, + span: Span, ) -> DINodeCreationResult<'ll> { let enum_type = unique_type_id.expect_ty(); let &ty::Adt(enum_adt_def, _) = enum_type.kind() else { bug!("build_enum_type_di_node() called with non-enum type: `{:?}`", enum_type) }; - let enum_type_and_layout = cx.layout_of(enum_type); + let enum_type_and_layout = cx.spanned_layout_of(enum_type, span); if wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout) { return build_c_style_enum_di_node(cx, enum_adt_def, enum_type_and_layout); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 2c3a84499ac..79334f7f9fe 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -28,7 +28,9 @@ use rustc_target::spec::DebuginfoKind; use smallvec::SmallVec; use tracing::debug; -use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, type_di_node}; +use self::metadata::{ + UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, spanned_type_di_node, type_di_node, +}; use self::namespace::mangled_name_of_instance; use self::utils::{DIB, create_DIArray, is_node_local_to_unit}; use crate::builder::Builder; @@ -626,7 +628,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let loc = self.lookup_debug_loc(span.lo()); let file_metadata = file_metadata(self, &loc.file); - let type_metadata = type_di_node(self, variable_type); + let type_metadata = spanned_type_di_node(self, variable_type, span); let (argument_index, dwarf_tag) = match variable_kind { ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable), diff --git a/tests/ui/limits/huge-enum.full-debuginfo.stderr b/tests/ui/limits/huge-enum.full-debuginfo.stderr new file mode 100644 index 00000000000..4b179d59e5f --- /dev/null +++ b/tests/ui/limits/huge-enum.full-debuginfo.stderr @@ -0,0 +1,8 @@ +error: values of the type `Option` are too big for the target architecture + --> $DIR/huge-enum.rs:17:9 + | +LL | let big: BIG = None; + | ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/limits/huge-enum.no-debuginfo.stderr b/tests/ui/limits/huge-enum.no-debuginfo.stderr new file mode 100644 index 00000000000..4b179d59e5f --- /dev/null +++ b/tests/ui/limits/huge-enum.no-debuginfo.stderr @@ -0,0 +1,8 @@ +error: values of the type `Option` are too big for the target architecture + --> $DIR/huge-enum.rs:17:9 + | +LL | let big: BIG = None; + | ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/limits/huge-enum.rs b/tests/ui/limits/huge-enum.rs index 6d5b86411f3..9395bee9765 100644 --- a/tests/ui/limits/huge-enum.rs +++ b/tests/ui/limits/huge-enum.rs @@ -1,9 +1,11 @@ +// FIXME(#61117): Remove revisions once x86_64-gnu-debug CI job sets rust.debuginfo-level-tests=2 +// NOTE: The .stderr for both revisions shall be identical. +//@ revisions: no-debuginfo full-debuginfo //@ build-fail //@ normalize-stderr: "std::option::Option<\[u32; \d+\]>" -> "TYPE" //@ normalize-stderr: "\[u32; \d+\]" -> "TYPE" - -// FIXME(#61117): Respect debuginfo-level-tests, do not force debuginfo-level=0 -//@ compile-flags: -Cdebuginfo=0 +//@[no-debuginfo] compile-flags: -Cdebuginfo=0 +//@[full-debuginfo] compile-flags: -Cdebuginfo=2 #[cfg(target_pointer_width = "32")] type BIG = Option<[u32; (1<<29)-1]>; diff --git a/tests/ui/limits/huge-enum.stderr b/tests/ui/limits/huge-enum.stderr deleted file mode 100644 index 5b97a2104a3..00000000000 --- a/tests/ui/limits/huge-enum.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: values of the type `Option` are too big for the target architecture - --> $DIR/huge-enum.rs:15:9 - | -LL | let big: BIG = None; - | ^^^ - -error: aborting due to 1 previous error - -- cgit 1.4.1-3-g733a5 From d76cff3f06f4de2e760eee3130c8a393fa4a124f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 28 Aug 2025 17:36:46 +0000 Subject: Only export the sanitizer symbols for LTO and move export code to cg_llvm Don't export them from cdylibs. There is no need to do so and it complicates exported_non_generic_symbols. In addition the GCC backend likely uses different symbols and may potentially not even need us to explicitly tell it to export the symbols it needs. --- compiler/rustc_codegen_llvm/src/back/lto.rs | 28 +++++++++++++ .../rustc_codegen_ssa/src/back/symbol_export.rs | 49 +--------------------- 2 files changed, 29 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index d85f432702c..551a448d97c 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -15,6 +15,7 @@ use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::memmap::Mmap; use rustc_errors::DiagCtxtHandle; +use rustc_hir::attrs::SanitizerSet; use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; use rustc_session::config::{self, Lto}; @@ -42,6 +43,33 @@ fn prepare_lto( .map(|symbol| CString::new(symbol.to_owned()).unwrap()) .collect::>(); + if cgcx.regular_module_config.instrument_coverage + || cgcx.regular_module_config.pgo_gen.enabled() + { + // These are weak symbols that point to the profile version and the + // profile name, which need to be treated as exported so LTO doesn't nix + // them. + const PROFILER_WEAK_SYMBOLS: [&CStr; 2] = + [c"__llvm_profile_raw_version", c"__llvm_profile_filename"]; + + symbols_below_threshold.extend(PROFILER_WEAK_SYMBOLS.iter().map(|&sym| sym.to_owned())); + } + + if cgcx.regular_module_config.sanitizer.contains(SanitizerSet::MEMORY) { + let mut msan_weak_symbols = Vec::new(); + + // Similar to profiling, preserve weak msan symbol during LTO. + if cgcx.regular_module_config.sanitizer_recover.contains(SanitizerSet::MEMORY) { + msan_weak_symbols.push(c"__msan_keep_going"); + } + + if cgcx.regular_module_config.sanitizer_memory_track_origins != 0 { + msan_weak_symbols.push(c"__msan_track_origins"); + } + + symbols_below_threshold.extend(msan_weak_symbols.into_iter().map(|sym| sym.to_owned())); + } + // __llvm_profile_counter_bias is pulled in at link time by an undefined reference to // __llvm_profile_runtime, therefore we won't know until link time if this symbol // should have default visibility. diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 13419bcb22c..d8a1480e911 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolNam use rustc_middle::util::Providers; use rustc_session::config::{CrateType, OomStrategy}; use rustc_symbol_mangling::mangle_internal_symbol; -use rustc_target::spec::{SanitizerSet, TlsModel}; +use rustc_target::spec::TlsModel; use tracing::debug; use crate::base::allocator_kind_for_codegen; @@ -242,53 +242,6 @@ fn exported_non_generic_symbols_provider_local<'tcx>( } } - if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() { - // These are weak symbols that point to the profile version and the - // profile name, which need to be treated as exported so LTO doesn't nix - // them. - const PROFILER_WEAK_SYMBOLS: [&str; 2] = - ["__llvm_profile_raw_version", "__llvm_profile_filename"]; - - symbols.extend(PROFILER_WEAK_SYMBOLS.iter().map(|sym| { - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym)); - ( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::C, - kind: SymbolExportKind::Data, - used: false, - rustc_std_internal_symbol: false, - }, - ) - })); - } - - if tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) { - let mut msan_weak_symbols = Vec::new(); - - // Similar to profiling, preserve weak msan symbol during LTO. - if tcx.sess.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY) { - msan_weak_symbols.push("__msan_keep_going"); - } - - if tcx.sess.opts.unstable_opts.sanitizer_memory_track_origins != 0 { - msan_weak_symbols.push("__msan_track_origins"); - } - - symbols.extend(msan_weak_symbols.into_iter().map(|sym| { - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym)); - ( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::C, - kind: SymbolExportKind::Data, - used: false, - rustc_std_internal_symbol: false, - }, - ) - })); - } - // Sort so we get a stable incr. comp. hash. symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx)); -- cgit 1.4.1-3-g733a5 From 23e72ab41e27842eae0d60a6f4750c5151aabcbc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:05:47 +0000 Subject: Move ___asan_globals_registered export All other sanitizer symbols are handled in prepare_lto already. --- compiler/rustc_codegen_llvm/src/back/lto.rs | 4 ++++ compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 6 ------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 551a448d97c..fc38c4f3e51 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -70,6 +70,10 @@ fn prepare_lto( symbols_below_threshold.extend(msan_weak_symbols.into_iter().map(|sym| sym.to_owned())); } + // Preserve LLVM-injected, ASAN-related symbols. + // See also https://github.com/rust-lang/rust/issues/113404. + symbols_below_threshold.push(c"___asan_globals_registered".to_owned()); + // __llvm_profile_counter_bias is pulled in at link time by an undefined reference to // __llvm_profile_runtime, therefore we won't know until link time if this symbol // should have default visibility. diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 8c34052770e..dd492325814 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1226,12 +1226,6 @@ extern "C" void LLVMRustPrintPasses() { extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols, size_t Len) { auto PreserveFunctions = [=](const GlobalValue &GV) { - // Preserve LLVM-injected, ASAN-related symbols. - // See also https://github.com/rust-lang/rust/issues/113404. - if (GV.getName() == "___asan_globals_registered") { - return true; - } - // Preserve symbols exported from Rust modules. for (size_t I = 0; I < Len; I++) { if (GV.getName() == Symbols[I]) { -- cgit 1.4.1-3-g733a5 From df802ccd2fad88ea617622ae0bf89067a250145e Mon Sep 17 00:00:00 2001 From: neeko-cat <60898184+neeko-cat@users.noreply.github.com> Date: Thu, 28 Aug 2025 22:19:37 +0200 Subject: fix `core::marker::Destruct` doc --- library/core/src/marker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 8ad58599c68..73aad27afef 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1049,7 +1049,7 @@ marker_impls! { /// A marker for types that can be dropped. /// -/// This should be used for `~const` bounds, +/// This should be used for `[const]` bounds, /// as non-const bounds will always hold for every type. #[unstable(feature = "const_destruct", issue = "133214")] #[rustc_const_unstable(feature = "const_destruct", issue = "133214")] -- cgit 1.4.1-3-g733a5 From 1a33d628df211c92650e357c291097b6ce4f223f Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Thu, 28 Aug 2025 18:37:58 -0400 Subject: implement Sum and Product for Saturating(u*) --- library/core/src/iter/traits/accum.rs | 58 +++++++++++++++++++++++++++- library/coretests/tests/iter/traits/accum.rs | 36 +++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index 12e2b8b393a..73122369b41 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -1,5 +1,5 @@ use crate::iter; -use crate::num::Wrapping; +use crate::num::{Saturating, Wrapping}; /// Trait to represent types that can be created by summing up an iterator. /// @@ -98,6 +98,61 @@ macro_rules! integer_sum_product { ); } +macro_rules! saturating_integer_sum_product { + (@impls $zero:expr, $one:expr, $doc:expr, #[$attr:meta], $($a:ty)*) => ($( + #[$attr] + #[doc = $doc] + impl Sum for $a { + fn sum>(iter: I) -> Self { + iter.fold( + $zero, + |a, b| a + b, + ) + } + } + + #[$attr] + #[doc = $doc] + impl Product for $a { + fn product>(iter: I) -> Self { + iter.fold( + $one, + |a, b| a * b, + ) + } + } + + #[$attr] + #[doc = $doc] + impl<'a> Sum<&'a $a> for $a { + fn sum>(iter: I) -> Self { + iter.fold( + $zero, + |a, b| a + b, + ) + } + } + + #[$attr] + #[doc = $doc] + impl<'a> Product<&'a $a> for $a { + fn product>(iter: I) -> Self { + iter.fold( + $one, + |a, b| a * b, + ) + } + } + )*); + ($($a:ty)*) => ( + saturating_integer_sum_product!(@impls Saturating(0), Saturating(1), + "The short-circuiting behavior of this implementation is unspecified. If you care about \ + short-circuiting, use [`Iterator::fold`] directly.", + #[stable(feature = "saturating_iter_arith", since = "CURRENT_RUSTC_VERSION")], + $(Saturating<$a>)*); + ); +} + macro_rules! float_sum_product { ($($a:ident)*) => ($( #[stable(feature = "iter_arith_traits", since = "1.12.0")] @@ -147,6 +202,7 @@ macro_rules! float_sum_product { } integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize } +saturating_integer_sum_product! { u8 u16 u32 u64 u128 usize } float_sum_product! { f32 f64 } #[stable(feature = "iter_arith_traits_result", since = "1.16.0")] diff --git a/library/coretests/tests/iter/traits/accum.rs b/library/coretests/tests/iter/traits/accum.rs index f3eeb31fe58..95f299d2680 100644 --- a/library/coretests/tests/iter/traits/accum.rs +++ b/library/coretests/tests/iter/traits/accum.rs @@ -1,4 +1,5 @@ use core::iter::*; +use std::num::Saturating; #[test] fn test_iterator_sum() { @@ -64,3 +65,38 @@ fn test_iterator_product_option() { let v: &[Option] = &[Some(1), None, Some(3), Some(4)]; assert_eq!(v.iter().cloned().product::>(), None); } + +#[test] +fn test_saturating_sum_product() { + let v = (1u32..=10).map(|i| Saturating(i)); + assert_eq!(v.sum::>(), Saturating(55)); + let v = (1u32..=10).map(|i| Saturating(i)); + assert_eq!(v.product::>(), Saturating(3628800)); + let v = [Saturating(usize::MAX), Saturating(2)]; + assert_eq!(v.iter().copied().sum::>(), Saturating(usize::MAX)); + assert_eq!(v.iter().copied().product::>(), Saturating(usize::MAX)); + + let mut cnt = 0; + let v = 250..=u8::MAX; + assert_eq!( + v.map(|i| { + cnt += 1; + Saturating(i) + }) + .sum::>(), + Saturating(u8::MAX) + ); + assert_eq!(cnt, 6); // no short-circuiting + + let mut cnt = 0; + let v = (250..=u8::MAX).chain(0..5); + assert_eq!( + v.map(|i| { + cnt += 1; + Saturating(i) + }) + .product::>(), + Saturating(0) + ); + assert_eq!(cnt, 11); // no short-circuiting +} -- cgit 1.4.1-3-g733a5 From 2d0668d37cd5d10504bdd62bcedef457b8fbad40 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Thu, 28 Aug 2025 23:03:25 +0000 Subject: Mark pipe2 supported in Android Android has supported pipe2 since 2010, long before the current min SDK. --- library/std/src/sys/pal/unix/pipe.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/pal/unix/pipe.rs b/library/std/src/sys/pal/unix/pipe.rs index 6b0cd14da4f..4798acf9dad 100644 --- a/library/std/src/sys/pal/unix/pipe.rs +++ b/library/std/src/sys/pal/unix/pipe.rs @@ -20,6 +20,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { // and musl 0.9.3, and some other targets also have it. cfg_select! { any( + target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "hurd", -- cgit 1.4.1-3-g733a5 From a54567e76ce0b32c6d48d019ab4bd9c8a7070933 Mon Sep 17 00:00:00 2001 From: Caiweiran Date: Fri, 29 Aug 2025 08:11:48 +0000 Subject: tests: Ignore basic-stepping.rs on riscv64 --- tests/debuginfo/basic-stepping.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/debuginfo/basic-stepping.rs b/tests/debuginfo/basic-stepping.rs index e7a70c8b087..f6399814a43 100644 --- a/tests/debuginfo/basic-stepping.rs +++ b/tests/debuginfo/basic-stepping.rs @@ -4,6 +4,7 @@ //@ ignore-aarch64: Doesn't work yet. //@ ignore-loongarch64: Doesn't work yet. +//@ ignore-riscv64: Doesn't work yet. //@ compile-flags: -g // gdb-command: run -- cgit 1.4.1-3-g733a5 From 3d54f19421d07781e1ce7283ed99b4eb39a08bb5 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 28 Aug 2025 13:53:10 +1000 Subject: Don't bother logging an arbitrary subset of the compiletest config Running `./x --verbose` will still print out the command-line arguments, and setting `RUST_LOG=compiletest` will now log the full config instead of a subset. --- src/tools/compiletest/src/bin/main.rs | 3 +-- src/tools/compiletest/src/lib.rs | 48 ++--------------------------------- 2 files changed, 3 insertions(+), 48 deletions(-) diff --git a/src/tools/compiletest/src/bin/main.rs b/src/tools/compiletest/src/bin/main.rs index 1f777e71cf9..8fac6ccdc58 100644 --- a/src/tools/compiletest/src/bin/main.rs +++ b/src/tools/compiletest/src/bin/main.rs @@ -2,7 +2,7 @@ use std::env; use std::io::IsTerminal; use std::sync::Arc; -use compiletest::{early_config_check, log_config, parse_config, run_tests}; +use compiletest::{early_config_check, parse_config, run_tests}; fn main() { tracing_subscriber::fmt::init(); @@ -19,6 +19,5 @@ fn main() { early_config_check(&config); - log_config(&config); run_tests(config); } diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 58f7c6b5071..91ab40edc60 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -44,7 +44,6 @@ use crate::common::{ }; use crate::directives::DirectivesCache; use crate::executor::{CollectedTest, ColorConfig}; -use crate::util::logv; /// Creates the `Config` instance for this invocation of compiletest. /// @@ -477,51 +476,6 @@ pub fn parse_config(args: Vec) -> Config { } } -pub fn log_config(config: &Config) { - let c = config; - logv(c, "configuration:".to_string()); - logv(c, format!("compile_lib_path: {}", config.compile_lib_path)); - logv(c, format!("run_lib_path: {}", config.run_lib_path)); - logv(c, format!("rustc_path: {}", config.rustc_path)); - logv(c, format!("cargo_path: {:?}", config.cargo_path)); - logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path)); - - logv(c, format!("src_root: {}", config.src_root)); - logv(c, format!("src_test_suite_root: {}", config.src_test_suite_root)); - - logv(c, format!("build_root: {}", config.build_root)); - logv(c, format!("build_test_suite_root: {}", config.build_test_suite_root)); - - logv(c, format!("sysroot_base: {}", config.sysroot_base)); - - logv(c, format!("stage: {}", config.stage)); - logv(c, format!("stage_id: {}", config.stage_id)); - logv(c, format!("mode: {}", config.mode)); - logv(c, format!("run_ignored: {}", config.run_ignored)); - logv(c, format!("filters: {:?}", config.filters)); - logv(c, format!("skip: {:?}", config.skip)); - logv(c, format!("filter_exact: {}", config.filter_exact)); - logv( - c, - format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),), - ); - logv(c, format!("runner: {}", opt_str(&config.runner))); - logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags)); - logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags)); - logv(c, format!("target: {}", config.target)); - logv(c, format!("host: {}", config.host)); - logv(c, format!("android-cross-path: {}", config.android_cross_path)); - logv(c, format!("adb_path: {}", config.adb_path)); - logv(c, format!("adb_test_dir: {}", config.adb_test_dir)); - logv(c, format!("adb_device_status: {}", config.adb_device_status)); - logv(c, format!("ar: {}", config.ar)); - logv(c, format!("target-linker: {:?}", config.target_linker)); - logv(c, format!("host-linker: {:?}", config.host_linker)); - logv(c, format!("verbose: {}", config.verbose)); - logv(c, format!("minicore_path: {}", config.minicore_path)); - logv(c, "\n".to_string()); -} - pub fn opt_str(maybestr: &Option) -> &str { match *maybestr { None => "(none)", @@ -538,6 +492,8 @@ pub fn opt_str2(maybestr: Option) -> String { /// Called by `main` after the config has been parsed. pub fn run_tests(config: Arc) { + debug!(?config, "run_tests"); + // If we want to collect rustfix coverage information, // we first make sure that the coverage file does not exist. // It will be created later on. -- cgit 1.4.1-3-g733a5 From 269db62491b43be6292af0fdabb84a1eb6c77c5d Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 28 Aug 2025 14:15:33 +1000 Subject: Change the `logv` function into a `TestCx` method. When working on a new output-capture system, this will make it easier to obtain a capturing stream from the test context. --- src/tools/compiletest/src/runtest.rs | 18 +++++++++++++++--- src/tools/compiletest/src/runtest/debuginfo.rs | 3 +-- src/tools/compiletest/src/runtest/pretty.rs | 10 +++------- src/tools/compiletest/src/util.rs | 11 ----------- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 3a05b242519..aa463d7b255 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -7,7 +7,7 @@ use std::io::prelude::*; use std::io::{self, BufReader}; use std::process::{Child, Command, ExitStatus, Output, Stdio}; use std::sync::Arc; -use std::{env, iter, str}; +use std::{env, fmt, iter, str}; use build_helper::fs::remove_and_create_dir_all; use camino::{Utf8Path, Utf8PathBuf}; @@ -25,7 +25,7 @@ use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; use crate::directives::TestProps; use crate::errors::{Error, ErrorKind, load_errors}; use crate::read2::{Truncated, read2_abbreviated}; -use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex}; +use crate::util::{Utf8PathBufExt, add_dylib_path, static_regex}; use crate::{ColorConfig, help, json, stamp_file_path, warning}; mod debugger; @@ -1459,7 +1459,7 @@ impl<'test> TestCx<'test> { ) -> ProcRes { let cmdline = { let cmdline = self.make_cmdline(&command, lib_path); - logv(self.config, format!("executing {}", cmdline)); + self.logv(format_args!("executing {cmdline}")); cmdline }; @@ -2006,6 +2006,18 @@ impl<'test> TestCx<'test> { output_base_name(self.config, self.testpaths, self.safe_revision()) } + /// Prints a message to (captured) stdout if `config.verbose` is true. + /// The message is also logged to `tracing::debug!` regardles of verbosity. + /// + /// Use `format_args!` as the argument to perform formatting if required. + fn logv(&self, message: impl fmt::Display) { + debug!("{message}"); + if self.config.verbose { + // Note: `./x test ... --verbose --no-capture` is needed to see this print. + println!("{message}"); + } + } + /// Prefix to print before error messages. Normally just `error`, but also /// includes the revision name for tests that use revisions. #[must_use] diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 24fdbab3aec..88d022b8bba 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -10,7 +10,6 @@ use super::debugger::DebuggerCommands; use super::{Debugger, Emit, ProcRes, TestCx, Truncated, WillExecute}; use crate::common::Config; use crate::debuggers::{extract_gdb_version, is_android_gdb_target}; -use crate::util::logv; impl TestCx<'_> { pub(super) fn run_debuginfo_test(&self) { @@ -234,7 +233,7 @@ impl TestCx<'_> { gdb.args(debugger_opts); // FIXME(jieyouxu): don't pass an empty Path let cmdline = self.make_cmdline(&gdb, Utf8Path::new("")); - logv(self.config, format!("executing {}", cmdline)); + self.logv(format_args!("executing {cmdline}")); cmdline }; diff --git a/src/tools/compiletest/src/runtest/pretty.rs b/src/tools/compiletest/src/runtest/pretty.rs index e3b07f1d63d..26557727233 100644 --- a/src/tools/compiletest/src/runtest/pretty.rs +++ b/src/tools/compiletest/src/runtest/pretty.rs @@ -1,14 +1,13 @@ use std::fs; use super::{ProcRes, ReadFrom, TestCx}; -use crate::util::logv; impl TestCx<'_> { pub(super) fn run_pretty_test(&self) { if self.props.pp_exact.is_some() { - logv(self.config, "testing for exact pretty-printing".to_owned()); + self.logv("testing for exact pretty-printing"); } else { - logv(self.config, "testing for converging pretty-printing".to_owned()); + self.logv("testing for converging pretty-printing"); } let rounds = match self.props.pp_exact { @@ -21,10 +20,7 @@ impl TestCx<'_> { let mut round = 0; while round < rounds { - logv( - self.config, - format!("pretty-printing round {} revision {:?}", round, self.revision), - ); + self.logv(format_args!("pretty-printing round {round} revision {:?}", self.revision)); let read_from = if round == 0 { ReadFrom::Path } else { ReadFrom::Stdin(srcs[round].to_owned()) }; diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index fb047548c45..1f16a672a98 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -2,9 +2,6 @@ use std::env; use std::process::Command; use camino::{Utf8Path, Utf8PathBuf}; -use tracing::*; - -use crate::common::Config; #[cfg(test)] mod tests; @@ -26,14 +23,6 @@ fn path_div() -> &'static str { ";" } -pub fn logv(config: &Config, s: String) { - debug!("{}", s); - if config.verbose { - // Note: `./x test ... --verbose --no-capture` is needed to see this print. - println!("{}", s); - } -} - pub trait Utf8PathBufExt { /// Append an extension to the path, even if it already has one. fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf; -- cgit 1.4.1-3-g733a5 From c80cadee6424ac5ad8fe017c4ea0b18a5bff4b56 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 28 Aug 2025 14:24:13 +1000 Subject: Move module `compute_diff` into `compiletest::runtest` The code in this module is always called in the context of running an individual tests, and sometimes prints output that needs to be captured. Moving this module into `runtest` will make it easier to find and audit all of the print statements that need to be updated when overhauling output-capture. --- src/tools/compiletest/src/compute_diff.rs | 160 ---------------------- src/tools/compiletest/src/lib.rs | 1 - src/tools/compiletest/src/runtest.rs | 6 +- src/tools/compiletest/src/runtest/compute_diff.rs | 160 ++++++++++++++++++++++ src/tools/compiletest/src/runtest/mir_opt.rs | 2 +- 5 files changed, 164 insertions(+), 165 deletions(-) delete mode 100644 src/tools/compiletest/src/compute_diff.rs create mode 100644 src/tools/compiletest/src/runtest/compute_diff.rs diff --git a/src/tools/compiletest/src/compute_diff.rs b/src/tools/compiletest/src/compute_diff.rs deleted file mode 100644 index 509e7e11703..00000000000 --- a/src/tools/compiletest/src/compute_diff.rs +++ /dev/null @@ -1,160 +0,0 @@ -use std::collections::VecDeque; -use std::fs::{File, FileType}; - -use camino::Utf8Path; - -#[derive(Debug, PartialEq)] -pub enum DiffLine { - Context(String), - Expected(String), - Resulting(String), -} - -#[derive(Debug, PartialEq)] -pub struct Mismatch { - pub line_number: u32, - pub lines: Vec, -} - -impl Mismatch { - fn new(line_number: u32) -> Mismatch { - Mismatch { line_number, lines: Vec::new() } - } -} - -// Produces a diff between the expected output and actual output. -pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec { - let mut line_number = 1; - let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size); - let mut lines_since_mismatch = context_size + 1; - let mut results = Vec::new(); - let mut mismatch = Mismatch::new(0); - - for result in diff::lines(expected, actual) { - match result { - diff::Result::Left(s) => { - if lines_since_mismatch >= context_size && lines_since_mismatch > 0 { - results.push(mismatch); - mismatch = Mismatch::new(line_number - context_queue.len() as u32); - } - - while let Some(line) = context_queue.pop_front() { - mismatch.lines.push(DiffLine::Context(line.to_owned())); - } - - mismatch.lines.push(DiffLine::Expected(s.to_owned())); - line_number += 1; - lines_since_mismatch = 0; - } - diff::Result::Right(s) => { - if lines_since_mismatch >= context_size && lines_since_mismatch > 0 { - results.push(mismatch); - mismatch = Mismatch::new(line_number - context_queue.len() as u32); - } - - while let Some(line) = context_queue.pop_front() { - mismatch.lines.push(DiffLine::Context(line.to_owned())); - } - - mismatch.lines.push(DiffLine::Resulting(s.to_owned())); - lines_since_mismatch = 0; - } - diff::Result::Both(s, _) => { - if context_queue.len() >= context_size { - let _ = context_queue.pop_front(); - } - - if lines_since_mismatch < context_size { - mismatch.lines.push(DiffLine::Context(s.to_owned())); - } else if context_size > 0 { - context_queue.push_back(s); - } - - line_number += 1; - lines_since_mismatch += 1; - } - } - } - - results.push(mismatch); - results.remove(0); - - results -} - -pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> String { - use std::fmt::Write; - let mut output = String::new(); - let diff_results = make_diff(expected, actual, context_size); - for result in diff_results { - let mut line_number = result.line_number; - for line in result.lines { - match line { - DiffLine::Expected(e) => { - writeln!(output, "-\t{}", e).unwrap(); - line_number += 1; - } - DiffLine::Context(c) => { - writeln!(output, "{}\t{}", line_number, c).unwrap(); - line_number += 1; - } - DiffLine::Resulting(r) => { - writeln!(output, "+\t{}", r).unwrap(); - } - } - } - writeln!(output).unwrap(); - } - output -} - -/// Filters based on filetype and extension whether to diff a file. -/// -/// Returns whether any data was actually written. -pub(crate) fn write_filtered_diff( - diff_filename: &str, - out_dir: &Utf8Path, - compare_dir: &Utf8Path, - verbose: bool, - filter: Filter, -) -> bool -where - Filter: Fn(FileType, Option<&str>) -> bool, -{ - use std::io::{Read, Write}; - let mut diff_output = File::create(diff_filename).unwrap(); - let mut wrote_data = false; - for entry in walkdir::WalkDir::new(out_dir.as_std_path()) { - let entry = entry.expect("failed to read file"); - let extension = entry.path().extension().and_then(|p| p.to_str()); - if filter(entry.file_type(), extension) { - let expected_path = compare_dir - .as_std_path() - .join(entry.path().strip_prefix(&out_dir.as_std_path()).unwrap()); - let expected = if let Ok(s) = std::fs::read(&expected_path) { s } else { continue }; - let actual_path = entry.path(); - let actual = std::fs::read(&actual_path).unwrap(); - let diff = unified_diff::diff( - &expected, - &expected_path.to_str().unwrap(), - &actual, - &actual_path.to_str().unwrap(), - 3, - ); - wrote_data |= !diff.is_empty(); - diff_output.write_all(&diff).unwrap(); - } - } - - if !wrote_data { - println!("note: diff is identical to nightly rustdoc"); - assert!(diff_output.metadata().unwrap().len() == 0); - return false; - } else if verbose { - eprintln!("printing diff:"); - let mut buf = Vec::new(); - diff_output.read_to_end(&mut buf).unwrap(); - std::io::stderr().lock().write_all(&mut buf).unwrap(); - } - true -} diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 91ab40edc60..8737fec80bb 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -9,7 +9,6 @@ mod tests; pub mod common; -pub mod compute_diff; mod debuggers; pub mod diagnostics; pub mod directives; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index aa463d7b255..eea471bc6cb 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -21,15 +21,13 @@ use crate::common::{ UI_WINDOWS_SVG, expected_output_path, incremental_dir, output_base_dir, output_base_name, output_testname_unique, }; -use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; use crate::directives::TestProps; use crate::errors::{Error, ErrorKind, load_errors}; use crate::read2::{Truncated, read2_abbreviated}; +use crate::runtest::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; use crate::util::{Utf8PathBufExt, add_dylib_path, static_regex}; use crate::{ColorConfig, help, json, stamp_file_path, warning}; -mod debugger; - // Helper modules that implement test running logic for each test suite. // tidy-alphabetical-start mod assembly; @@ -48,6 +46,8 @@ mod rustdoc_json; mod ui; // tidy-alphabetical-end +mod compute_diff; +mod debugger; #[cfg(test)] mod tests; diff --git a/src/tools/compiletest/src/runtest/compute_diff.rs b/src/tools/compiletest/src/runtest/compute_diff.rs new file mode 100644 index 00000000000..509e7e11703 --- /dev/null +++ b/src/tools/compiletest/src/runtest/compute_diff.rs @@ -0,0 +1,160 @@ +use std::collections::VecDeque; +use std::fs::{File, FileType}; + +use camino::Utf8Path; + +#[derive(Debug, PartialEq)] +pub enum DiffLine { + Context(String), + Expected(String), + Resulting(String), +} + +#[derive(Debug, PartialEq)] +pub struct Mismatch { + pub line_number: u32, + pub lines: Vec, +} + +impl Mismatch { + fn new(line_number: u32) -> Mismatch { + Mismatch { line_number, lines: Vec::new() } + } +} + +// Produces a diff between the expected output and actual output. +pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec { + let mut line_number = 1; + let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size); + let mut lines_since_mismatch = context_size + 1; + let mut results = Vec::new(); + let mut mismatch = Mismatch::new(0); + + for result in diff::lines(expected, actual) { + match result { + diff::Result::Left(s) => { + if lines_since_mismatch >= context_size && lines_since_mismatch > 0 { + results.push(mismatch); + mismatch = Mismatch::new(line_number - context_queue.len() as u32); + } + + while let Some(line) = context_queue.pop_front() { + mismatch.lines.push(DiffLine::Context(line.to_owned())); + } + + mismatch.lines.push(DiffLine::Expected(s.to_owned())); + line_number += 1; + lines_since_mismatch = 0; + } + diff::Result::Right(s) => { + if lines_since_mismatch >= context_size && lines_since_mismatch > 0 { + results.push(mismatch); + mismatch = Mismatch::new(line_number - context_queue.len() as u32); + } + + while let Some(line) = context_queue.pop_front() { + mismatch.lines.push(DiffLine::Context(line.to_owned())); + } + + mismatch.lines.push(DiffLine::Resulting(s.to_owned())); + lines_since_mismatch = 0; + } + diff::Result::Both(s, _) => { + if context_queue.len() >= context_size { + let _ = context_queue.pop_front(); + } + + if lines_since_mismatch < context_size { + mismatch.lines.push(DiffLine::Context(s.to_owned())); + } else if context_size > 0 { + context_queue.push_back(s); + } + + line_number += 1; + lines_since_mismatch += 1; + } + } + } + + results.push(mismatch); + results.remove(0); + + results +} + +pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> String { + use std::fmt::Write; + let mut output = String::new(); + let diff_results = make_diff(expected, actual, context_size); + for result in diff_results { + let mut line_number = result.line_number; + for line in result.lines { + match line { + DiffLine::Expected(e) => { + writeln!(output, "-\t{}", e).unwrap(); + line_number += 1; + } + DiffLine::Context(c) => { + writeln!(output, "{}\t{}", line_number, c).unwrap(); + line_number += 1; + } + DiffLine::Resulting(r) => { + writeln!(output, "+\t{}", r).unwrap(); + } + } + } + writeln!(output).unwrap(); + } + output +} + +/// Filters based on filetype and extension whether to diff a file. +/// +/// Returns whether any data was actually written. +pub(crate) fn write_filtered_diff( + diff_filename: &str, + out_dir: &Utf8Path, + compare_dir: &Utf8Path, + verbose: bool, + filter: Filter, +) -> bool +where + Filter: Fn(FileType, Option<&str>) -> bool, +{ + use std::io::{Read, Write}; + let mut diff_output = File::create(diff_filename).unwrap(); + let mut wrote_data = false; + for entry in walkdir::WalkDir::new(out_dir.as_std_path()) { + let entry = entry.expect("failed to read file"); + let extension = entry.path().extension().and_then(|p| p.to_str()); + if filter(entry.file_type(), extension) { + let expected_path = compare_dir + .as_std_path() + .join(entry.path().strip_prefix(&out_dir.as_std_path()).unwrap()); + let expected = if let Ok(s) = std::fs::read(&expected_path) { s } else { continue }; + let actual_path = entry.path(); + let actual = std::fs::read(&actual_path).unwrap(); + let diff = unified_diff::diff( + &expected, + &expected_path.to_str().unwrap(), + &actual, + &actual_path.to_str().unwrap(), + 3, + ); + wrote_data |= !diff.is_empty(); + diff_output.write_all(&diff).unwrap(); + } + } + + if !wrote_data { + println!("note: diff is identical to nightly rustdoc"); + assert!(diff_output.metadata().unwrap().len() == 0); + return false; + } else if verbose { + eprintln!("printing diff:"); + let mut buf = Vec::new(); + diff_output.read_to_end(&mut buf).unwrap(); + std::io::stderr().lock().write_all(&mut buf).unwrap(); + } + true +} diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs index efdb131bf14..55043bf4bc2 100644 --- a/src/tools/compiletest/src/runtest/mir_opt.rs +++ b/src/tools/compiletest/src/runtest/mir_opt.rs @@ -6,7 +6,7 @@ use miropt_test_tools::{MiroptTest, MiroptTestFile, files_for_miropt_test}; use tracing::debug; use super::{Emit, TestCx, WillExecute}; -use crate::compute_diff::write_diff; +use crate::runtest::compute_diff::write_diff; impl TestCx<'_> { pub(super) fn run_mir_opt_test(&self) { -- cgit 1.4.1-3-g733a5 From 6340b97768cc3803d96de92c8571d49f79f3e2ed Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 29 Jul 2025 12:37:30 +1000 Subject: Don't print captures in `TestCx::normalize_platform_differences` This appears to have been leftover debugging code. If the capture information turns out to have still been useful, we can find a way to emit it in a way that doesn't interfere with overhauling compiletests's output capture system. --- src/tools/compiletest/src/runtest.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index eea471bc6cb..867624cc8fa 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2678,8 +2678,8 @@ impl<'test> TestCx<'test> { // // It's not possible to detect paths in the error messages generally, but this is a // decent enough heuristic. - static_regex!( - r#"(?x) + let re = static_regex!( + r#"(?x) (?: # Match paths that don't include spaces. (?:\\[\pL\pN\.\-_']+)+\.\pL+ @@ -2687,11 +2687,8 @@ impl<'test> TestCx<'test> { # If the path starts with a well-known root, then allow spaces and no file extension. \$(?:DIR|SRC_DIR|TEST_BUILD_DIR|BUILD_DIR|LIB_DIR)(?:\\[\pL\pN\.\-_'\ ]+)+ )"# - ) - .replace_all(&output, |caps: &Captures<'_>| { - println!("{}", &caps[0]); - caps[0].replace(r"\", "/") - }) + ); + re.replace_all(&output, |caps: &Captures<'_>| caps[0].replace(r"\", "/")) .replace("\r\n", "\n") } -- cgit 1.4.1-3-g733a5 From 16b5ac111c1299a4ba9324104eb1cba22d54383b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 29 Aug 2025 14:26:44 +1000 Subject: Remove very outdated comment about token streams. They're now just an `Arc>`. No ropes, no views, nothing like that. --- compiler/rustc_ast/src/tokenstream.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index f4f35a4d2ee..f9bac42ada3 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -3,15 +3,6 @@ //! `TokenStream`s represent syntactic objects before they are converted into ASTs. //! A `TokenStream` is, roughly speaking, a sequence of [`TokenTree`]s, //! which are themselves a single [`Token`] or a `Delimited` subsequence of tokens. -//! -//! ## Ownership -//! -//! `TokenStream`s are persistent data structures constructed as ropes with reference -//! counted-children. In general, this means that calling an operation on a `TokenStream` -//! (such as `slice`) produces an entirely new `TokenStream` from the borrowed reference to -//! the original. This essentially coerces `TokenStream`s into "views" of their subparts, -//! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking -//! ownership of the original. use std::borrow::Cow; use std::ops::Range; -- cgit 1.4.1-3-g733a5 From 364a3be579bbc6a9a06b3d32e84748382e1001ae Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 29 Aug 2025 14:25:40 +1000 Subject: Put `TokenStream` stuff in a sensible order. I.e. the type definition, then a single inherent `impl` block, then the trait `impl` blocks. The lack of sensible ordering here has bugged me for some time. --- compiler/rustc_ast/src/tokenstream.rs | 132 +++++++++++++++++----------------- 1 file changed, 65 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index f9bac42ada3..a5d8fbfac61 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -90,17 +90,6 @@ impl TokenTree { } } -impl HashStable for TokenStream -where - CTX: crate::HashStableContext, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - for sub_tt in self.iter() { - sub_tt.hash_stable(hcx, hasher); - } - } -} - /// A lazy version of [`AttrTokenStream`], which defers creation of an actual /// `AttrTokenStream` until it is needed. #[derive(Clone)] @@ -547,10 +536,6 @@ pub struct AttrsTarget { pub tokens: LazyAttrTokenStream, } -/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s. -#[derive(Clone, Debug, Default, Encodable, Decodable)] -pub struct TokenStream(pub(crate) Arc>); - /// Indicates whether a token can join with the following token to form a /// compound token. Used for conversions to `proc_macro::Spacing`. Also used to /// guide pretty-printing, which is where the `JointHidden` value (which isn't @@ -611,58 +596,9 @@ pub enum Spacing { JointHidden, } -impl TokenStream { - /// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream` - /// separating the two arguments with a comma for diagnostic suggestions. - pub fn add_comma(&self) -> Option<(TokenStream, Span)> { - // Used to suggest if a user writes `foo!(a b);` - let mut suggestion = None; - let mut iter = self.0.iter().enumerate().peekable(); - while let Some((pos, ts)) = iter.next() { - if let Some((_, next)) = iter.peek() { - let sp = match (&ts, &next) { - (_, TokenTree::Token(Token { kind: token::Comma, .. }, _)) => continue, - ( - TokenTree::Token(token_left, Spacing::Alone), - TokenTree::Token(token_right, _), - ) if (token_left.is_non_reserved_ident() || token_left.is_lit()) - && (token_right.is_non_reserved_ident() || token_right.is_lit()) => - { - token_left.span - } - (TokenTree::Delimited(sp, ..), _) => sp.entire(), - _ => continue, - }; - let sp = sp.shrink_to_hi(); - let comma = TokenTree::token_alone(token::Comma, sp); - suggestion = Some((pos, comma, sp)); - } - } - if let Some((pos, comma, sp)) = suggestion { - let mut new_stream = Vec::with_capacity(self.0.len() + 1); - let parts = self.0.split_at(pos + 1); - new_stream.extend_from_slice(parts.0); - new_stream.push(comma); - new_stream.extend_from_slice(parts.1); - return Some((TokenStream::new(new_stream), sp)); - } - None - } -} - -impl FromIterator for TokenStream { - fn from_iter>(iter: I) -> Self { - TokenStream::new(iter.into_iter().collect::>()) - } -} - -impl Eq for TokenStream {} - -impl PartialEq for TokenStream { - fn eq(&self, other: &TokenStream) -> bool { - self.iter().eq(other.iter()) - } -} +/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s. +#[derive(Clone, Debug, Default, Encodable, Decodable)] +pub struct TokenStream(pub(crate) Arc>); impl TokenStream { pub fn new(tts: Vec) -> TokenStream { @@ -838,6 +774,68 @@ impl TokenStream { } } } + + /// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream` + /// separating the two arguments with a comma for diagnostic suggestions. + pub fn add_comma(&self) -> Option<(TokenStream, Span)> { + // Used to suggest if a user writes `foo!(a b);` + let mut suggestion = None; + let mut iter = self.0.iter().enumerate().peekable(); + while let Some((pos, ts)) = iter.next() { + if let Some((_, next)) = iter.peek() { + let sp = match (&ts, &next) { + (_, TokenTree::Token(Token { kind: token::Comma, .. }, _)) => continue, + ( + TokenTree::Token(token_left, Spacing::Alone), + TokenTree::Token(token_right, _), + ) if (token_left.is_non_reserved_ident() || token_left.is_lit()) + && (token_right.is_non_reserved_ident() || token_right.is_lit()) => + { + token_left.span + } + (TokenTree::Delimited(sp, ..), _) => sp.entire(), + _ => continue, + }; + let sp = sp.shrink_to_hi(); + let comma = TokenTree::token_alone(token::Comma, sp); + suggestion = Some((pos, comma, sp)); + } + } + if let Some((pos, comma, sp)) = suggestion { + let mut new_stream = Vec::with_capacity(self.0.len() + 1); + let parts = self.0.split_at(pos + 1); + new_stream.extend_from_slice(parts.0); + new_stream.push(comma); + new_stream.extend_from_slice(parts.1); + return Some((TokenStream::new(new_stream), sp)); + } + None + } +} + +impl PartialEq for TokenStream { + fn eq(&self, other: &TokenStream) -> bool { + self.iter().eq(other.iter()) + } +} + +impl Eq for TokenStream {} + +impl FromIterator for TokenStream { + fn from_iter>(iter: I) -> Self { + TokenStream::new(iter.into_iter().collect::>()) + } +} + +impl HashStable for TokenStream +where + CTX: crate::HashStableContext, +{ + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + for sub_tt in self.iter() { + sub_tt.hash_stable(hcx, hasher); + } + } } #[derive(Clone)] -- cgit 1.4.1-3-g733a5 From 6fd0e50ecf25e3d1ef6185a3b85dfec24e9e8cb2 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 29 Aug 2025 10:42:44 +0200 Subject: autoderef final ty is already resolved --- compiler/rustc_hir_analysis/src/autoderef.rs | 12 ++++-------- compiler/rustc_hir_typeck/src/autoderef.rs | 2 +- compiler/rustc_hir_typeck/src/callee.rs | 5 ++--- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 2 +- compiler/rustc_hir_typeck/src/place_op.rs | 3 +-- 6 files changed, 10 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index c88c534e135..e27e68d3662 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -202,14 +202,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { Some((normalized_ty, ocx.into_pending_obligations())) } - /// Returns the final type we ended up with, which may be an inference - /// variable (we will resolve it first, if we want). - pub fn final_ty(&self, resolve: bool) -> Ty<'tcx> { - if resolve { - self.infcx.resolve_vars_if_possible(self.state.cur_ty) - } else { - self.state.cur_ty - } + /// Returns the final type we ended up with, which may be an unresolved + /// inference variable. + pub fn final_ty(&self) -> Ty<'tcx> { + self.state.cur_ty } pub fn step_count(&self) -> usize { diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs index 7af26623ce7..4fe77278706 100644 --- a/compiler/rustc_hir_typeck/src/autoderef.rs +++ b/compiler/rustc_hir_typeck/src/autoderef.rs @@ -42,7 +42,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut obligations = PredicateObligations::new(); let targets = - steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(autoderef.final_ty(false))); + steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(autoderef.final_ty())); let steps: Vec<_> = steps .iter() .map(|&(source, kind)| { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 4200afb74e6..c6a4d78dcc8 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef); } - match autoderef.final_ty(false).kind() { + match autoderef.final_ty().kind() { ty::FnDef(def_id, _) => { let abi = self.tcx.fn_sig(def_id).skip_binder().skip_binder().abi; self.check_call_abi(abi, call_expr.span); @@ -200,8 +200,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], autoderef: &Autoderef<'a, 'tcx>, ) -> Option> { - let adjusted_ty = - self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false)); + let adjusted_ty = self.structurally_resolve_type(autoderef.span(), autoderef.final_ty()); // If the callee is a function pointer or a closure, then we're all set. match *adjusted_ty.kind() { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 940f0e3708d..a652e08905a 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2918,7 +2918,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Emits an error if we deref an infer variable, like calling `.field` on a base type // of `&_`. We can also use this to suppress unnecessary "missing field" errors that // will follow ambiguity errors. - let final_ty = self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false)); + let final_ty = self.structurally_resolve_type(autoderef.span(), autoderef.final_ty()); if let ty::Error(_) = final_ty.kind() { return final_ty; } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index bb4748b0565..ab584eb7c90 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -629,7 +629,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( .collect(); (steps, autoderef_via_deref.reached_recursion_limit()) }; - let final_ty = autoderef_via_deref.final_ty(true); + let final_ty = autoderef_via_deref.final_ty(); let opt_bad_ty = match final_ty.kind() { ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy { reached_raw_pointer, diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index fedc75abe49..1125e984080 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -109,8 +109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { index_ty: Ty<'tcx>, index_expr: &hir::Expr<'_>, ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { - let adjusted_ty = - self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false)); + let adjusted_ty = self.structurally_resolve_type(autoderef.span(), autoderef.final_ty()); debug!( "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ index_ty={:?})", -- cgit 1.4.1-3-g733a5 From e3f1e94be775db497c15e2119d09b62bb834c91f Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Fri, 29 Aug 2025 12:13:30 +0300 Subject: std: haiku: fix `B_FIND_PATH_IMAGE_PATH` --- library/std/src/sys/pal/unix/os.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 81275afa707..d70f1aab77e 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -469,7 +469,7 @@ pub fn current_exe() -> io::Result { unsafe { let result = libc::find_path( crate::ptr::null_mut(), - libc::path_base_directory::B_FIND_PATH_IMAGE_PATH, + libc::B_FIND_PATH_IMAGE_PATH, crate::ptr::null_mut(), name.as_mut_ptr(), name.len(), -- cgit 1.4.1-3-g733a5 From 85cefabfcd8caa1ab95926537252164a6d63351d Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 11 Aug 2025 12:06:38 +0200 Subject: std: use a TAIT to define `SplitPaths` on UNIX --- library/std/src/sys/pal/unix/os.rs | 36 +++++++----------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 81275afa707..0b1abe88275 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -16,10 +16,7 @@ use crate::{fmt, io, iter, mem, ptr, slice, str}; const TMPBUF_SZ: usize = 128; -const PATH_SEPARATOR: u8 = cfg_select! { - target_os = "redox" => b';', - _ => b':', -}; +const PATH_SEPARATOR: u8 = if cfg!(target_os = "redox") { b';' } else { b':' }; unsafe extern "C" { #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))] @@ -189,33 +186,14 @@ pub fn chdir(p: &path::Path) -> io::Result<()> { if result == 0 { Ok(()) } else { Err(io::Error::last_os_error()) } } -pub struct SplitPaths<'a> { - iter: iter::Map bool>, fn(&'a [u8]) -> PathBuf>, -} +pub type SplitPaths<'a> = impl Iterator; +#[define_opaque(SplitPaths)] pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> { - fn bytes_to_path(b: &[u8]) -> PathBuf { - PathBuf::from(::from_bytes(b)) - } - fn is_separator(b: &u8) -> bool { - *b == PATH_SEPARATOR - } - let unparsed = unparsed.as_bytes(); - SplitPaths { - iter: unparsed - .split(is_separator as fn(&u8) -> bool) - .map(bytes_to_path as fn(&[u8]) -> PathBuf), - } -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } + unparsed + .as_bytes() + .split(|&b| b == PATH_SEPARATOR) + .map(|part| PathBuf::from(OsStr::from_bytes(part))) } #[derive(Debug)] -- cgit 1.4.1-3-g733a5 From 638a52c789e92009cf26ed73a4a5bc597814fe7b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 29 Aug 2025 16:26:23 +0200 Subject: Improve librustdoc error when a file creation/modification failed --- src/librustdoc/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index e2682045ab4..058d9cc7c90 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -760,7 +760,9 @@ fn run_renderer< tcx.dcx().struct_fatal(format!("couldn't generate documentation: {}", e.error)); let file = e.file.display().to_string(); if !file.is_empty() { - msg.note(format!("failed to create or modify \"{file}\"")); + msg.note(format!("failed to create or modify {e}")); + } else { + msg.note(format!("failed to create or modify file: {e}")); } msg.emit(); } -- cgit 1.4.1-3-g733a5 From 435de36225382f763cc7ce6d744365c75c318596 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 30 Aug 2025 04:52:26 +0000 Subject: Prepare for merging from rust-lang/rust This updates the rust-version file to e004014d1bf4c29928a0f0f9f7d0964d43606cbd. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 5e833540002..695959e2e68 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -269d5b56bcfdf2be82213e72ef9a2e4c592a8c6b +e004014d1bf4c29928a0f0f9f7d0964d43606cbd -- cgit 1.4.1-3-g733a5