From 06658ab84bbd4f835830808f78eb117d8f57efa0 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 24 Nov 2025 12:17:11 +0100 Subject: [PATCH 01/12] cmse: do not calculate the layout of a type with infer types --- .../src/hir_ty_lowering/cmse.rs | 10 ++++++ tests/crashes/130104.rs | 6 ---- .../cmse-nonsecure-call/infer.rs | 34 ++++++++++++++++++ .../cmse-nonsecure-call/infer.stderr | 27 ++++++++++++++ .../cmse-nonsecure-entry/infer.rs | 36 +++++++++++++++++++ .../cmse-nonsecure-entry/infer.stderr | 32 +++++++++++++++++ 6 files changed, 139 insertions(+), 6 deletions(-) delete mode 100644 tests/crashes/130104.rs create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.rs create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.stderr create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.rs create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index f8af6888923ce..81bdfc1705a1c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -86,6 +86,11 @@ fn is_valid_cmse_inputs<'tcx>( let fn_sig = tcx.erase_and_anonymize_regions(fn_sig); for (ty, hir_ty) in fn_sig.inputs().iter().zip(fn_decl.inputs) { + if ty.has_infer_types() { + let err = LayoutError::Unknown(*ty); + return Err((hir_ty.span, tcx.arena.alloc(err))); + } + let layout = tcx .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty)) .map_err(|e| (hir_ty.span, e))?; @@ -138,6 +143,11 @@ fn is_valid_cmse_output<'tcx>( return Ok(()); } + if return_type.has_infer_types() { + let err = LayoutError::Unknown(return_type); + return Err(tcx.arena.alloc(err)); + } + let typing_env = ty::TypingEnv::fully_monomorphized(); let layout = tcx.layout_of(typing_env.as_query_input(return_type))?; diff --git a/tests/crashes/130104.rs b/tests/crashes/130104.rs deleted file mode 100644 index b961108c92330..0000000000000 --- a/tests/crashes/130104.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: rust-lang/rust#130104 - -fn main() { - let non_secure_function = - core::mem::transmute:: _, extern "cmse-nonsecure-call" fn() -> _>; -} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.rs new file mode 100644 index 0000000000000..3452dc268e59b --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.rs @@ -0,0 +1,34 @@ +//@ add-minicore +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ needs-llvm-components: arm +#![feature(abi_cmse_nonsecure_call, no_core, lang_items)] +#![no_core] + +// Infer variables cause panics in layout generation, so the argument/return type is checked for +// whether it contains an infer var, and `LayoutError::Unknown` is emitted if so. +// +// See https://github.com/rust-lang/rust/issues/130104. + +extern crate minicore; +use minicore::*; + +fn infer_1() { + let _ = mem::transmute:: _, extern "cmse-nonsecure-call" fn() -> _>; + //~^ ERROR type annotations needed +} + +fn infer_2() { + let _ = mem::transmute:: (i32, _), extern "cmse-nonsecure-call" fn() -> (i32, _)>; + //~^ ERROR type annotations needed +} + +fn infer_3() { + let _ = mem::transmute:: (), extern "cmse-nonsecure-call" fn(_: _) -> ()>; + //~^ ERROR type annotations needed +} + +fn infer_4() { + let _ = + mem::transmute:: (), extern "cmse-nonsecure-call" fn(_: (i32, _)) -> ()>; + //~^ ERROR type annotations needed +} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.stderr new file mode 100644 index 0000000000000..aab314c1ff25a --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/infer.stderr @@ -0,0 +1,27 @@ +error[E0282]: type annotations needed + --> $DIR/infer.rs:16:13 + | +LL | let _ = mem::transmute:: _, extern "cmse-nonsecure-call" fn() -> _>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error[E0282]: type annotations needed + --> $DIR/infer.rs:21:13 + | +LL | let _ = mem::transmute:: (i32, _), extern "cmse-nonsecure-call" fn() -> (i32, _)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error[E0282]: type annotations needed + --> $DIR/infer.rs:26:13 + | +LL | let _ = mem::transmute:: (), extern "cmse-nonsecure-call" fn(_: _) -> ()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error[E0282]: type annotations needed + --> $DIR/infer.rs:32:9 + | +LL | mem::transmute:: (), extern "cmse-nonsecure-call" fn(_: (i32, _)) -> ()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.rs new file mode 100644 index 0000000000000..75a08ff403560 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.rs @@ -0,0 +1,36 @@ +//@ add-minicore +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ needs-llvm-components: arm +#![feature(cmse_nonsecure_entry, no_core, lang_items)] +#![no_core] + +// Infer variables cause panics in layout generation, so the argument/return type is checked for +// whether it contains an infer var, and `LayoutError::Unknown` is emitted if so. +// +// See https://github.com/rust-lang/rust/issues/130104. + +extern crate minicore; +use minicore::*; + +fn infer_1() { + let _ = mem::transmute:: _, extern "cmse-nonsecure-entry" fn() -> _>; + //~^ ERROR type annotations needed +} + +fn infer_2() { + let _ = mem::transmute:: (i32, _), extern "cmse-nonsecure-entry" fn() -> (i32, _)>; + //~^ ERROR type annotations needed +} + +fn infer_3() { + let _ = mem::transmute:: (), extern "cmse-nonsecure-entry" fn(_: _) -> ()>; + //~^ ERROR type annotations needed +} + +fn infer_4() { + let _ = mem::transmute::< + //~^ ERROR type annotations needed + fn(_: (i32, _)) -> (), + extern "cmse-nonsecure-entry" fn(_: (i32, _)) -> (), + >; +} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.stderr new file mode 100644 index 0000000000000..4243771c3e674 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/infer.stderr @@ -0,0 +1,32 @@ +error[E0282]: type annotations needed + --> $DIR/infer.rs:16:13 + | +LL | let _ = mem::transmute:: _, extern "cmse-nonsecure-entry" fn() -> _>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error[E0282]: type annotations needed + --> $DIR/infer.rs:21:13 + | +LL | let _ = mem::transmute:: (i32, _), extern "cmse-nonsecure-entry" fn() -> (i32, _)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error[E0282]: type annotations needed + --> $DIR/infer.rs:26:13 + | +LL | let _ = mem::transmute:: (), extern "cmse-nonsecure-entry" fn(_: _) -> ()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error[E0282]: type annotations needed + --> $DIR/infer.rs:31:13 + | +LL | let _ = mem::transmute::< + | _____________^ +LL | | +LL | | fn(_: (i32, _)) -> (), +LL | | extern "cmse-nonsecure-entry" fn(_: (i32, _)) -> (), +LL | | >; + | |_____^ cannot infer type of the type parameter `Src` declared on the function `transmute` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0282`. From 67094fc00a5a1eb5f530d605cfb73adc9f2079ef Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 26 Nov 2025 11:19:52 -0600 Subject: [PATCH 02/12] test(frontmatter): Check handling of long code fences --- tests/ui/frontmatter/fence-too-many-dashes.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/ui/frontmatter/fence-too-many-dashes.rs diff --git a/tests/ui/frontmatter/fence-too-many-dashes.rs b/tests/ui/frontmatter/fence-too-many-dashes.rs new file mode 100644 index 0000000000000..2246a14044fc6 --- /dev/null +++ b/tests/ui/frontmatter/fence-too-many-dashes.rs @@ -0,0 +1,12 @@ +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +// ignore-tidy-linelength +[dependencies] +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +#![feature(frontmatter)] + +//@ check-pass + +// check that we limit fence lengths + +fn main() {} From 70b6d779834becf483fd5186b6f9edb54f16bcf9 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 26 Nov 2025 14:01:22 -0600 Subject: [PATCH 03/12] fix(parse): Limit frontmatter fences to 255 dashes Like raw string literals. --- compiler/rustc_parse/messages.ftl | 1 + compiler/rustc_parse/src/errors.rs | 6 ++++++ compiler/rustc_parse/src/lexer/mod.rs | 5 +++++ tests/ui/frontmatter/fence-too-many-dashes.rs | 3 +-- tests/ui/frontmatter/fence-too-many-dashes.stderr | 4 ++++ 5 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tests/ui/frontmatter/fence-too-many-dashes.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 7055e60956a9c..8a556a73dbd0b 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -347,6 +347,7 @@ parse_frontmatter_invalid_opening_preceding_whitespace = invalid preceding white parse_frontmatter_length_mismatch = frontmatter close does not match the opening .label_opening = the opening here has {$len_opening} dashes... .label_close = ...while the close has {$len_close} dashes +parse_frontmatter_too_many_dashes = too many `-` symbols: frontmatter openings may be delimited by up to 255 `-` symbols, but found {$len_opening} parse_frontmatter_unclosed = unclosed frontmatter .note = frontmatter opening here was not closed diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 62a333fbf81d7..b0236c3538cc2 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -822,6 +822,12 @@ pub(crate) struct FrontmatterLengthMismatch { pub len_close: usize, } +#[derive(Diagnostic)] +#[diag(parse_frontmatter_too_many_dashes)] +pub(crate) struct FrontmatterTooManyDashes { + pub len_opening: usize, +} + #[derive(Diagnostic)] #[diag(parse_leading_plus_not_supported)] pub(crate) struct LeadingPlusNotSupported { diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 51019db7c00e4..c62c8acced700 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -665,6 +665,11 @@ impl<'psess, 'src> Lexer<'psess, 'src> { }); } + // Only up to 255 `-`s are allowed in code fences + if u8::try_from(len_opening).is_err() { + self.dcx().emit_err(errors::FrontmatterTooManyDashes { len_opening }); + } + if !rest.trim_matches(is_horizontal_whitespace).is_empty() { let span = self.mk_sp(last_line_start_pos, self.pos); self.dcx().emit_err(errors::FrontmatterExtraCharactersAfterClose { span }); diff --git a/tests/ui/frontmatter/fence-too-many-dashes.rs b/tests/ui/frontmatter/fence-too-many-dashes.rs index 2246a14044fc6..abb64748d3d02 100644 --- a/tests/ui/frontmatter/fence-too-many-dashes.rs +++ b/tests/ui/frontmatter/fence-too-many-dashes.rs @@ -1,12 +1,11 @@ ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//~? ERROR: too many `-` symbols: frontmatter openings may be delimited by up to 255 `-` symbols // ignore-tidy-linelength [dependencies] ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- #![feature(frontmatter)] -//@ check-pass - // check that we limit fence lengths fn main() {} diff --git a/tests/ui/frontmatter/fence-too-many-dashes.stderr b/tests/ui/frontmatter/fence-too-many-dashes.stderr new file mode 100644 index 0000000000000..09ed9ffa7a421 --- /dev/null +++ b/tests/ui/frontmatter/fence-too-many-dashes.stderr @@ -0,0 +1,4 @@ +error: too many `-` symbols: frontmatter openings may be delimited by up to 255 `-` symbols, but found 256 + +error: aborting due to 1 previous error + From daccd994e5270dd927d5ab295f37511140ef9938 Mon Sep 17 00:00:00 2001 From: bendn Date: Thu, 20 Nov 2025 00:04:50 +0700 Subject: [PATCH 04/12] stabilize maybe_uninit_slice --- library/core/src/mem/maybe_uninit.rs | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index aee28c4590c29..d07115219f8a9 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1097,20 +1097,6 @@ impl MaybeUninit { ) } } - - /// Gets a pointer to the first element of the array. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[inline(always)] - pub const fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { - this.as_ptr() as *const T - } - - /// Gets a mutable pointer to the first element of the array. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[inline(always)] - pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { - this.as_mut_ptr() as *mut T - } } impl [MaybeUninit] { @@ -1477,7 +1463,7 @@ impl [MaybeUninit] { /// requirement the compiler knows about it is that the data pointer must be /// non-null. Dropping such a `Vec` however will cause undefined /// behaviour. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] #[inline(always)] #[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")] pub const unsafe fn assume_init_drop(&mut self) @@ -1499,7 +1485,8 @@ impl [MaybeUninit] { /// Calling this when the content is not yet fully initialized causes undefined /// behavior: it is up to the caller to guarantee that every `MaybeUninit` in /// the slice really is in an initialized state. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] #[inline(always)] pub const unsafe fn assume_init_ref(&self) -> &[T] { // SAFETY: casting `slice` to a `*const [T]` is safe since the caller guarantees that @@ -1517,7 +1504,8 @@ impl [MaybeUninit] { /// behavior: it is up to the caller to guarantee that every `MaybeUninit` in the /// slice really is in an initialized state. For instance, `.assume_init_mut()` cannot /// be used to initialize a `MaybeUninit` slice. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "maybe_uninit_slice", since = "CURRENT_RUSTC_VERSION")] #[inline(always)] pub const unsafe fn assume_init_mut(&mut self) -> &mut [T] { // SAFETY: similar to safety notes for `slice_get_ref`, but we have a From d67f99af2e9851c1d2ce565db848180d03e782b5 Mon Sep 17 00:00:00 2001 From: bendn Date: Thu, 20 Nov 2025 00:40:52 +0700 Subject: [PATCH 05/12] fix --- compiler/rustc_arena/src/lib.rs | 2 +- library/alloc/src/lib.rs | 1 - library/alloctests/lib.rs | 1 - library/core/src/clone/uninit.rs | 8 +------- library/core/src/mem/maybe_uninit.rs | 6 +++--- library/core/src/slice/sort/stable/merge.rs | 2 +- library/core/src/slice/sort/stable/quicksort.rs | 2 +- library/std/src/lib.rs | 1 - library/std/tests/path.rs | 1 - 9 files changed, 7 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index a821d9e7fa23e..5151c358774ed 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -10,13 +10,13 @@ // tidy-alphabetical-start #![allow(clippy::mut_from_ref)] // Arena allocators are one place where this pattern is fine. #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(maybe_uninit_slice))] #![cfg_attr(test, feature(test))] #![deny(unsafe_op_in_unsafe_fn)] #![doc(test(no_crate_inject, attr(deny(warnings), allow(internal_features))))] #![feature(core_intrinsics)] #![feature(decl_macro)] #![feature(dropck_eyepatch)] -#![feature(maybe_uninit_slice)] #![feature(never_type)] #![feature(rustc_attrs)] #![feature(unwrap_infallible)] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3f391fe2c1de8..bf73deb0e8372 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -127,7 +127,6 @@ #![feature(layout_for_ptr)] #![feature(legacy_receiver_trait)] #![feature(local_waker)] -#![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(panic_internals)] #![feature(pattern)] diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index 73c25679d05ba..f6c7105ea2801 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -28,7 +28,6 @@ #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] -#![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(ptr_alignment_type)] #![feature(ptr_internals)] diff --git a/library/core/src/clone/uninit.rs b/library/core/src/clone/uninit.rs index 8d1185067eb88..b6e351fc7c96c 100644 --- a/library/core/src/clone/uninit.rs +++ b/library/core/src/clone/uninit.rs @@ -114,16 +114,10 @@ impl<'a, T> InitializingSlice<'a, T> { impl<'a, T> Drop for InitializingSlice<'a, T> { #[cold] // will only be invoked on unwind fn drop(&mut self) { - let initialized_slice = ptr::slice_from_raw_parts_mut( - MaybeUninit::slice_as_mut_ptr(self.data), - self.initialized_len, - ); // SAFETY: // * the pointer is valid because it was made from a mutable reference // * `initialized_len` counts the initialized elements as an invariant of this type, // so each of the pointed-to elements is initialized and may be dropped. - unsafe { - ptr::drop_in_place::<[T]>(initialized_slice); - } + unsafe { self.data[..self.initialized_len].assume_init_drop() }; } } diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index d07115219f8a9..e00cf45fcab20 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1047,7 +1047,7 @@ impl MaybeUninit { /// # Examples /// /// ``` - /// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)] + /// #![feature(maybe_uninit_as_bytes)] /// use std::mem::MaybeUninit; /// /// let val = 0x12345678_i32; @@ -1396,7 +1396,7 @@ impl [MaybeUninit] { /// # Examples /// /// ``` - /// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)] + /// #![feature(maybe_uninit_as_bytes)] /// use std::mem::MaybeUninit; /// /// let uninit = [MaybeUninit::new(0x1234u16), MaybeUninit::new(0x5678u16)]; @@ -1423,7 +1423,7 @@ impl [MaybeUninit] { /// # Examples /// /// ``` - /// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)] + /// #![feature(maybe_uninit_as_bytes)] /// use std::mem::MaybeUninit; /// /// let mut uninit = [MaybeUninit::::uninit(), MaybeUninit::::uninit()]; diff --git a/library/core/src/slice/sort/stable/merge.rs b/library/core/src/slice/sort/stable/merge.rs index bb2747bfc78ac..26d8480b7f71f 100644 --- a/library/core/src/slice/sort/stable/merge.rs +++ b/library/core/src/slice/sort/stable/merge.rs @@ -35,7 +35,7 @@ pub fn merge bool>( // 1. Protects integrity of `v` from panics in `is_less`. // 2. Fills the remaining gap in `v` if the longer run gets consumed first. - let buf = MaybeUninit::slice_as_mut_ptr(scratch); + let buf = scratch.as_mut_ptr().cast_init(); let v_base = v.as_mut_ptr(); let v_mid = v_base.add(mid); diff --git a/library/core/src/slice/sort/stable/quicksort.rs b/library/core/src/slice/sort/stable/quicksort.rs index 0439ba870bd2b..734a495ce225b 100644 --- a/library/core/src/slice/sort/stable/quicksort.rs +++ b/library/core/src/slice/sort/stable/quicksort.rs @@ -97,7 +97,7 @@ fn stable_partition bool>( } let v_base = v.as_ptr(); - let scratch_base = MaybeUninit::slice_as_mut_ptr(scratch); + let scratch_base = scratch.as_mut_ptr().cast_init(); // The core idea is to write the values that compare as less-than to the left // side of `scratch`, while the values that compared as greater or equal than diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 8df87124245bc..21d09d00c15e2 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -348,7 +348,6 @@ #![feature(ip)] #![feature(lazy_get)] #![feature(maybe_uninit_array_assume_init)] -#![feature(maybe_uninit_slice)] #![feature(panic_can_unwind)] #![feature(panic_internals)] #![feature(pin_coerce_unsized_trait)] diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index c60edbdf961e1..4094b7acd8749 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![feature(clone_to_uninit)] -#![feature(maybe_uninit_slice)] #![feature(normalize_lexically)] #![feature(path_trailing_sep)] // tidy-alphabetical-end From 6cdfb609f9dba3dfc9e412bb6a6d87ee9efcf462 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 28 Nov 2025 23:31:41 -0500 Subject: [PATCH 06/12] make assoc fn inherit const stability from inherent `const impl` blocks --- compiler/rustc_passes/src/stability.rs | 2 +- .../traits/const-traits/auxiliary/staged-api.rs | 9 ++++++++- .../const-traits/inherent-impl-stability.rs | 16 ++++++++++++++++ .../const-traits/inherent-impl-stability.stderr | 13 +++++++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/const-traits/inherent-impl-stability.rs create mode 100644 tests/ui/traits/const-traits/inherent-impl-stability.stderr diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index b7e6e2d451e3f..39830db2b11db 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -54,7 +54,7 @@ fn inherit_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { match def_kind { DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { match tcx.def_kind(tcx.local_parent(def_id)) { - DefKind::Impl { of_trait: true } => true, + DefKind::Impl { .. } => true, _ => false, } } diff --git a/tests/ui/traits/const-traits/auxiliary/staged-api.rs b/tests/ui/traits/const-traits/auxiliary/staged-api.rs index b2b1e0615c37f..65e75864ff825 100644 --- a/tests/ui/traits/const-traits/auxiliary/staged-api.rs +++ b/tests/ui/traits/const-traits/auxiliary/staged-api.rs @@ -1,4 +1,3 @@ -//@ compile-flags: -Znext-solver #![feature(const_trait_impl)] #![feature(staged_api)] #![stable(feature = "rust1", since = "1.0.0")] @@ -19,6 +18,14 @@ impl const MyTrait for Unstable { fn func() {} } +// tested in inherent-impl-stability.rs instead to avoid clutter +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "unstable", issue = "none")] +const impl Unstable { + #[stable(feature = "rust1", since = "1.0.0")] + pub fn inherent_func() {} +} + #[stable(feature = "rust1", since = "1.0.0")] pub struct Unstable2; diff --git a/tests/ui/traits/const-traits/inherent-impl-stability.rs b/tests/ui/traits/const-traits/inherent-impl-stability.rs new file mode 100644 index 0000000000000..e520e5af2e094 --- /dev/null +++ b/tests/ui/traits/const-traits/inherent-impl-stability.rs @@ -0,0 +1,16 @@ +//@ aux-build: staged-api.rs +extern crate staged_api; + +use staged_api::*; + +// Const stability has no impact on usage in non-const contexts. +fn non_const_context() { + Unstable::inherent_func(); +} + +const fn stable_const_context() { + Unstable::inherent_func(); + //~^ ERROR: `staged_api::Unstable::inherent_func` is not yet stable as a const fn +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/inherent-impl-stability.stderr b/tests/ui/traits/const-traits/inherent-impl-stability.stderr new file mode 100644 index 0000000000000..018065c1f4f06 --- /dev/null +++ b/tests/ui/traits/const-traits/inherent-impl-stability.stderr @@ -0,0 +1,13 @@ +error: `staged_api::Unstable::inherent_func` is not yet stable as a const fn + --> $DIR/inherent-impl-stability.rs:12:5 + | +LL | Unstable::inherent_func(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add `#![feature(unstable)]` to the crate attributes to enable + | +LL + #![feature(unstable)] + | + +error: aborting due to 1 previous error + From d4af0f07729e1ce75e35f6c15ae5bab0830db760 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sun, 30 Nov 2025 20:29:26 +0900 Subject: [PATCH 07/12] Fix indent in E0591.md --- .../rustc_error_codes/src/error_codes/E0591.md | 16 ++++++++-------- tests/ui/explain/basic.stdout | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0591.md b/compiler/rustc_error_codes/src/error_codes/E0591.md index 6ed8370e8c1c7..c32aa95a3bfdd 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0591.md +++ b/compiler/rustc_error_codes/src/error_codes/E0591.md @@ -62,14 +62,14 @@ This pattern should be rewritten. There are a few possible ways to do this: and do the cast in the fn body (the preferred option) - cast the fn item of a fn pointer before calling transmute, as shown here: - ``` - # extern "C" fn foo(_: Box) {} - # use std::mem::transmute; - # unsafe { - let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_)); - let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too - # } - ``` +``` +# extern "C" fn foo(_: Box) {} +# use std::mem::transmute; +# unsafe { +let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_)); +let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too +# } +``` The same applies to transmutes to `*mut fn()`, which were observed in practice. Note though that use of this type is generally incorrect. diff --git a/tests/ui/explain/basic.stdout b/tests/ui/explain/basic.stdout index ef1d866c3ff3b..6377768d4785d 100644 --- a/tests/ui/explain/basic.stdout +++ b/tests/ui/explain/basic.stdout @@ -56,10 +56,10 @@ This pattern should be rewritten. There are a few possible ways to do this: and do the cast in the fn body (the preferred option) - cast the fn item of a fn pointer before calling transmute, as shown here: - ``` - let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_)); - let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too - ``` +``` +let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_)); +let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too +``` The same applies to transmutes to `*mut fn()`, which were observed in practice. Note though that use of this type is generally incorrect. From b111aed11ff1ad640b978b4f4480f56b898bf9f5 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Mon, 24 Nov 2025 14:45:52 +0800 Subject: [PATCH 08/12] fudge infer vars in cause code intentionally --- compiler/rustc_infer/src/traits/mod.rs | 2 + .../src/solve/fulfill/derive_errors.rs | 4 ++ .../leaking-vars-in-cause-code-1.rs | 43 +++++++++++++++++++ .../leaking-vars-in-cause-code-1.stderr | 35 +++++++++++++++ .../leaking-vars-in-cause-code-2.rs | 31 +++++++++++++ .../leaking-vars-in-cause-code-2.stderr | 37 ++++++++++++++++ 6 files changed, 152 insertions(+) create mode 100644 tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.rs create mode 100644 tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.stderr create mode 100644 tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.rs create mode 100644 tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 79a4859f286fb..0536a6c909507 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -37,6 +37,8 @@ use crate::infer::InferCtxt; #[derive(Clone, TypeFoldable, TypeVisitable)] pub struct Obligation<'tcx, T> { /// The reason we have to prove this thing. + /// FIXME: we shouldn't ignore the cause but instead change the affected visitors + /// to only visit predicates manually. #[type_foldable(identity)] #[type_visitable(ignore)] pub cause: ObligationCause<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 8482c8a2972dc..eef8b870a5b85 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -177,7 +177,11 @@ fn find_best_leaf_obligation<'tcx>( ) .break_value() .ok_or(()) + // walk around the fact that the cause in `Obligation` is ignored by folders so that + // we can properly fudge the infer vars in cause code. + .map(|o| (o.cause.clone(), o)) }) + .map(|(cause, o)| PredicateObligation { cause, ..o }) .unwrap_or(obligation); deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation) } diff --git a/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.rs b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.rs new file mode 100644 index 0000000000000..76a44dbe1abb2 --- /dev/null +++ b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.rs @@ -0,0 +1,43 @@ +//@ compile-flags: -Znext-solver +//@ edition: 2024 +// +// A regression test for the ICE variant in trait-system-refactor-initiative#245. +// We'll meet regions that're already popped off when using parent predicate in cause code. +// `cause` in `Obligation` is ignored by folders/visitors. +// In this case, `fudge_inference_if_ok` doesn't fudge a region var in cause code. +// +// The old solver doesn't trigger ICE because regions in the predicate are replaced with +// placeholders when checking generator witness. Besides, the old solver doesn't eagerly +// resolves vars before canonicalizing the predicate in `predicate_must_hold_modulo_regions`. + +trait AsyncFn: Send + 'static { + type Fut: Future + Send; + + fn call(&self) -> Self::Fut; +} + +async fn wrap_call(filter: &P) { + filter.call().await; +} + +fn get_boxed_fn() -> Box { + todo!() +} + +async fn cursed_fut() { + wrap_call(get_boxed_fn().as_ref()).await; +} + +fn observe_fut_not_send() { + assert_send(cursed_fut()); + //~^ ERROR: `dyn AsyncFn + Send>>>` cannot be shared between threads safely [E0277] +} + +fn assert_send(t: T) -> T { + t +} + +pub type BoxFuture<'a, T> = std::pin::Pin + Send + 'a>>; +type DynAsyncFnBoxed = dyn AsyncFn>; + +fn main() {} diff --git a/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.stderr b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.stderr new file mode 100644 index 0000000000000..a0951863f8a5c --- /dev/null +++ b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-1.stderr @@ -0,0 +1,35 @@ +error[E0277]: `dyn AsyncFn + Send>>>` cannot be shared between threads safely + --> $DIR/leaking-vars-in-cause-code-1.rs:32:17 + | +LL | assert_send(cursed_fut()); + | ----------- ^^^^^^^^^^^^ `dyn AsyncFn + Send>>>` cannot be shared between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Sync` is not implemented for `dyn AsyncFn + Send>>>` + = note: required for `&dyn AsyncFn + Send>>>` to implement `Send` +note: required because it's used within this `async` fn body + --> $DIR/leaking-vars-in-cause-code-1.rs:19:53 + | +LL | async fn wrap_call(filter: &P) { + | _____________________________________________________^ +LL | | filter.call().await; +LL | | } + | |_^ +note: required because it's used within this `async` fn body + --> $DIR/leaking-vars-in-cause-code-1.rs:27:23 + | +LL | async fn cursed_fut() { + | _______________________^ +LL | | wrap_call(get_boxed_fn().as_ref()).await; +LL | | } + | |_^ +note: required by a bound in `assert_send` + --> $DIR/leaking-vars-in-cause-code-1.rs:36:19 + | +LL | fn assert_send(t: T) -> T { + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.rs b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.rs new file mode 100644 index 0000000000000..4dd170c60113e --- /dev/null +++ b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -Znext-solver + +// The `cause` in `Obligation` is ignored by type folders. So infer vars in cause code is not +// fudged. +// Check the comments of +// `leaking-vars-in-cause-code-1.rs` for more details. +trait Trait {} +struct A(T); +struct B(T); + +trait IncompleteGuidance {} + +impl Trait<()> for A +where + T: IncompleteGuidance, +{ +} + +impl Trait<()> for B +//~^ ERROR: the type parameter `U` is not constrained by the impl trait, self type, or predicates +where + A: Trait, +{ +} + +fn impls_trait>() {} + +fn main() { + impls_trait::>(); + //~^ ERROR: the trait bound `(): IncompleteGuidance` is not satisfied +} diff --git a/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr new file mode 100644 index 0000000000000..9e8194b46c04f --- /dev/null +++ b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr @@ -0,0 +1,37 @@ +error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates + --> $DIR/leaking-vars-in-cause-code-2.rs:19:9 + | +LL | impl Trait<()> for B + | ^ unconstrained type parameter + +error[E0277]: the trait bound `(): IncompleteGuidance` is not satisfied + --> $DIR/leaking-vars-in-cause-code-2.rs:29:19 + | +LL | impls_trait::>(); + | ^^^^^ the trait `IncompleteGuidance` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/leaking-vars-in-cause-code-2.rs:11:1 + | +LL | trait IncompleteGuidance {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: required for `A<()>` to implement `Trait<()>` + --> $DIR/leaking-vars-in-cause-code-2.rs:13:9 + | +LL | impl Trait<()> for A + | ^^^^^^^^^ ^^^^ +LL | where +LL | T: IncompleteGuidance, + | ------------------ unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `B<()>` to implement `Trait<()>` +note: required by a bound in `impls_trait` + --> $DIR/leaking-vars-in-cause-code-2.rs:26:19 + | +LL | fn impls_trait>() {} + | ^^^^^^^^^ required by this bound in `impls_trait` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0207, E0277. +For more information about an error, try `rustc --explain E0207`. From ae7fa32e5bb2057d92fc8e5e58bc17cf4f045609 Mon Sep 17 00:00:00 2001 From: MolecularPilot Date: Sat, 8 Nov 2025 22:17:55 +1100 Subject: [PATCH 09/12] Implement `clamp_magnitude` for floats & signed integers Added feature gate, documentation and tests also. --- library/core/src/num/f128.rs | 32 ++++ library/core/src/num/f16.rs | 32 ++++ library/core/src/num/f32.rs | 29 ++++ library/core/src/num/f64.rs | 29 ++++ library/core/src/num/int_macros.rs | 27 ++++ library/coretests/tests/lib.rs | 1 + .../coretests/tests/num/clamp_magnitude.rs | 139 ++++++++++++++++++ 7 files changed, 289 insertions(+) create mode 100644 library/coretests/tests/num/clamp_magnitude.rs diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index e7101537b298f..f51b561cabf87 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1276,6 +1276,38 @@ impl f128 { self } + /// Clamps this number to a symmetric range centered around zero. + /// + /// The method clamps the number's magnitude (absolute value) to be at most `limit`. + /// + /// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more + /// explicit about the intent. + /// + /// # Panics + /// + /// Panics if `limit` is negative or NaN, as this indicates a logic error. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// #![feature(clamp_magnitude)] + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// assert_eq!(5.0f128.clamp_magnitude(3.0), 3.0); + /// assert_eq!((-5.0f128).clamp_magnitude(3.0), -3.0); + /// assert_eq!(2.0f128.clamp_magnitude(3.0), 2.0); + /// assert_eq!((-2.0f128).clamp_magnitude(3.0), -2.0); + /// # } + /// ``` + #[inline] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[must_use = "this returns the clamped value and does not modify the original"] + pub fn clamp_magnitude(self, limit: f128) -> f128 { + assert!(limit >= 0.0, "limit must be non-negative"); + let limit = limit.abs(); // Canonicalises -0.0 to 0.0 + self.clamp(-limit, limit) + } + /// Computes the absolute value of `self`. /// /// This function always returns the precise result. diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index aa8342a22ad58..318c9599ccea1 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1254,6 +1254,38 @@ impl f16 { self } + /// Clamps this number to a symmetric range centered around zero. + /// + /// The method clamps the number's magnitude (absolute value) to be at most `limit`. + /// + /// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more + /// explicit about the intent. + /// + /// # Panics + /// + /// Panics if `limit` is negative or NaN, as this indicates a logic error. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// #![feature(clamp_magnitude)] + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// assert_eq!(5.0f16.clamp_magnitude(3.0), 3.0); + /// assert_eq!((-5.0f16).clamp_magnitude(3.0), -3.0); + /// assert_eq!(2.0f16.clamp_magnitude(3.0), 2.0); + /// assert_eq!((-2.0f16).clamp_magnitude(3.0), -2.0); + /// # } + /// ``` + #[inline] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[must_use = "this returns the clamped value and does not modify the original"] + pub fn clamp_magnitude(self, limit: f16) -> f16 { + assert!(limit >= 0.0, "limit must be non-negative"); + let limit = limit.abs(); // Canonicalises -0.0 to 0.0 + self.clamp(-limit, limit) + } + /// Computes the absolute value of `self`. /// /// This function always returns the precise result. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 3070e1dedbe43..91e276c5bc8e8 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1431,6 +1431,35 @@ impl f32 { self } + /// Clamps this number to a symmetric range centered around zero. + /// + /// The method clamps the number's magnitude (absolute value) to be at most `limit`. + /// + /// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more + /// explicit about the intent. + /// + /// # Panics + /// + /// Panics if `limit` is negative or NaN, as this indicates a logic error. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp_magnitude)] + /// assert_eq!(5.0f32.clamp_magnitude(3.0), 3.0); + /// assert_eq!((-5.0f32).clamp_magnitude(3.0), -3.0); + /// assert_eq!(2.0f32.clamp_magnitude(3.0), 2.0); + /// assert_eq!((-2.0f32).clamp_magnitude(3.0), -2.0); + /// ``` + #[must_use = "this returns the clamped value and does not modify the original"] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[inline] + pub fn clamp_magnitude(self, limit: f32) -> f32 { + assert!(limit >= 0.0, "limit must be non-negative"); + let limit = limit.abs(); // Canonicalises -0.0 to 0.0 + self.clamp(-limit, limit) + } + /// Computes the absolute value of `self`. /// /// This function always returns the precise result. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index dc8ccc551b2da..a4b2979c37d0d 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1429,6 +1429,35 @@ impl f64 { self } + /// Clamps this number to a symmetric range centered around zero. + /// + /// The method clamps the number's magnitude (absolute value) to be at most `limit`. + /// + /// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more + /// explicit about the intent. + /// + /// # Panics + /// + /// Panics if `limit` is negative or NaN, as this indicates a logic error. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp_magnitude)] + /// assert_eq!(5.0f64.clamp_magnitude(3.0), 3.0); + /// assert_eq!((-5.0f64).clamp_magnitude(3.0), -3.0); + /// assert_eq!(2.0f64.clamp_magnitude(3.0), 2.0); + /// assert_eq!((-2.0f64).clamp_magnitude(3.0), -2.0); + /// ``` + #[must_use = "this returns the clamped value and does not modify the original"] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[inline] + pub fn clamp_magnitude(self, limit: f64) -> f64 { + assert!(limit >= 0.0, "limit must be non-negative"); + let limit = limit.abs(); // Canonicalises -0.0 to 0.0 + self.clamp(-limit, limit) + } + /// Computes the absolute value of `self`. /// /// This function always returns the precise result. diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 7d395eb780346..9134d37636f0f 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -3855,5 +3855,32 @@ macro_rules! int_impl { pub const fn max_value() -> Self { Self::MAX } + + /// Clamps this number to a symmetric range centred around zero. + /// + /// The method clamps the number's magnitude (absolute value) to be at most `limit`. + /// + /// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more + /// explicit about the intent. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp_magnitude)] + #[doc = concat!("assert_eq!(120", stringify!($SelfT), ".clamp_magnitude(100), 100);")] + #[doc = concat!("assert_eq!(-120", stringify!($SelfT), ".clamp_magnitude(100), -100);")] + #[doc = concat!("assert_eq!(80", stringify!($SelfT), ".clamp_magnitude(100), 80);")] + #[doc = concat!("assert_eq!(-80", stringify!($SelfT), ".clamp_magnitude(100), -80);")] + /// ``` + #[must_use = "this returns the clamped value and does not modify the original"] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[inline] + pub fn clamp_magnitude(self, limit: $UnsignedT) -> Self { + if let Ok(limit) = core::convert::TryInto::<$SelfT>::try_into(limit) { + self.clamp(-limit, limit) + } else { + self + } + } } } diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 80b62038c40ec..124a8cf69385d 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -15,6 +15,7 @@ #![feature(cfg_target_has_reliable_f16_f128)] #![feature(char_internals)] #![feature(char_max_len)] +#![feature(clamp_magnitude)] #![feature(clone_to_uninit)] #![feature(const_cell_traits)] #![feature(const_cmp)] diff --git a/library/coretests/tests/num/clamp_magnitude.rs b/library/coretests/tests/num/clamp_magnitude.rs new file mode 100644 index 0000000000000..0f96e55f6914e --- /dev/null +++ b/library/coretests/tests/num/clamp_magnitude.rs @@ -0,0 +1,139 @@ +macro_rules! check_int_clamp { + ($t:ty, $ut:ty) => { + let min = <$t>::MIN; + let max = <$t>::MAX; + let max_u = <$ut>::MAX; + + // Basic clamping + assert_eq!((100 as $t).clamp_magnitude(50), 50); + assert_eq!((-100 as $t).clamp_magnitude(50), -50); + assert_eq!((30 as $t).clamp_magnitude(50), 30); + assert_eq!((-30 as $t).clamp_magnitude(50), -30); + + // Exact boundary + assert_eq!((50 as $t).clamp_magnitude(50), 50); + assert_eq!((-50 as $t).clamp_magnitude(50), -50); + + // Zero cases + assert_eq!((0 as $t).clamp_magnitude(100), 0); + assert_eq!((0 as $t).clamp_magnitude(0), 0); + assert_eq!((100 as $t).clamp_magnitude(0), 0); + assert_eq!((-100 as $t).clamp_magnitude(0), 0); + + // MIN/MAX values + // Symmetric range [-MAX, MAX] + assert_eq!(max.clamp_magnitude(max as $ut), max); + assert_eq!(min.clamp_magnitude(max as $ut), -max); + + // Full range (limit covers MIN) + let min_abs = min.unsigned_abs(); + assert_eq!(min.clamp_magnitude(min_abs), min); + + // Limit larger than type max (uN > iN::MAX) + assert_eq!(max.clamp_magnitude(max_u), max); + assert_eq!(min.clamp_magnitude(max_u), min); + }; +} + +#[test] +fn test_clamp_magnitude_i8() { + check_int_clamp!(i8, u8); +} + +#[test] +fn test_clamp_magnitude_i16() { + check_int_clamp!(i16, u16); +} + +#[test] +fn test_clamp_magnitude_i32() { + check_int_clamp!(i32, u32); +} + +#[test] +fn test_clamp_magnitude_i64() { + check_int_clamp!(i64, u64); +} + +#[test] +fn test_clamp_magnitude_i128() { + check_int_clamp!(i128, u128); +} + +#[test] +fn test_clamp_magnitude_isize() { + check_int_clamp!(isize, usize); +} + +macro_rules! check_float_clamp { + ($t:ty) => { + // Basic clamping + assert_eq!((5.0 as $t).clamp_magnitude(3.0), 3.0); + assert_eq!((-5.0 as $t).clamp_magnitude(3.0), -3.0); + assert_eq!((2.0 as $t).clamp_magnitude(3.0), 2.0); + assert_eq!((-2.0 as $t).clamp_magnitude(3.0), -2.0); + + // Exact boundary + assert_eq!((3.0 as $t).clamp_magnitude(3.0), 3.0); + assert_eq!((-3.0 as $t).clamp_magnitude(3.0), -3.0); + + // Zero cases + assert_eq!((0.0 as $t).clamp_magnitude(1.0), 0.0); + assert_eq!((-0.0 as $t).clamp_magnitude(1.0), 0.0); + assert_eq!((5.0 as $t).clamp_magnitude(0.0), 0.0); + assert_eq!((-5.0 as $t).clamp_magnitude(0.0), 0.0); + + // Special values - Infinity + let inf = <$t>::INFINITY; + let neg_inf = <$t>::NEG_INFINITY; + assert_eq!(inf.clamp_magnitude(100.0), 100.0); + assert_eq!(neg_inf.clamp_magnitude(100.0), -100.0); + assert_eq!(inf.clamp_magnitude(inf), inf); + + // Value with infinite limit + assert_eq!((1.0 as $t).clamp_magnitude(inf), 1.0); + assert_eq!((-1.0 as $t).clamp_magnitude(inf), -1.0); + + // MIN and MAX + let max = <$t>::MAX; + let min = <$t>::MIN; + // Large limit + let huge = 1e30; + assert_eq!(max.clamp_magnitude(huge), huge); + assert_eq!(min.clamp_magnitude(huge), -huge); + }; +} + +#[test] +fn test_clamp_magnitude_f32() { + check_float_clamp!(f32); +} + +#[test] +fn test_clamp_magnitude_f64() { + check_float_clamp!(f64); +} + +#[test] +#[should_panic(expected = "limit must be non-negative")] +fn test_clamp_magnitude_f32_panic_negative_limit() { + let _ = 1.0f32.clamp_magnitude(-1.0); +} + +#[test] +#[should_panic(expected = "limit must be non-negative")] +fn test_clamp_magnitude_f64_panic_negative_limit() { + let _ = 1.0f64.clamp_magnitude(-1.0); +} + +#[test] +#[should_panic] +fn test_clamp_magnitude_f32_panic_nan_limit() { + let _ = 1.0f32.clamp_magnitude(f32::NAN); +} + +#[test] +#[should_panic] +fn test_clamp_magnitude_f64_panic_nan_limit() { + let _ = 1.0f64.clamp_magnitude(f64::NAN); +} From 968376d507d86e935cc0f61da9c206fbf9633bdb Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Sun, 30 Nov 2025 22:03:21 +0300 Subject: [PATCH 10/12] Add label rib when visiting delegation body, add test --- compiler/rustc_resolve/src/late.rs | 6 +++++- tests/ui/delegation/ice-issue-148889.rs | 18 ++++++++++++++++++ tests/ui/delegation/ice-issue-148889.stderr | 13 +++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/ui/delegation/ice-issue-148889.rs create mode 100644 tests/ui/delegation/ice-issue-148889.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index df620ddb66529..b689765bf6fa1 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3689,7 +3689,11 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let ident = Ident::new(kw::SelfLower, span.normalize_to_macro_rules()); let res = Res::Local(delegation.id); this.innermost_rib_bindings(ValueNS).insert(ident, res); - this.visit_block(body); + + //As we lower target_expr_template body to a body of a function we need a label rib (#148889) + this.with_label_rib(RibKind::FnOrCoroutine, |this| { + this.visit_block(body); + }); }); } diff --git a/tests/ui/delegation/ice-issue-148889.rs b/tests/ui/delegation/ice-issue-148889.rs new file mode 100644 index 0000000000000..e5f9fa1cf4934 --- /dev/null +++ b/tests/ui/delegation/ice-issue-148889.rs @@ -0,0 +1,18 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +trait Trait { + fn static_method2(x: i32, y: i32) -> i32 { + x + y + } +} + +struct S; +impl Trait for S {} + +pub fn main() { + 'foo: loop { + reuse ::static_method2 { loop { break 'foo; } } + //~^ ERROR use of unreachable label `'foo` + } +} diff --git a/tests/ui/delegation/ice-issue-148889.stderr b/tests/ui/delegation/ice-issue-148889.stderr new file mode 100644 index 0000000000000..2ebc7b3ec14e1 --- /dev/null +++ b/tests/ui/delegation/ice-issue-148889.stderr @@ -0,0 +1,13 @@ +error[E0767]: use of unreachable label `'foo` + --> $DIR/ice-issue-148889.rs:15:59 + | +LL | 'foo: loop { + | ---- unreachable label defined here +LL | reuse ::static_method2 { loop { break 'foo; } } + | ^^^^ unreachable label `'foo` + | + = note: labels are unreachable through functions, closures, async blocks and modules + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0767`. From 97f93df9c77ffbdd938e88943754298bf510ac99 Mon Sep 17 00:00:00 2001 From: lapla Date: Mon, 1 Dec 2025 09:32:06 +0900 Subject: [PATCH 11/12] Don't suggest unwrap for Result in const --- .../src/fn_ctxt/suggestions.rs | 18 +++++++------- .../rustc_hir_typeck/src/method/suggest.rs | 18 +++++++------- .../const-result-no-expect-suggestion.rs | 15 ++++++++++++ .../const-result-no-expect-suggestion.stderr | 24 +++++++++++++++++++ 4 files changed, 59 insertions(+), 16 deletions(-) create mode 100644 tests/ui/consts/const-result-no-expect-suggestion.rs create mode 100644 tests/ui/consts/const-result-no-expect-suggestion.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1d16c3af7fb75..1adcd91cc3ee2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2106,14 +2106,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )), ); - let (article, kind, variant, sugg_operator) = - if self.tcx.is_diagnostic_item(sym::Result, adt.did()) { - ("a", "Result", "Err", ret_ty_matches(sym::Result)) - } else if self.tcx.is_diagnostic_item(sym::Option, adt.did()) { - ("an", "Option", "None", ret_ty_matches(sym::Option)) - } else { - return false; - }; + let (article, kind, variant, sugg_operator) = if self.tcx.is_diagnostic_item(sym::Result, adt.did()) + // Do not suggest `.expect()` in const context where it's not available. rust-lang/rust#149316 + && !self.tcx.hir_is_inside_const_context(expr.hir_id) + { + ("a", "Result", "Err", ret_ty_matches(sym::Result)) + } else if self.tcx.is_diagnostic_item(sym::Option, adt.did()) { + ("an", "Option", "None", ret_ty_matches(sym::Option)) + } else { + return false; + }; if is_ctor || !self.may_coerce(args.type_at(0), expected) { return false; } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 9a657ab159035..4b9ad345210dd 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3041,14 +3041,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.def_span(pick.item.def_id), format!("the method `{item_name}` exists on the type `{self_ty}`"), ); - let (article, kind, variant, question) = - if tcx.is_diagnostic_item(sym::Result, kind.did()) { - ("a", "Result", "Err", ret_ty_matches(sym::Result)) - } else if tcx.is_diagnostic_item(sym::Option, kind.did()) { - ("an", "Option", "None", ret_ty_matches(sym::Option)) - } else { - return; - }; + let (article, kind, variant, question) = if tcx.is_diagnostic_item(sym::Result, kind.did()) + // Do not suggest `.expect()` in const context where it's not available. rust-lang/rust#149316 + && !tcx.hir_is_inside_const_context(expr.hir_id) + { + ("a", "Result", "Err", ret_ty_matches(sym::Result)) + } else if tcx.is_diagnostic_item(sym::Option, kind.did()) { + ("an", "Option", "None", ret_ty_matches(sym::Option)) + } else { + return; + }; if question { err.span_suggestion_verbose( expr.span.shrink_to_hi(), diff --git a/tests/ui/consts/const-result-no-expect-suggestion.rs b/tests/ui/consts/const-result-no-expect-suggestion.rs new file mode 100644 index 0000000000000..cd725d9cee0ec --- /dev/null +++ b/tests/ui/consts/const-result-no-expect-suggestion.rs @@ -0,0 +1,15 @@ +const fn f(value: u32) -> Result { + Ok(value) +} + +const TEST: u32 = f(2); +//~^ ERROR: mismatched types + +const fn g() -> Result { + Ok(String::new()) +} + +const TEST2: usize = g().len(); +//~^ ERROR: no method named `len` found for enum `Result` + +fn main() {} diff --git a/tests/ui/consts/const-result-no-expect-suggestion.stderr b/tests/ui/consts/const-result-no-expect-suggestion.stderr new file mode 100644 index 0000000000000..70aa306ae3c88 --- /dev/null +++ b/tests/ui/consts/const-result-no-expect-suggestion.stderr @@ -0,0 +1,24 @@ +error[E0308]: mismatched types + --> $DIR/const-result-no-expect-suggestion.rs:5:19 + | +LL | const TEST: u32 = f(2); + | ^^^^ expected `u32`, found `Result` + | + = note: expected type `u32` + found enum `Result` + +error[E0599]: no method named `len` found for enum `Result` in the current scope + --> $DIR/const-result-no-expect-suggestion.rs:12:26 + | +LL | const TEST2: usize = g().len(); + | ^^^ + | +note: the method `len` exists on the type `String` + --> $SRC_DIR/alloc/src/string.rs:LL:COL +help: there is a method `le` with a similar name, but with different arguments + --> $SRC_DIR/core/src/cmp.rs:LL:COL + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0599. +For more information about an error, try `rustc --explain E0308`. From 62fe6a01438ae919a04e2d91d22e4ffa632f5971 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Mon, 1 Dec 2025 15:30:53 +0300 Subject: [PATCH 12/12] Rename added test --- .../{ice-issue-148889.rs => unreachable-label-ice-148889.rs} | 0 ...-issue-148889.stderr => unreachable-label-ice-148889.stderr} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/ui/delegation/{ice-issue-148889.rs => unreachable-label-ice-148889.rs} (100%) rename tests/ui/delegation/{ice-issue-148889.stderr => unreachable-label-ice-148889.stderr} (90%) diff --git a/tests/ui/delegation/ice-issue-148889.rs b/tests/ui/delegation/unreachable-label-ice-148889.rs similarity index 100% rename from tests/ui/delegation/ice-issue-148889.rs rename to tests/ui/delegation/unreachable-label-ice-148889.rs diff --git a/tests/ui/delegation/ice-issue-148889.stderr b/tests/ui/delegation/unreachable-label-ice-148889.stderr similarity index 90% rename from tests/ui/delegation/ice-issue-148889.stderr rename to tests/ui/delegation/unreachable-label-ice-148889.stderr index 2ebc7b3ec14e1..2141962609183 100644 --- a/tests/ui/delegation/ice-issue-148889.stderr +++ b/tests/ui/delegation/unreachable-label-ice-148889.stderr @@ -1,5 +1,5 @@ error[E0767]: use of unreachable label `'foo` - --> $DIR/ice-issue-148889.rs:15:59 + --> $DIR/unreachable-label-ice-148889.rs:15:59 | LL | 'foo: loop { | ---- unreachable label defined here