From 290cbdf50ed7aa856a6794178500c7bd76fc7ec9 Mon Sep 17 00:00:00 2001 From: ltdk Date: Thu, 15 Feb 2024 10:13:47 -0500 Subject: [PATCH 01/14] Add slice::try_range --- library/alloc/src/slice.rs | 4 +-- library/core/src/slice/index.rs | 59 ++++++++++++++++++++++++++++++--- library/core/src/slice/mod.rs | 2 +- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index f4e392760c8e4..21d5dce04a0fc 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -33,8 +33,6 @@ use crate::vec::Vec; #[cfg(test)] mod tests; -#[unstable(feature = "slice_range", issue = "76393")] -pub use core::slice::range; #[unstable(feature = "array_chunks", issue = "74985")] pub use core::slice::ArrayChunks; #[unstable(feature = "array_chunks", issue = "74985")] @@ -51,6 +49,8 @@ pub use core::slice::{from_mut, from_ref}; pub use core::slice::{from_mut_ptr_range, from_ptr_range}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{from_raw_parts, from_raw_parts_mut}; +#[unstable(feature = "slice_range", issue = "76393")] +pub use core::slice::{range, try_range}; #[stable(feature = "slice_group_by", since = "1.77.0")] pub use core::slice::{ChunkBy, ChunkByMut}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index fb9be396eab80..c34d616e268f9 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -681,8 +681,7 @@ where { let len = bounds.end; - let start: ops::Bound<&usize> = range.start_bound(); - let start = match start { + let start = match range.start_bound() { ops::Bound::Included(&start) => start, ops::Bound::Excluded(start) => { start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) @@ -690,8 +689,7 @@ where ops::Bound::Unbounded => 0, }; - let end: ops::Bound<&usize> = range.end_bound(); - let end = match end { + let end = match range.end_bound() { ops::Bound::Included(end) => { end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) } @@ -709,6 +707,59 @@ where ops::Range { start, end } } +/// Performs bounds-checking of a range without panicking. +/// +/// This is a version of [`range`] that returns [`None`] instead of panicking. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// let v = [10, 40, 30]; +/// assert_eq!(Some(1..2), slice::try_range(1..2, ..v.len())); +/// assert_eq!(Some(0..2), slice::try_range(..2, ..v.len())); +/// assert_eq!(Some(1..3), slice::try_range(1.., ..v.len())); +/// ``` +/// +/// Returns [`None`] when [`Index::index`] would panic: +/// +/// ``` +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// assert_eq!(None, slice::try_range(2..1, ..3)); +/// assert_eq!(None, slice::try_range(1..4, ..3)); +/// assert_eq!(None, slice::try_range(1..=usize::MAX, ..3)); +/// ``` +/// +/// [`Index::index`]: ops::Index::index +#[unstable(feature = "slice_range", issue = "76393")] +#[must_use] +pub fn try_range(range: R, bounds: ops::RangeTo) -> Option> +where + R: ops::RangeBounds, +{ + let len = bounds.end; + + let start = match range.start_bound() { + ops::Bound::Included(&start) => start, + ops::Bound::Excluded(start) => start.checked_add(1)?, + ops::Bound::Unbounded => 0, + }; + + let end = match range.end_bound() { + ops::Bound::Included(end) => end.checked_add(1)?, + ops::Bound::Excluded(&end) => end, + ops::Bound::Unbounded => len, + }; + + if start > end || end > len { None } else { Some(ops::Range { start, end }) } +} + /// Convert pair of `ops::Bound`s into `ops::Range` without performing any bounds checking and (in debug) overflow checking pub(crate) fn into_range_unchecked( len: usize, diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 73e92ed1dad63..aa228e12325ef 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -91,7 +91,7 @@ pub use sort::heapsort; pub use index::SliceIndex; #[unstable(feature = "slice_range", issue = "76393")] -pub use index::range; +pub use index::{range, try_range}; #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] pub use ascii::EscapeAscii; From 7e6dccc47d257727c8135ec0d933155d42463e0e Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 26 Feb 2024 11:26:13 -0300 Subject: [PATCH 02/14] Win10: Use GetSystemTimePreciseAsFileTime directly --- library/std/src/sys/pal/windows/c.rs | 1 + library/std/src/sys/pal/windows/c/bindings.txt | 1 + library/std/src/sys/pal/windows/c/windows_sys.rs | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index b007796722baf..0f9754b22b7e1 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -346,6 +346,7 @@ compat_fn_with_fallback! { // >= Win8 / Server 2012 // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime + #[cfg(target_vendor = "win7")] pub fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime: *mut FILETIME) -> () { GetSystemTimeAsFileTime(lpsystemtimeasfiletime) } diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index ab2a8caf5dfd9..5be7bee62f63b 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2475,6 +2475,7 @@ Windows.Win32.System.Pipes.PIPE_WAIT Windows.Win32.System.SystemInformation.GetSystemDirectoryW Windows.Win32.System.SystemInformation.GetSystemInfo Windows.Win32.System.SystemInformation.GetSystemTimeAsFileTime +Windows.Win32.System.SystemInformation.GetSystemTimePreciseAsFileTime Windows.Win32.System.SystemInformation.GetWindowsDirectoryW Windows.Win32.System.SystemInformation.PROCESSOR_ARCHITECTURE Windows.Win32.System.SystemInformation.SYSTEM_INFO diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 8eb779373f7e4..b18792849b8f9 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -345,6 +345,10 @@ extern "system" { pub fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime: *mut FILETIME) -> (); } #[link(name = "kernel32")] +extern "system" { + pub fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime: *mut FILETIME) -> (); +} +#[link(name = "kernel32")] extern "system" { pub fn GetTempPathW(nbufferlength: u32, lpbuffer: PWSTR) -> u32; } From eb40adbd4604e86a1b0bd3c89d71cec3d2a7d077 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 26 Feb 2024 12:01:55 -0300 Subject: [PATCH 03/14] Add shim for GetSystemTimePreciseAsFileTime This is exactly the same as GetSystemTimeAsFileTime except that it promises maximum precision. --- src/tools/miri/src/shims/time.rs | 5 +++-- src/tools/miri/src/shims/windows/foreign_items.rs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 13ce9d119bc3b..4535bcf6dfedd 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -110,12 +110,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { #[allow(non_snake_case, clippy::arithmetic_side_effects)] fn GetSystemTimeAsFileTime( &mut self, + shim_name: &str, LPFILETIME_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.assert_target_os("windows", "GetSystemTimeAsFileTime"); - this.check_no_isolation("`GetSystemTimeAsFileTime`")?; + this.assert_target_os("windows", shim_name); + this.check_no_isolation(shim_name)?; let filetime = this.deref_pointer_as(LPFILETIME_op, this.windows_ty_layout("FILETIME"))?; diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index fdd7fc5fad4e8..15ddd8a584699 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -246,11 +246,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } // Time related shims - "GetSystemTimeAsFileTime" => { + "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => { #[allow(non_snake_case)] let [LPFILETIME] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.GetSystemTimeAsFileTime(LPFILETIME)?; + this.GetSystemTimeAsFileTime(link_name.as_str(), LPFILETIME)?; } "QueryPerformanceCounter" => { #[allow(non_snake_case)] From f030d49536cf821a062ecc48497e027f7dbf2767 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 23 Feb 2024 11:53:25 +0000 Subject: [PATCH 04/14] Expose `Freeze` trait again --- library/core/src/marker.rs | 10 ++++++++-- .../auto-trait-bounds-by-associated-type-50159.rs | 9 ++++++--- tests/rustdoc/empty-section.rs | 4 ++-- tests/rustdoc/synthetic_auto/basic.rs | 2 +- tests/rustdoc/synthetic_auto/manual.rs | 2 +- tests/ui/associated-consts/freeze.rs | 12 ++++++++++++ 6 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 tests/ui/associated-consts/freeze.rs diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 2e22129d7b64d..c5cacd12f7014 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -810,15 +810,21 @@ pub trait DiscriminantKind { type Discriminant: Clone + Copy + Debug + Eq + PartialEq + Hash + Send + Sync + Unpin; } -/// Compiler-internal trait used to determine whether a type contains +/// Used to determine whether a type contains /// any `UnsafeCell` internally, but not through an indirection. /// This affects, for example, whether a `static` of that type is /// placed in read-only static memory or writable static memory. +/// This can be used to declare that a constant with a generic type +/// will not contain interior mutability, and subsequently allow +/// placing the constant behind references. #[lang = "freeze"] -pub(crate) unsafe auto trait Freeze {} +#[unstable(feature = "freeze", issue = "60715")] +pub unsafe auto trait Freeze {} +#[unstable(feature = "freeze", issue = "60715")] impl !Freeze for UnsafeCell {} marker_impls! { + #[unstable(feature = "freeze", issue = "60715")] unsafe Freeze for {T: ?Sized} PhantomData, {T: ?Sized} *const T, diff --git a/tests/rustdoc/auto-trait-bounds-by-associated-type-50159.rs b/tests/rustdoc/auto-trait-bounds-by-associated-type-50159.rs index 0663ed5fc81ff..7d9133b85a613 100644 --- a/tests/rustdoc/auto-trait-bounds-by-associated-type-50159.rs +++ b/tests/rustdoc/auto-trait-bounds-by-associated-type-50159.rs @@ -1,5 +1,5 @@ // https://github.com/rust-lang/rust/issues/50159 -#![crate_name="foo"] +#![crate_name = "foo"] pub trait Signal { type Item; @@ -9,7 +9,10 @@ pub trait Signal2 { type Item2; } -impl Signal2 for B where B: Signal { +impl Signal2 for B +where + B: Signal, +{ type Item2 = C; } @@ -17,7 +20,7 @@ impl Signal2 for B where B: Signal { // @has - '//h3[@class="code-header"]' 'impl Send for Switchwhere ::Item: Send' // @has - '//h3[@class="code-header"]' 'impl Sync for Switchwhere ::Item: Sync' // @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 6 pub struct Switch { pub inner: ::Item2, } diff --git a/tests/rustdoc/empty-section.rs b/tests/rustdoc/empty-section.rs index d8241ab96f6dd..0d6afb0e44447 100644 --- a/tests/rustdoc/empty-section.rs +++ b/tests/rustdoc/empty-section.rs @@ -1,6 +1,5 @@ #![crate_name = "foo"] - -#![feature(negative_impls)] +#![feature(negative_impls, freeze_impls, freeze)] pub struct Foo; @@ -8,6 +7,7 @@ pub struct Foo; // @!hasraw - 'Auto Trait Implementations' impl !Send for Foo {} impl !Sync for Foo {} +impl !std::marker::Freeze for Foo {} impl !std::marker::Unpin for Foo {} impl !std::panic::RefUnwindSafe for Foo {} impl !std::panic::UnwindSafe for Foo {} diff --git a/tests/rustdoc/synthetic_auto/basic.rs b/tests/rustdoc/synthetic_auto/basic.rs index 043ac24148838..16b8cce490c84 100644 --- a/tests/rustdoc/synthetic_auto/basic.rs +++ b/tests/rustdoc/synthetic_auto/basic.rs @@ -2,7 +2,7 @@ // @has - '//h3[@class="code-header"]' 'impl Send for Foowhere T: Send' // @has - '//h3[@class="code-header"]' 'impl Sync for Foowhere T: Sync' // @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 6 pub struct Foo { field: T, } diff --git a/tests/rustdoc/synthetic_auto/manual.rs b/tests/rustdoc/synthetic_auto/manual.rs index 7fc8447df3efc..692d68294a7ef 100644 --- a/tests/rustdoc/synthetic_auto/manual.rs +++ b/tests/rustdoc/synthetic_auto/manual.rs @@ -6,7 +6,7 @@ // 'impl Send for Foo' // // @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5 pub struct Foo { field: T, } diff --git a/tests/ui/associated-consts/freeze.rs b/tests/ui/associated-consts/freeze.rs new file mode 100644 index 0000000000000..2364ee1f4956f --- /dev/null +++ b/tests/ui/associated-consts/freeze.rs @@ -0,0 +1,12 @@ +#![feature(freeze)] + +//@ check-pass + +use std::marker::Freeze; + +trait Trait { + const VALUE: T; + const VALUE_REF: &'static T = &Self::VALUE; +} + +fn main() {} From 78492307406520214f24ce2519f3891f0048bf8e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 23 Feb 2024 12:11:11 +0000 Subject: [PATCH 05/14] Forbid implementing `Freeze` even if the trait is stabilized --- .../example/mini_core.rs | 1 + .../rustc_codegen_gcc/example/mini_core.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 2 ++ .../rustc_hir_analysis/src/coherence/mod.rs | 14 +++++++++++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/lib.rs | 1 + library/core/src/marker.rs | 6 ++--- .../min-global-align/min_global_align.rs | 2 +- .../feature-gate-freeze-impls.rs | 15 ++++++++++++ .../feature-gate-freeze-impls.stderr | 23 +++++++++++++++++++ 10 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-freeze-impls.rs create mode 100644 tests/ui/feature-gates/feature-gate-freeze-impls.stderr diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index a79909ce0c878..47db7ee369186 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -8,6 +8,7 @@ rustc_attrs, transparent_unions, auto_traits, + freeze_impls, thread_local )] #![no_core] diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index 230009741dc41..1f364f78ece76 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -1,6 +1,6 @@ #![feature( no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types, - decl_macro, rustc_attrs, transparent_unions, auto_traits, + decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls, thread_local )] #![no_core] diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 53254d567ccf2..db192ae9a3519 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -469,6 +469,8 @@ declare_features! ( (unstable, fn_align, "1.53.0", Some(82232)), /// Support delegating implementation of functions to other already implemented functions. (incomplete, fn_delegation, "1.76.0", Some(118212)), + /// Allows impls for the Freeze trait. + (internal, freeze_impls, "CURRENT_RUSTC_VERSION", Some(121675)), /// Allows defining gen blocks and `gen fn`. (unstable, gen_blocks, "1.75.0", Some(117078)), /// Infer generic args for both consts and types. diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index d6281fa08f745..52acc10b9fe7f 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -10,6 +10,7 @@ use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; +use rustc_session::parse::feature_err; use rustc_span::{sym, ErrorGuaranteed}; use rustc_trait_selection::traits; @@ -49,6 +50,19 @@ fn enforce_trait_manually_implementable( ) -> Result<(), ErrorGuaranteed> { let impl_header_span = tcx.def_span(impl_def_id); + if tcx.lang_items().freeze_trait() == Some(trait_def_id) { + if !tcx.features().freeze_impls { + feature_err( + &tcx.sess, + sym::freeze_impls, + impl_header_span, + "explicit impls for the `Freeze` trait are not permitted", + ) + .with_span_label(impl_header_span, format!("impl of `Freeze` not allowed")) + .emit(); + } + } + // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]` if trait_def.deny_explicit_impl { let trait_name = tcx.item_name(trait_def_id); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4d8475bef54c8..f52f187973fa0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -841,6 +841,7 @@ symbols! { format_placeholder, format_unsafe_arg, freeze, + freeze_impls, freg, frem_algebraic, frem_fast, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 7b735d48bdfce..6ea7fda15389d 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -203,6 +203,7 @@ // Language features: // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(platform_intrinsics))] +#![cfg_attr(not(bootstrap), feature(freeze_impls))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index c5cacd12f7014..a56a2578c2241 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -818,13 +818,13 @@ pub trait DiscriminantKind { /// will not contain interior mutability, and subsequently allow /// placing the constant behind references. #[lang = "freeze"] -#[unstable(feature = "freeze", issue = "60715")] +#[unstable(feature = "freeze", issue = "121675")] pub unsafe auto trait Freeze {} -#[unstable(feature = "freeze", issue = "60715")] +#[unstable(feature = "freeze", issue = "121675")] impl !Freeze for UnsafeCell {} marker_impls! { - #[unstable(feature = "freeze", issue = "60715")] + #[unstable(feature = "freeze", issue = "121675")] unsafe Freeze for {T: ?Sized} PhantomData, {T: ?Sized} *const T, diff --git a/tests/run-make/min-global-align/min_global_align.rs b/tests/run-make/min-global-align/min_global_align.rs index 135792e937205..cd1ef8cb351ff 100644 --- a/tests/run-make/min-global-align/min_global_align.rs +++ b/tests/run-make/min-global-align/min_global_align.rs @@ -1,4 +1,4 @@ -#![feature(no_core, lang_items)] +#![feature(no_core, lang_items, freeze_impls)] #![crate_type = "rlib"] #![no_core] diff --git a/tests/ui/feature-gates/feature-gate-freeze-impls.rs b/tests/ui/feature-gates/feature-gate-freeze-impls.rs new file mode 100644 index 0000000000000..c14c9494874a2 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-freeze-impls.rs @@ -0,0 +1,15 @@ +#![feature(freeze, negative_impls)] + +use std::marker::Freeze; + +struct Foo; + +unsafe impl Freeze for Foo {} +//~^ explicit impls for the `Freeze` trait are not permitted + +struct Bar; + +impl !Freeze for Bar {} +//~^ explicit impls for the `Freeze` trait are not permitted + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-freeze-impls.stderr b/tests/ui/feature-gates/feature-gate-freeze-impls.stderr new file mode 100644 index 0000000000000..eef524fe78e8b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-freeze-impls.stderr @@ -0,0 +1,23 @@ +error[E0658]: explicit impls for the `Freeze` trait are not permitted + --> $DIR/feature-gate-freeze-impls.rs:7:1 + | +LL | unsafe impl Freeze for Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Freeze` not allowed + | + = note: see issue #121675 for more information + = help: add `#![feature(freeze_impls)]` 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]: explicit impls for the `Freeze` trait are not permitted + --> $DIR/feature-gate-freeze-impls.rs:12:1 + | +LL | impl !Freeze for Bar {} + | ^^^^^^^^^^^^^^^^^^^^ impl of `Freeze` not allowed + | + = note: see issue #121675 for more information + = help: add `#![feature(freeze_impls)]` 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 2 previous errors + +For more information about this error, try `rustc --explain E0658`. From 7ff3bade73b3507b49ad2771b0dd2650e7c08d57 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 4 Mar 2024 22:31:28 +0000 Subject: [PATCH 06/14] std::threads: revisit stack address calculation on netbsd. like older linux glibc versions, we need to get the guard size and increasing the stack's bottom address accordingly. --- library/std/src/sys/pal/unix/thread.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 2af6382f3daee..8c9167ee9eb28 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -803,12 +803,30 @@ pub mod guard { Some(stack_ptr.with_addr(stackaddr)) } + #[cfg(target_os = "netbsd")] + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + let mut ret = None; + let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); + let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr); + if e == 0 { + let mut stackaddr = crate::ptr::null_mut(); + let mut stacksize = 0; + let mut guardsize = 0; + assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); + // on netbsd, we need to take in account the guard size to push up + // the stack's address from the bottom. + assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0); + stackaddr = stackaddr.add(guardsize); + ret = Some(stackaddr); + } + ret + } + #[cfg(any( target_os = "android", target_os = "freebsd", target_os = "hurd", target_os = "linux", - target_os = "netbsd", target_os = "l4re" ))] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { @@ -911,9 +929,10 @@ pub mod guard { } }) * page_size; Some(guard) - } else if cfg!(target_os = "openbsd") { + } else if cfg!(any(target_os = "openbsd", target_os = "netbsd")) { // OpenBSD stack already includes a guard page, and stack is // immutable. + // NetBSD stack includes the guard page. // // We'll just note where we expect rlimit to start // faulting, so our handler can report "stack overflow", and From dd95cb7106e60a79a994899aa4836d6dc8b5b9fa Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 6 Mar 2024 12:10:52 -0800 Subject: [PATCH 07/14] Add `target.*.runner` configuration for targets This commit adds a `runner` field configuration to `config.toml` for specifying a wrapper executable when executing binaries for a target. This is pulled out of #122036 where a WebAssembly runtime is used, for example, to execute tests for `wasm32-wasip1`. The name "runner" here is chosen to match Cargo's `CARGO_*_RUNNER` configuration, and to make things a bit more consistent this additionally renames compiletest's `--runtool` argument to `--runner`. --- config.example.toml | 11 +++++++++++ src/bootstrap/src/core/build_steps/test.rs | 4 ++++ src/bootstrap/src/core/config/config.rs | 3 +++ src/bootstrap/src/lib.rs | 11 +++++++++++ src/tools/compiletest/src/common.rs | 6 ++++-- src/tools/compiletest/src/lib.rs | 6 +++--- src/tools/compiletest/src/runtest.rs | 4 ++-- 7 files changed, 38 insertions(+), 7 deletions(-) diff --git a/config.example.toml b/config.example.toml index c1939933850c4..4fbdccba91104 100644 --- a/config.example.toml +++ b/config.example.toml @@ -842,6 +842,17 @@ # See that option for more info. #codegen-backends = rust.codegen-backends (array) +# This is a "runner" to pass to `compiletest` when executing tests. Tests will +# execute this tool where the binary-to-test is passed as an argument. Can +# be useful for situations such as when WebAssembly is being tested and a +# runtime needs to be configured. This value is similar to +# Cargo's `CARGO_$target_RUNNER` configuration. +# +# This configuration is a space-separated list of arguments so `foo bar` would +# execute the program `foo` with the first argument as `bar` and the second +# argument as the test binary. +#runner = (string) + # ============================================================================= # Distribution options # diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 4a4497e57db14..ed9f8db38041e 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1970,6 +1970,8 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the if builder.remote_tested(target) { cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient)); + } else if let Some(tool) = builder.runner(target) { + cmd.arg("--runner").arg(tool); } if suite != "mir-opt" { @@ -2519,6 +2521,8 @@ fn prepare_cargo_test( format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()), ); + } else if let Some(tool) = builder.runner(target) { + cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), tool); } cargo diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 326f8f57173a1..c1988851738dc 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -579,6 +579,7 @@ pub struct Target { pub musl_libdir: Option, pub wasi_root: Option, pub qemu_rootfs: Option, + pub runner: Option, pub no_std: bool, pub codegen_backends: Option>>, } @@ -1142,6 +1143,7 @@ define_config! { qemu_rootfs: Option = "qemu-rootfs", no_std: Option = "no-std", codegen_backends: Option> = "codegen-backends", + runner: Option = "runner", } } @@ -1862,6 +1864,7 @@ impl Config { target.musl_libdir = cfg.musl_libdir.map(PathBuf::from); target.wasi_root = cfg.wasi_root.map(PathBuf::from); target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from); + target.runner = cfg.runner; target.sanitizers = cfg.sanitizers; target.profiler = cfg.profiler; target.rpath = cfg.rpath; diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index ab8f3c0d9e497..181df93b6954c 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1353,6 +1353,17 @@ impl Build { || env::var_os("TEST_DEVICE_ADDR").is_some() } + /// Returns an optional "runner" to pass to `compiletest` when executing + /// test binaries. + /// + /// An example of this would be a WebAssembly runtime when testing the wasm + /// targets. + fn runner(&self, target: TargetSelection) -> Option { + let target = self.config.target_config.get(&target)?; + let runner = target.runner.as_ref()?; + Some(runner.to_owned()) + } + /// Returns the root of the "rootfs" image that this target will be using, /// if one was configured. /// diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 06d8f099c33fa..78246136f2a1b 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -266,8 +266,10 @@ pub struct Config { pub logfile: Option, /// A command line to prefix program execution with, - /// for running under valgrind - pub runtool: Option, + /// for running under valgrind for example. + /// + /// Similar to `CARGO_*_RUNNER` configuration. + pub runner: Option, /// Flags to pass to the compiler when building for the host pub host_rustcflags: Vec, diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index b32a5a4bf1a4a..ef02e7fcb4abb 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -86,7 +86,7 @@ pub fn parse_config(args: Vec) -> Config { .optflag("", "exact", "filters match exactly") .optopt( "", - "runtool", + "runner", "supervisor program to run tests under \ (eg. emulator, valgrind)", "PROGRAM", @@ -256,7 +256,7 @@ pub fn parse_config(args: Vec) -> Config { _ => panic!("unknown `--run` option `{}` given", mode), }), logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)), - runtool: matches.opt_str("runtool"), + runner: matches.opt_str("runner"), host_rustcflags: matches.opt_strs("host-rustcflags"), target_rustcflags: matches.opt_strs("target-rustcflags"), optimize_tests: matches.opt_present("optimize-tests"), @@ -341,7 +341,7 @@ pub fn log_config(config: &Config) { c, format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),), ); - logv(c, format!("runtool: {}", opt_str(&config.runtool))); + 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)); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ae0db88d873be..9fd83c507edde 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -461,7 +461,7 @@ impl<'test> TestCx<'test> { } let mut new_config = self.config.clone(); - new_config.runtool = new_config.valgrind_path.clone(); + new_config.runner = new_config.valgrind_path.clone(); let new_cx = TestCx { config: &new_config, ..*self }; proc_res = new_cx.exec_compiled_test(); @@ -2647,7 +2647,7 @@ impl<'test> TestCx<'test> { fn make_run_args(&self) -> ProcArgs { // If we've got another tool to run under (valgrind), // then split apart its command - let mut args = self.split_maybe_args(&self.config.runtool); + let mut args = self.split_maybe_args(&self.config.runner); // If this is emscripten, then run tests under nodejs if self.config.target.contains("emscripten") { From 9bdb8a6888939c61c2907a5d37562833cf8d1ff3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 8 Mar 2024 07:43:35 -0800 Subject: [PATCH 08/14] Add a change entry --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index d166b84e51fc5..a348fa3584147 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -141,4 +141,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "A new `boostrap-cache-path` option has been introduced which can be utilized to modify the cache path for bootstrap.", }, + ChangeInfo { + change_id: 122108, + severity: ChangeSeverity::Info, + summary: "a new `target.*.runner` option is available to specify a wrapper executable required to run tests for a target", + }, ]; From ffdd97f79178f16c5306a84af933aa31f223ffb4 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 8 Mar 2024 21:54:03 +0000 Subject: [PATCH 09/14] further changes from feedback --- library/std/src/sys/pal/unix/thread.rs | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 8c9167ee9eb28..6520ca9fc48ef 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -803,28 +803,10 @@ pub mod guard { Some(stack_ptr.with_addr(stackaddr)) } - #[cfg(target_os = "netbsd")] - unsafe fn get_stack_start() -> Option<*mut libc::c_void> { - let mut ret = None; - let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); - let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr); - if e == 0 { - let mut stackaddr = crate::ptr::null_mut(); - let mut stacksize = 0; - let mut guardsize = 0; - assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); - // on netbsd, we need to take in account the guard size to push up - // the stack's address from the bottom. - assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0); - stackaddr = stackaddr.add(guardsize); - ret = Some(stackaddr); - } - ret - } - #[cfg(any( target_os = "android", target_os = "freebsd", + target_os = "netbsd", target_os = "hurd", target_os = "linux", target_os = "l4re" From e5e1fa610b4b6945903246b030d7d1cad2866afb Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 2 Mar 2024 20:34:38 +0300 Subject: [PATCH 10/14] skip sanity check for non-host targets in `check` builds For `check` builds, since we only need to perform a sanity check on the host target, this patch skips target sanity checks on non-host targets. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/sanity.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 1dce8d8ac7184..e03b1e179084e 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -15,6 +15,7 @@ use std::fs; use std::path::PathBuf; use std::process::Command; +use crate::builder::Kind; use crate::core::config::Target; use crate::utils::helpers::output; use crate::Build; @@ -64,6 +65,8 @@ pub fn check(build: &mut Build) { let mut skip_target_sanity = env::var_os("BOOTSTRAP_SKIP_TARGET_SANITY").is_some_and(|s| s == "1" || s == "true"); + skip_target_sanity |= build.config.cmd.kind() == Kind::Check; + // Skip target sanity checks when we are doing anything with mir-opt tests or Miri let skipped_paths = [OsStr::new("mir-opt"), OsStr::new("miri")]; skip_target_sanity |= build.config.paths.iter().any(|path| { @@ -169,11 +172,8 @@ than building it. continue; } - // Some environments don't want or need these tools, such as when testing Miri. - // FIXME: it would be better to refactor this code to split necessary setup from pure sanity - // checks, and have a regular flag for skipping the latter. Also see - // . - if skip_target_sanity { + // skip check for cross-targets + if skip_target_sanity && target != &build.build { continue; } @@ -215,11 +215,8 @@ than building it. panic!("All the *-none-* and nvptx* targets are no-std targets") } - // Some environments don't want or need these tools, such as when testing Miri. - // FIXME: it would be better to refactor this code to split necessary setup from pure sanity - // checks, and have a regular flag for skipping the latter. Also see - // . - if skip_target_sanity { + // skip check for cross-targets + if skip_target_sanity && target != &build.build { continue; } From 81ebaf27cb4301a833f5a4ba1f4a6e63cfcc32b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Mar 2024 17:12:27 +0100 Subject: [PATCH 11/14] RawVec::into_box: avoid unnecessary intermediate reference --- library/alloc/src/raw_vec.rs | 3 +-- tests/ui/hygiene/panic-location.rs | 1 + tests/ui/hygiene/panic-location.run.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index ace73c0fdaa5e..0ee293db73a93 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -5,7 +5,6 @@ use core::cmp; use core::hint; use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::ptr::{self, NonNull, Unique}; -use core::slice; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; @@ -192,7 +191,7 @@ impl RawVec { let me = ManuallyDrop::new(self); unsafe { - let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit, len); + let slice = ptr::slice_from_raw_parts_mut(me.ptr() as *mut MaybeUninit, len); Box::from_raw_in(slice, ptr::read(&me.alloc)) } } diff --git a/tests/ui/hygiene/panic-location.rs b/tests/ui/hygiene/panic-location.rs index a98960d74b019..b2f9bfe4f9a7a 100644 --- a/tests/ui/hygiene/panic-location.rs +++ b/tests/ui/hygiene/panic-location.rs @@ -1,6 +1,7 @@ //@ run-fail //@ check-run-results //@ exec-env:RUST_BACKTRACE=0 +//@ normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC" // // Regression test for issue #70963 // The captured stderr from this test reports a location diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr index ec0ce18c3dfa7..5c1778bc485f9 100644 --- a/tests/ui/hygiene/panic-location.run.stderr +++ b/tests/ui/hygiene/panic-location.run.stderr @@ -1,3 +1,3 @@ -thread 'main' panicked at library/alloc/src/raw_vec.rs:26:5: +thread 'main' panicked at library/alloc/src/raw_vec.rs:LL:CC: capacity overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From a7443f554215b76ef1f911b1d6d07b4b7ebbb23c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Mar 2024 18:04:03 +0100 Subject: [PATCH 12/14] test into_boxed_slice with custom allocator in Miri --- .../tests/pass/box-custom-alloc-aliasing.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs b/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs index 541e5f244db08..ada9cf4537547 100644 --- a/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs +++ b/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs @@ -92,6 +92,8 @@ unsafe impl Allocator for MyAllocator { } unsafe fn deallocate(&self, ptr: NonNull, _layout: Layout) { + // Make sure accesses via `self` don't disturb anything. + let _val = self.bins[0].top.get(); // Since manually finding the corresponding bin of `ptr` is very expensive, // doing pointer arithmetics is preferred. // But this means we access `top` via `ptr` rather than `self`! @@ -101,22 +103,30 @@ unsafe impl Allocator for MyAllocator { if self.thread_id == thread_id { unsafe { (*their_bin).push(ptr) }; } else { - todo!("Deallocating from another thread") + todo!("Deallocating from another thread"); } + // Make sure we can also still access this via `self` after the rest is done. + let _val = self.bins[0].top.get(); } } // Make sure to involve `Box` in allocating these, // as that's where `noalias` may come from. -fn v(t: T, a: A) -> Vec { +fn v1(t: T, a: A) -> Vec { (Box::new_in([t], a) as Box<[T], A>).into_vec() } +fn v2(t: T, a: A) -> Vec { + let v = v1(t, a); + // There was a bug in `into_boxed_slice` that caused aliasing issues, + // so round-trip through that as well. + v.into_boxed_slice().into_vec() +} fn main() { assert!(mem::size_of::() <= 128); // if it grows bigger, the trick to access the "header" no longer works let my_alloc = MyAllocator::new(); - let a = v(1usize, &my_alloc); - let b = v(2usize, &my_alloc); + let a = v1(1usize, &my_alloc); + let b = v2(2usize, &my_alloc); assert_eq!(a[0] + 1, b[0]); assert_eq!(addr_of!(a[0]).wrapping_add(1), addr_of!(b[0])); drop((a, b)); From 50760aa2b59b54fba474283e5c5c4e028ce4d9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 11 Mar 2024 05:43:12 +0100 Subject: [PATCH 13/14] Optimize `process_heap_alloc` --- library/std/src/sys/pal/windows/alloc.rs | 55 ++++++++++++++++-------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs index 270eca37b14d6..681d1a5efe932 100644 --- a/library/std/src/sys/pal/windows/alloc.rs +++ b/library/std/src/sys/pal/windows/alloc.rs @@ -6,6 +6,7 @@ use crate::ptr; use crate::sync::atomic::{AtomicPtr, Ordering}; use crate::sys::c; use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN}; +use core::mem::MaybeUninit; #[cfg(test)] mod tests; @@ -94,29 +95,30 @@ static HEAP: AtomicPtr = AtomicPtr::new(ptr::null_mut()); // a non-null handle returned by `GetProcessHeap`. #[inline] fn init_or_get_process_heap() -> c::HANDLE { - let heap = HEAP.load(Ordering::Relaxed); - if core::intrinsics::unlikely(heap.is_null()) { - // `HEAP` has not yet been successfully initialized - let heap = unsafe { GetProcessHeap() }; - if !heap.is_null() { - // SAFETY: No locking is needed because within the same process, - // successful calls to `GetProcessHeap` will always return the same value, even on different threads. - HEAP.store(heap, Ordering::Release); - - // SAFETY: `HEAP` contains a non-null handle returned by `GetProcessHeap` - heap - } else { - // Could not get the current process heap. - ptr::null_mut() - } - } else { + // `HEAP` has not yet been successfully initialized + let heap = unsafe { GetProcessHeap() }; + if !heap.is_null() { + // SAFETY: No locking is needed because within the same process, + // successful calls to `GetProcessHeap` will always return the same value, even on different threads. + HEAP.store(heap, Ordering::Release); + // SAFETY: `HEAP` contains a non-null handle returned by `GetProcessHeap` heap + } else { + // Could not get the current process heap. + ptr::null_mut() } } +/// This is outlined from `process_heap_alloc` so that `process_heap_alloc` +/// does not need any stack allocations. #[inline(never)] -fn process_heap_alloc(flags: c::DWORD, dwBytes: c::SIZE_T) -> c::LPVOID { +#[cold] +extern "C" fn process_heap_init_and_alloc( + _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc` + flags: c::DWORD, + dwBytes: c::SIZE_T, +) -> c::LPVOID { let heap = init_or_get_process_heap(); if core::intrinsics::unlikely(heap.is_null()) { return ptr::null_mut(); @@ -125,6 +127,21 @@ fn process_heap_alloc(flags: c::DWORD, dwBytes: c::SIZE_T) -> c::LPVOID { unsafe { HeapAlloc(heap, flags, dwBytes) } } +#[inline(never)] +fn process_heap_alloc( + _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc`, + flags: c::DWORD, + dwBytes: c::SIZE_T, +) -> c::LPVOID { + let heap = HEAP.load(Ordering::Relaxed); + if core::intrinsics::likely(!heap.is_null()) { + // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`. + unsafe { HeapAlloc(heap, flags, dwBytes) } + } else { + process_heap_init_and_alloc(MaybeUninit::uninit(), flags, dwBytes) + } +} + // Get a non-null handle to the default heap of the current process. // SAFETY: `HEAP` must have been successfully initialized. #[inline] @@ -148,12 +165,12 @@ unsafe fn allocate(layout: Layout, zeroed: bool) -> *mut u8 { if layout.align() <= MIN_ALIGN { // The returned pointer points to the start of an allocated block. - process_heap_alloc(flags, layout.size()) as *mut u8 + process_heap_alloc(MaybeUninit::uninit(), flags, layout.size()) as *mut u8 } else { // Allocate extra padding in order to be able to satisfy the alignment. let total = layout.align() + layout.size(); - let ptr = process_heap_alloc(flags, total) as *mut u8; + let ptr = process_heap_alloc(MaybeUninit::uninit(), flags, total) as *mut u8; if ptr.is_null() { // Allocation has failed. return ptr::null_mut(); From 47b4b8e8c5189228015ee645dfc65e9b73d2c19c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 11 Mar 2024 09:06:08 +1100 Subject: [PATCH 14/14] Allow multiple `impl Into<{D,Subd}iagMessage>` parameters in a function. The internal diagnostic lint currently only allows one, because that was all that occurred in practice. But rust-lang/rust-clippy/pull/12453 wants to introduce functions with more than one, and this limitation is getting in the way. --- compiler/rustc_lint/src/internal.rs | 17 +++++------------ tests/ui-fulldeps/internal-lints/diagnostics.rs | 10 ++++++++-- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 0872a8a20959f..153d91ce28cb0 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -409,9 +409,8 @@ impl LateLintPass<'_> for Diagnostics { } }; - // Does the callee have a `impl Into<{D,Subd}iagMessage>` parameter? (There should be at - // most one.) - let mut impl_into_diagnostic_message_param = None; + // Does the callee have one or more `impl Into<{D,Subd}iagMessage>` parameters? + let mut impl_into_diagnostic_message_params = vec![]; let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); let predicates = cx.tcx.predicates_of(def_id).instantiate_identity(cx.tcx).predicates; for (i, ¶m_ty) in fn_sig.inputs().iter().enumerate() { @@ -425,20 +424,14 @@ impl LateLintPass<'_> for Diagnostics { && let ty1 = trait_ref.args.type_at(1) && is_diag_message(ty1) { - if impl_into_diagnostic_message_param.is_some() { - cx.tcx.dcx().span_bug( - span, - "can't handle multiple `impl Into<{D,Sub}iagMessage>` params", - ); - } - impl_into_diagnostic_message_param = Some((i, p.name)); + impl_into_diagnostic_message_params.push((i, p.name)); } } } } // Is the callee interesting? - if !has_attr && impl_into_diagnostic_message_param.is_none() { + if !has_attr && impl_into_diagnostic_message_params.is_empty() { return; } @@ -481,7 +474,7 @@ impl LateLintPass<'_> for Diagnostics { // Calls to methods with an `impl Into<{D,Subd}iagMessage>` parameter must be passed an arg // with type `{D,Subd}iagMessage` or `impl Into<{D,Subd}iagMessage>`. Otherwise, emit an // `UNTRANSLATABLE_DIAGNOSTIC` lint. - if let Some((param_i, param_i_p_name)) = impl_into_diagnostic_message_param { + for (param_i, param_i_p_name) in impl_into_diagnostic_message_params { // Is the arg type `{Sub,D}iagMessage`or `impl Into<{Sub,D}iagMessage>`? let arg_ty = call_tys[param_i]; let is_translatable = is_diag_message(arg_ty) diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs index d443681d5db08..1d7417be58cc3 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.rs +++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs @@ -15,7 +15,7 @@ extern crate rustc_span; use rustc_errors::{ Diag, DiagCtxt, DiagInner, DiagMessage, Diagnostic, EmissionGuarantee, Level, LintDiagnostic, - SubdiagMessageOp, Subdiagnostic, + SubdiagMessageOp, SubdiagMessage, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -114,9 +114,15 @@ pub fn make_diagnostics<'a>(dcx: &'a DiagCtxt) { // Check that `rustc_lint_diagnostics`-annotated functions aren't themselves linted for // `diagnostic_outside_of_impl`. - #[rustc_lint_diagnostics] pub fn skipped_because_of_annotation<'a>(dcx: &'a DiagCtxt) { #[allow(rustc::untranslatable_diagnostic)] let _diag = dcx.struct_err("untranslatable diagnostic"); // okay! } + +// Check that multiple translatable params are allowed in a single function (at one point they +// weren't). +fn f(_x: impl Into, _y: impl Into) {} +fn g() { + f(crate::fluent_generated::no_crate_example, crate::fluent_generated::no_crate_example); +}