Auto merge of #149510 - matthiaskrgr:rollup-5rt6o7z, r=matthiaskrgr

Rollup of 9 pull requests

Successful merges:

 - rust-lang/rust#148690 (Implement `clamp_magnitude` method for primitive floats & signed integers)
 - rust-lang/rust#149102 (stabilize maybe_uninit_slice)
 - rust-lang/rust#149269 (cmse: do not calculate the layout of a type with infer types)
 - rust-lang/rust#149299 (Fudge infer vars in the cause code of `Obligation` intentionally)
 - rust-lang/rust#149344 (Don't suggest unwrap for Result in const)
 - rust-lang/rust#149358 (fix(parse): Limit frontmatter fences to 255 dashes )
 - rust-lang/rust#149445 (make assoc fn inherit const stability from inherent `const impl` blocks)
 - rust-lang/rust#149479 (Fix indent in E0591.md)
 - rust-lang/rust#149496 (Fix rust-lang/rust#148889: Add label rib when visiting delegation body)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors
2025-12-01 17:16:50 +00:00
46 changed files with 764 additions and 71 deletions
+1 -1
View File
@@ -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)]
@@ -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<i32>) {}
# 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<i32>) {}
# 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.
@@ -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))?;
@@ -2106,14 +2106,16 @@ pub(crate) fn suggest_missing_unwrap_expect(
)),
);
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;
}
@@ -3041,14 +3041,16 @@ fn suggest_unwrapping_inner_self(
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(),
+2
View File
@@ -37,6 +37,8 @@
#[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>,
+1
View File
@@ -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
+6
View File
@@ -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 {
+5
View File
@@ -665,6 +665,11 @@ fn validate_frontmatter(
});
}
// 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 });
+1 -1
View File
@@ -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,
}
}
+5 -1
View File
@@ -3689,7 +3689,11 @@ fn resolve_delegation(&mut self, delegation: &'ast Delegation) {
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);
});
});
}
@@ -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)
}
-1
View File
@@ -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)]
-1
View File
@@ -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)]
+1 -7
View File
@@ -114,16 +114,10 @@ fn push(&mut self, value: 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() };
}
}
+8 -20
View File
@@ -1047,7 +1047,7 @@ pub const fn as_mut_ptr(&mut self) -> *mut T {
/// # Examples
///
/// ```
/// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)]
/// #![feature(maybe_uninit_as_bytes)]
/// use std::mem::MaybeUninit;
///
/// let val = 0x12345678_i32;
@@ -1097,20 +1097,6 @@ pub const fn as_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
)
}
}
/// 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<T>]) -> *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<T>]) -> *mut T {
this.as_mut_ptr() as *mut T
}
}
impl<T> [MaybeUninit<T>] {
@@ -1410,7 +1396,7 @@ pub fn write_iter<I>(&mut self, it: I) -> (&mut [T], &mut [MaybeUninit<T>])
/// # 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)];
@@ -1437,7 +1423,7 @@ pub const fn as_bytes(&self) -> &[MaybeUninit<u8>] {
/// # Examples
///
/// ```
/// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)]
/// #![feature(maybe_uninit_as_bytes)]
/// use std::mem::MaybeUninit;
///
/// let mut uninit = [MaybeUninit::<u16>::uninit(), MaybeUninit::<u16>::uninit()];
@@ -1477,7 +1463,7 @@ pub const fn as_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
/// requirement the compiler knows about it is that the data pointer must be
/// non-null. Dropping such a `Vec<T>` 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 @@ pub const fn as_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
/// Calling this when the content is not yet fully initialized causes undefined
/// behavior: it is up to the caller to guarantee that every `MaybeUninit<T>` 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 @@ pub const fn as_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
/// behavior: it is up to the caller to guarantee that every `MaybeUninit<T>` 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
+32
View File
@@ -1291,6 +1291,38 @@ pub const fn clamp(mut self, min: f128, max: f128) -> 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.
+32
View File
@@ -1269,6 +1269,38 @@ pub const fn clamp(mut self, min: f16, max: f16) -> 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.
+29
View File
@@ -1446,6 +1446,35 @@ pub const fn clamp(mut self, min: f32, max: f32) -> 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.
+29
View File
@@ -1444,6 +1444,35 @@ pub const fn clamp(mut self, min: f64, max: f64) -> 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.
+27
View File
@@ -3878,5 +3878,32 @@ pub const fn min_value() -> Self {
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
}
}
}
}
+1 -1
View File
@@ -35,7 +35,7 @@ pub fn merge<T, F: FnMut(&T, &T) -> 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);
@@ -97,7 +97,7 @@ fn stable_partition<T, F: FnMut(&T, &T) -> 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
+1
View File
@@ -16,6 +16,7 @@
#![feature(cfg_target_has_reliable_f16_f128)]
#![feature(char_internals)]
#![feature(char_max_len)]
#![feature(clamp_magnitude)]
#![feature(clone_to_uninit)]
#![feature(const_array)]
#![feature(const_cell_traits)]
@@ -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);
}
-1
View File
@@ -346,7 +346,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)]
-1
View File
@@ -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
-6
View File
@@ -1,6 +0,0 @@
//@ known-bug: rust-lang/rust#130104
fn main() {
let non_secure_function =
core::mem::transmute::<fn() -> _, extern "cmse-nonsecure-call" fn() -> _>;
}
@@ -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::<fn() -> _, extern "cmse-nonsecure-call" fn() -> _>;
//~^ ERROR type annotations needed
}
fn infer_2() {
let _ = mem::transmute::<fn() -> (i32, _), extern "cmse-nonsecure-call" fn() -> (i32, _)>;
//~^ ERROR type annotations needed
}
fn infer_3() {
let _ = mem::transmute::<fn(_: _) -> (), extern "cmse-nonsecure-call" fn(_: _) -> ()>;
//~^ ERROR type annotations needed
}
fn infer_4() {
let _ =
mem::transmute::<fn(_: (i32, _)) -> (), extern "cmse-nonsecure-call" fn(_: (i32, _)) -> ()>;
//~^ ERROR type annotations needed
}
@@ -0,0 +1,27 @@
error[E0282]: type annotations needed
--> $DIR/infer.rs:16:13
|
LL | let _ = mem::transmute::<fn() -> _, 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::<fn() -> (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::<fn(_: _) -> (), 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::<fn(_: (i32, _)) -> (), 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`.
@@ -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::<fn() -> _, extern "cmse-nonsecure-entry" fn() -> _>;
//~^ ERROR type annotations needed
}
fn infer_2() {
let _ = mem::transmute::<fn() -> (i32, _), extern "cmse-nonsecure-entry" fn() -> (i32, _)>;
//~^ ERROR type annotations needed
}
fn infer_3() {
let _ = mem::transmute::<fn(_: _) -> (), 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, _)) -> (),
>;
}
@@ -0,0 +1,32 @@
error[E0282]: type annotations needed
--> $DIR/infer.rs:16:13
|
LL | let _ = mem::transmute::<fn() -> _, 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::<fn() -> (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::<fn(_: _) -> (), 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`.
@@ -0,0 +1,15 @@
const fn f(value: u32) -> Result<u32, ()> {
Ok(value)
}
const TEST: u32 = f(2);
//~^ ERROR: mismatched types
const fn g() -> Result<String, ()> {
Ok(String::new())
}
const TEST2: usize = g().len();
//~^ ERROR: no method named `len` found for enum `Result<T, E>`
fn main() {}
@@ -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<u32, ()>`
|
= note: expected type `u32`
found enum `Result<u32, ()>`
error[E0599]: no method named `len` found for enum `Result<T, E>` 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`.
@@ -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 <S as Trait>::static_method2 { loop { break 'foo; } }
//~^ ERROR use of unreachable label `'foo`
}
}
@@ -0,0 +1,13 @@
error[E0767]: use of unreachable label `'foo`
--> $DIR/unreachable-label-ice-148889.rs:15:59
|
LL | 'foo: loop {
| ---- unreachable label defined here
LL | reuse <S as Trait>::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`.
+4 -4
View File
@@ -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.
@@ -0,0 +1,11 @@
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//~? ERROR: too many `-` symbols: frontmatter openings may be delimited by up to 255 `-` symbols
// ignore-tidy-linelength
[dependencies]
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#![feature(frontmatter)]
// check that we limit fence lengths
fn main() {}
@@ -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
@@ -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;
@@ -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() {}
@@ -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
@@ -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<Output = ()> + Send;
fn call(&self) -> Self::Fut;
}
async fn wrap_call<P: AsyncFn + ?Sized>(filter: &P) {
filter.call().await;
}
fn get_boxed_fn() -> Box<DynAsyncFnBoxed> {
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<Fut = Pin<Box<dyn Future<Output = ()> + Send>>>` cannot be shared between threads safely [E0277]
}
fn assert_send<T: Send>(t: T) -> T {
t
}
pub type BoxFuture<'a, T> = std::pin::Pin<Box<dyn Future<Output = T> + Send + 'a>>;
type DynAsyncFnBoxed = dyn AsyncFn<Fut = BoxFuture<'static, ()>>;
fn main() {}
@@ -0,0 +1,35 @@
error[E0277]: `dyn AsyncFn<Fut = Pin<Box<dyn Future<Output = ()> + Send>>>` cannot be shared between threads safely
--> $DIR/leaking-vars-in-cause-code-1.rs:32:17
|
LL | assert_send(cursed_fut());
| ----------- ^^^^^^^^^^^^ `dyn AsyncFn<Fut = Pin<Box<dyn Future<Output = ()> + 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<Fut = Pin<Box<dyn Future<Output = ()> + Send>>>`
= note: required for `&dyn AsyncFn<Fut = Pin<Box<dyn Future<Output = ()> + 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<P: AsyncFn + ?Sized>(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: 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`.
@@ -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<T> {}
struct A<T>(T);
struct B<T>(T);
trait IncompleteGuidance {}
impl<T> Trait<()> for A<T>
where
T: IncompleteGuidance,
{
}
impl<T, U> Trait<()> for B<T>
//~^ ERROR: the type parameter `U` is not constrained by the impl trait, self type, or predicates
where
A<T>: Trait<U>,
{
}
fn impls_trait<T: Trait<()>>() {}
fn main() {
impls_trait::<B<()>>();
//~^ ERROR: the trait bound `(): IncompleteGuidance` is not satisfied
}
@@ -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<T, U> Trait<()> for B<T>
| ^ 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::<B<()>>();
| ^^^^^ 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<T> Trait<()> for A<T>
| ^^^^^^^^^ ^^^^
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<T: 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`.