Auto merge of #151291 - jhpratt:rollup-CVsL9ZN, r=jhpratt

Rollup of 8 pull requests

Successful merges:

 - rust-lang/rust#148769 (Stabilize `alloc_layout_extra`)
 - rust-lang/rust#150200 (Add title field to `ice.md` issue template)
 - rust-lang/rust#150955 (Underscore-prefixed bindings are explicitly allowed to be unused)
 - rust-lang/rust#151200 (time: Add saturating arithmetic for `SystemTime`)
 - rust-lang/rust#151235 (Change field `bit_width: usize` to `bits: u32` in type info)
 - rust-lang/rust#151242 (Port #[needs_allocator] to attribute parser)
 - rust-lang/rust#151274 (Include a link to `count_ones` in the docs for `uN::count_zeros` [docs only])
 - rust-lang/rust#151279 (remove trailing periods in built-in attribute gate messages)

r? @ghost
This commit is contained in:
bors 2026-01-18 11:33:20 +00:00
commit ba2a7d3374
34 changed files with 266 additions and 99 deletions

View file

@ -2,6 +2,7 @@
name: Internal Compiler Error
about: Create a report for an internal compiler error in rustc.
labels: C-bug, I-ICE, T-compiler
title: "[ICE]: "
---
<!--
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide

View file

@ -658,3 +658,12 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
Some(AttributeKind::Linkage(linkage, cx.attr_span))
}
}
pub(crate) struct NeedsAllocatorParser;
impl<S: Stage> NoArgsAttributeParser<S> for NeedsAllocatorParser {
const PATH: &[Symbol] = &[sym::needs_allocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
}

View file

@ -41,7 +41,7 @@ use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
use crate::attributes::instruction_set::InstructionSetParser;
use crate::attributes::link_attrs::{
ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser,
LinkParser, LinkSectionParser, LinkageParser, StdInternalSymbolParser,
LinkParser, LinkSectionParser, LinkageParser, NeedsAllocatorParser, StdInternalSymbolParser,
};
use crate::attributes::lint_helpers::{
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
@ -259,6 +259,7 @@ attribute_parsers!(
Single<WithoutArgs<MacroEscapeParser>>,
Single<WithoutArgs<MarkerParser>>,
Single<WithoutArgs<MayDangleParser>>,
Single<WithoutArgs<NeedsAllocatorParser>>,
Single<WithoutArgs<NoCoreParser>>,
Single<WithoutArgs<NoImplicitPreludeParser>>,
Single<WithoutArgs<NoLinkParser>>,

View file

@ -14,11 +14,10 @@ diff --git a/coretests/tests/lib.rs b/coretests/tests/lib.rs
index 1e336bf..35e6f54 100644
--- a/coretests/tests/lib.rs
+++ b/coretests/tests/lib.rs
@@ -2,5 +2,4 @@
@@ -2,4 +2,3 @@
// tidy-alphabetical-start
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
#![cfg_attr(test, feature(cfg_select))]
#![feature(alloc_layout_extra)]
#![feature(array_ptr_get)]
diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs
index b735957..ea728b6 100644

View file

@ -257,8 +257,8 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
{
let field_place = self.project_field(&place, field_idx)?;
match field.name {
sym::bit_width => self.write_scalar(
ScalarInt::try_from_target_usize(bit_width, self.tcx.tcx).unwrap(),
sym::bits => self.write_scalar(
Scalar::from_u32(bit_width.try_into().expect("bit_width overflowed")),
&field_place,
)?,
sym::signed => self.write_scalar(Scalar::from_bool(signed), &field_place)?,
@ -278,8 +278,8 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
{
let field_place = self.project_field(&place, field_idx)?;
match field.name {
sym::bit_width => self.write_scalar(
ScalarInt::try_from_target_usize(bit_width, self.tcx.tcx).unwrap(),
sym::bits => self.write_scalar(
Scalar::from_u32(bit_width.try_into().expect("bit_width overflowed")),
&field_place,
)?,
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),

View file

@ -678,7 +678,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(
rustc_pass_indirectly_in_non_rustic_abis, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::No,
"types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic abis."
"types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic ABIs"
),
// Limits:
@ -1275,38 +1275,38 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(
rustc_as_ptr, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations."
"`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations"
),
rustc_attr!(
rustc_should_not_be_called_on_const_items, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"`#[rustc_should_not_be_called_on_const_items]` is used to mark methods that don't make sense to be called on interior mutable consts."
"`#[rustc_should_not_be_called_on_const_items]` is used to mark methods that don't make sense to be called on interior mutable consts"
),
rustc_attr!(
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference."
"`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference"
),
rustc_attr!(
rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers."
"`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers"
),
rustc_attr!(
rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes,
"`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument."
"`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument"
),
rustc_attr!(
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
"`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`."
"`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`"
),
rustc_attr!(
rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
"`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver."
"`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver"
),
rustc_attr!(
rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
"`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl."
"`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl"
),
rustc_attr!(
rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
@ -1333,7 +1333,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
ErrorFollowing, EncodeCrossCrate::Yes,
"`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \
the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`."
the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`"
),
BuiltinAttribute {
@ -1396,7 +1396,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
EncodeCrossCrate::No,
"the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
from method dispatch when the receiver is of the following type, for compatibility in \
editions < 2021 (array) or editions < 2024 (boxed_slice)."
editions < 2021 (array) or editions < 2024 (boxed_slice)"
),
rustc_attr!(
rustc_must_implement_one_of, Normal, template!(List: &["function1, function2, ..."]),

View file

@ -840,6 +840,9 @@ pub enum AttributeKind {
/// Represents `#[naked]`
Naked(Span),
/// Represents `#[needs_allocator]`
NeedsAllocator,
/// Represents `#[no_core]`
NoCore(Span),

View file

@ -75,6 +75,7 @@ impl AttributeKind {
MustNotSupend { .. } => Yes,
MustUse { .. } => Yes,
Naked(..) => No,
NeedsAllocator => No,
NoCore(..) => No,
NoImplicitPrelude(..) => No,
NoLink => No,

View file

@ -742,7 +742,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
proc_macro_data,
debugger_visualizers,
compiler_builtins: ast::attr::contains_name(attrs, sym::compiler_builtins),
needs_allocator: ast::attr::contains_name(attrs, sym::needs_allocator),
needs_allocator: find_attr!(attrs, AttributeKind::NeedsAllocator),
needs_panic_runtime: ast::attr::contains_name(attrs, sym::needs_panic_runtime),
no_builtins: ast::attr::contains_name(attrs, sym::no_builtins),
panic_runtime: ast::attr::contains_name(attrs, sym::panic_runtime),

View file

@ -1086,6 +1086,11 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
let Some((name, decl_span)) = self.checked_places.names[index] else { continue };
// By convention, underscore-prefixed bindings are explicitly allowed to be unused.
if name.as_str().starts_with('_') {
continue;
}
let is_maybe_drop_guard = maybe_drop_guard(
tcx,
self.typing_env,

View file

@ -315,6 +315,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::RustcDumpPredicates
| AttributeKind::RustcDumpDefParents
| AttributeKind::RustcDumpVtable(..)
| AttributeKind::NeedsAllocator
) => { /* do nothing */ }
Attribute::Unparsed(attr_item) => {
style = Some(attr_item.style);
@ -346,7 +347,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| sym::prelude_import
| sym::panic_handler
| sym::lang
| sym::needs_allocator
| sym::default_lib_allocator
| sym::rustc_diagnostic_item
| sym::rustc_no_mir_inline

View file

@ -590,12 +590,12 @@ symbols! {
binaryheap_iter,
bind_by_move_pattern_guards,
bindings_after_at,
bit_width,
bitand,
bitand_assign,
bitor,
bitor_assign,
bitreverse,
bits,
bitxor,
bitxor_assign,
black_box,

View file

@ -184,7 +184,7 @@ impl Global {
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
fn alloc_impl_runtime(layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
match layout.size() {
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)),
// SAFETY: `layout` is non-zero in size,
size => unsafe {
let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) };
@ -277,7 +277,7 @@ impl Global {
// SAFETY: conditions must be upheld by the caller
0 => unsafe {
self.deallocate(ptr, old_layout);
Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0))
Ok(NonNull::slice_from_raw_parts(new_layout.dangling_ptr(), 0))
},
// SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
@ -368,7 +368,7 @@ impl Global {
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
const fn alloc_impl_const(layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
match layout.size() {
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)),
// SAFETY: `layout` is non-zero in size,
size => unsafe {
let raw_ptr = core::intrinsics::const_allocate(layout.size(), layout.align());

View file

@ -834,7 +834,7 @@ impl<T: ?Sized + CloneToUninit, A: Allocator> Box<T, A> {
}
let layout = Layout::for_value::<T>(src);
let (ptr, guard) = if layout.size() == 0 {
(layout.dangling(), None)
(layout.dangling_ptr(), None)
} else {
// Safety: layout is non-zero-sized
let ptr = alloc.allocate(layout)?.cast();

View file

@ -245,7 +245,7 @@ impl<H> WithHeader<H> {
// Some paranoia checking, mostly so that the ThinBox tests are
// more able to catch issues.
debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST);
layout.dangling()
layout.dangling_ptr()
} else {
let ptr = alloc::alloc(layout);
if ptr.is_null() {
@ -282,7 +282,7 @@ impl<H> WithHeader<H> {
// Some paranoia checking, mostly so that the ThinBox tests are
// more able to catch issues.
debug_assert!(value_offset == 0 && size_of::<T>() == 0 && size_of::<H>() == 0);
layout.dangling()
layout.dangling_ptr()
} else {
let ptr = alloc::alloc(layout);
if ptr.is_null() {

View file

@ -86,7 +86,6 @@
// Library features:
// tidy-alphabetical-start
#![cfg_attr(not(no_global_oom_handling), feature(string_replace_in_place))]
#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
#![feature(array_into_iter_constructors)]
#![feature(ascii_char)]

View file

@ -261,7 +261,7 @@ use core::panic::{RefUnwindSafe, UnwindSafe};
#[cfg(not(no_global_oom_handling))]
use core::pin::Pin;
use core::pin::PinCoerceUnsized;
use core::ptr::{self, NonNull, drop_in_place};
use core::ptr::{self, Alignment, NonNull, drop_in_place};
#[cfg(not(no_global_oom_handling))]
use core::slice::from_raw_parts_mut;
use core::{borrow, fmt, hint};
@ -3847,11 +3847,11 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize {
// and extern types, the input safety requirement is currently enough to
// satisfy the requirements of align_of_val_raw; this is an implementation
// detail of the language that must not be relied upon outside of std.
unsafe { data_offset_align(align_of_val_raw(ptr)) }
unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) }
}
#[inline]
fn data_offset_align(align: usize) -> usize {
fn data_offset_align(align: Alignment) -> usize {
let layout = Layout::new::<RcInner<()>>();
layout.size() + layout.padding_needed_for(align)
}
@ -4478,7 +4478,7 @@ impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> {
/// Returns the pointer to be written into to initialize the [`Rc`].
fn data_ptr(&mut self) -> *mut T {
let offset = data_offset_align(self.layout_for_value.align());
let offset = data_offset_align(self.layout_for_value.alignment());
unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T }
}

View file

@ -26,7 +26,7 @@ use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Lega
use core::ops::{Residual, Try};
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::pin::{Pin, PinCoerceUnsized};
use core::ptr::{self, NonNull};
use core::ptr::{self, Alignment, NonNull};
#[cfg(not(no_global_oom_handling))]
use core::slice::from_raw_parts_mut;
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release};
@ -4208,11 +4208,11 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize {
// and extern types, the input safety requirement is currently enough to
// satisfy the requirements of align_of_val_raw; this is an implementation
// detail of the language that must not be relied upon outside of std.
unsafe { data_offset_align(align_of_val_raw(ptr)) }
unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) }
}
#[inline]
fn data_offset_align(align: usize) -> usize {
fn data_offset_align(align: Alignment) -> usize {
let layout = Layout::new::<ArcInner<()>>();
layout.size() + layout.padding_needed_for(align)
}
@ -4258,7 +4258,7 @@ impl<T: ?Sized, A: Allocator> UniqueArcUninit<T, A> {
/// Returns the pointer to be written into to initialize the [`Arc`].
fn data_ptr(&mut self) -> *mut T {
let offset = data_offset_align(self.layout_for_value.align());
let offset = data_offset_align(self.layout_for_value.alignment());
unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T }
}

View file

@ -14,7 +14,6 @@
//
// Library features:
// tidy-alphabetical-start
#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
#![feature(array_into_iter_constructors)]
#![feature(assert_matches)]

View file

@ -104,7 +104,7 @@ pub struct ConstAllocator;
unsafe impl Allocator for ConstAllocator {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
match layout.size() {
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)),
_ => unsafe {
let ptr = core::intrinsics::const_allocate(layout.size(), layout.align());
Ok(NonNull::new_unchecked(ptr as *mut [u8; 0] as *mut [u8]))

View file

@ -1,5 +1,4 @@
#![feature(allocator_api)]
#![feature(alloc_layout_extra)]
#![feature(const_heap)]
#![feature(deque_extend_front)]
#![feature(iter_array_chunks)]

View file

@ -217,10 +217,11 @@ impl Layout {
/// be that of a valid pointer, which means this must not be used
/// as a "not yet initialized" sentinel value.
/// Types that lazily allocate must track initialization by some other means.
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
#[stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[must_use]
#[inline]
pub const fn dangling(&self) -> NonNull<u8> {
pub const fn dangling_ptr(&self) -> NonNull<u8> {
NonNull::without_provenance(self.align.as_nonzero())
}
@ -250,29 +251,23 @@ impl Layout {
}
/// Returns the amount of padding we must insert after `self`
/// to ensure that the following address will satisfy `align`
/// (measured in bytes).
/// to ensure that the following address will satisfy `alignment`.
///
/// e.g., if `self.size()` is 9, then `self.padding_needed_for(4)`
/// e.g., if `self.size()` is 9, then `self.padding_needed_for(alignment4)`
/// (where `alignment4.as_usize() == 4`)
/// returns 3, because that is the minimum number of bytes of
/// padding required to get a 4-aligned address (assuming that the
/// corresponding memory block starts at a 4-aligned address).
///
/// The return value of this function has no meaning if `align` is
/// not a power-of-two.
///
/// Note that the utility of the returned value requires `align`
/// Note that the utility of the returned value requires `alignment`
/// to be less than or equal to the alignment of the starting
/// address for the whole allocated block of memory. One way to
/// satisfy this constraint is to ensure `align <= self.align()`.
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
#[must_use = "this returns the padding needed, \
without modifying the `Layout`"]
/// satisfy this constraint is to ensure `alignment.as_usize() <= self.align()`.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[must_use = "this returns the padding needed, without modifying the `Layout`"]
#[inline]
pub const fn padding_needed_for(&self, align: usize) -> usize {
// FIXME: Can we just change the type on this to `Alignment`?
let Some(align) = Alignment::new(align) else { return usize::MAX };
let len_rounded_up = self.size_rounded_up_to_custom_align(align);
pub const fn padding_needed_for(&self, alignment: Alignment) -> usize {
let len_rounded_up = self.size_rounded_up_to_custom_align(alignment);
// SAFETY: Cannot overflow because the rounded-up value is never less
unsafe { unchecked_sub(len_rounded_up, self.size) }
}
@ -335,6 +330,8 @@ impl Layout {
/// layout of the array and `offs` is the distance between the start
/// of each element in the array.
///
/// Does not include padding after the trailing element.
///
/// (That distance between elements is sometimes known as "stride".)
///
/// On arithmetic overflow, returns `LayoutError`.
@ -342,7 +339,6 @@ impl Layout {
/// # Examples
///
/// ```
/// #![feature(alloc_layout_extra)]
/// use std::alloc::Layout;
///
/// // All rust types have a size that's a multiple of their alignment.
@ -353,17 +349,32 @@ impl Layout {
/// // But you can manually make layouts which don't meet that rule.
/// let padding_needed = Layout::from_size_align(6, 4).unwrap();
/// let repeated = padding_needed.repeat(3).unwrap();
/// assert_eq!(repeated, (Layout::from_size_align(24, 4).unwrap(), 8));
/// assert_eq!(repeated, (Layout::from_size_align(22, 4).unwrap(), 8));
///
/// // Repeating an element zero times has zero size, but keeps the alignment (like `[T; 0]`)
/// let repeated = normal.repeat(0).unwrap();
/// assert_eq!(repeated, (Layout::from_size_align(0, 4).unwrap(), 12));
/// let repeated = padding_needed.repeat(0).unwrap();
/// assert_eq!(repeated, (Layout::from_size_align(0, 4).unwrap(), 8));
/// ```
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
#[stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> {
// FIXME(const-hack): the following could be way shorter with `?`
let padded = self.pad_to_align();
if let Ok(repeated) = padded.repeat_packed(n) {
Ok((repeated, padded.size()))
let Ok(result) = (if let Some(k) = n.checked_sub(1) {
let Ok(repeated) = padded.repeat_packed(k) else {
return Err(LayoutError);
};
repeated.extend_packed(*self)
} else {
Err(LayoutError)
}
debug_assert!(n == 0);
self.repeat_packed(0)
}) else {
return Err(LayoutError);
};
Ok((result, padded.size()))
}
/// Creates a layout describing the record for `self` followed by
@ -443,7 +454,8 @@ impl Layout {
/// aligned.
///
/// On arithmetic overflow, returns `LayoutError`.
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
#[stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> {
if let Some(size) = self.size.checked_mul(n) {
@ -460,7 +472,8 @@ impl Layout {
/// and is not incorporated *at all* into the resulting layout.
///
/// On arithmetic overflow, returns `LayoutError`.
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
#[stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> {
// SAFETY: each `size` is at most `isize::MAX == usize::MAX/2`, so the

View file

@ -114,7 +114,7 @@ pub struct Char {
#[unstable(feature = "type_info", issue = "146922")]
pub struct Int {
/// The bit width of the signed integer type.
pub bit_width: usize,
pub bits: u32,
/// Whether the integer type is signed.
pub signed: bool,
}
@ -125,7 +125,7 @@ pub struct Int {
#[unstable(feature = "type_info", issue = "146922")]
pub struct Float {
/// The bit width of the floating-point type.
pub bit_width: usize,
pub bits: u32,
}
/// Compile-time type information about string slice types.

View file

@ -93,6 +93,28 @@ macro_rules! uint_impl {
#[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")]
/// assert_eq!(max.count_zeros(), 0);
/// ```
///
/// This is heavily dependent on the width of the type, and thus
/// might give surprising results depending on type inference:
/// ```
/// # fn foo(_: u8) {}
/// # fn bar(_: u16) {}
/// let lucky = 7;
/// foo(lucky);
/// assert_eq!(lucky.count_zeros(), 5);
/// assert_eq!(lucky.count_ones(), 3);
///
/// let lucky = 7;
/// bar(lucky);
/// assert_eq!(lucky.count_zeros(), 13);
/// assert_eq!(lucky.count_ones(), 3);
/// ```
/// You might want to use [`Self::count_ones`] instead, or emphasize
/// the type you're using in the call rather than method syntax:
/// ```
/// let small = 1;
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::count_zeros(small), ", stringify!($BITS_MINUS_ONE) ,");")]
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_math", since = "1.32.0")]
#[must_use = "this returns the result of the operation, \

View file

@ -6,7 +6,7 @@ fn const_unchecked_layout() {
const SIZE: usize = 0x2000;
const ALIGN: usize = 0x1000;
const LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(SIZE, ALIGN) };
const DANGLING: NonNull<u8> = LAYOUT.dangling();
const DANGLING: NonNull<u8> = LAYOUT.dangling_ptr();
assert_eq!(LAYOUT.size(), SIZE);
assert_eq!(LAYOUT.align(), ALIGN);
assert_eq!(Some(DANGLING), NonNull::new(ptr::without_provenance_mut(ALIGN)));

View file

@ -1,7 +1,6 @@
// tidy-alphabetical-start
#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
#![cfg_attr(test, feature(cfg_select))]
#![feature(alloc_layout_extra)]
#![feature(array_ptr_get)]
#![feature(array_try_from_fn)]
#![feature(array_try_map)]

View file

@ -47,8 +47,8 @@ fn test_tuples() {
match (a.ty.info().kind, b.ty.info().kind) {
(TypeKind::Int(a), TypeKind::Int(b)) => {
assert!(a.bit_width == 8 && a.signed);
assert!(b.bit_width == 8 && !b.signed);
assert!(a.bits == 8 && a.signed);
assert!(b.bits == 8 && !b.signed);
}
_ => unreachable!(),
}
@ -70,27 +70,27 @@ fn test_primitives() {
let Type { kind: Int(ty), size, .. } = (const { Type::of::<i32>() }) else { panic!() };
assert_eq!(size, Some(4));
assert_eq!(ty.bit_width, 32);
assert_eq!(ty.bits, 32);
assert!(ty.signed);
let Type { kind: Int(ty), size, .. } = (const { Type::of::<isize>() }) else { panic!() };
assert_eq!(size, Some(size_of::<isize>()));
assert_eq!(ty.bit_width, size_of::<isize>() * 8);
assert_eq!(ty.bits as usize, size_of::<isize>() * 8);
assert!(ty.signed);
let Type { kind: Int(ty), size, .. } = (const { Type::of::<u32>() }) else { panic!() };
assert_eq!(size, Some(4));
assert_eq!(ty.bit_width, 32);
assert_eq!(ty.bits, 32);
assert!(!ty.signed);
let Type { kind: Int(ty), size, .. } = (const { Type::of::<usize>() }) else { panic!() };
assert_eq!(size, Some(size_of::<usize>()));
assert_eq!(ty.bit_width, size_of::<usize>() * 8);
assert_eq!(ty.bits as usize, size_of::<usize>() * 8);
assert!(!ty.signed);
let Type { kind: Float(ty), size, .. } = (const { Type::of::<f32>() }) else { panic!() };
assert_eq!(size, Some(4));
assert_eq!(ty.bit_width, 32);
assert_eq!(ty.bits, 32);
let Type { kind: Str(_ty), size, .. } = (const { Type::of::<str>() }) else { panic!() };
assert_eq!(size, None);

View file

@ -142,7 +142,7 @@ impl System {
#[inline]
fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
match layout.size() {
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)),
// SAFETY: `layout` is non-zero in size,
size => unsafe {
let raw_ptr = if zeroed {
@ -266,7 +266,7 @@ unsafe impl Allocator for System {
// SAFETY: conditions must be upheld by the caller
0 => unsafe {
Allocator::deallocate(self, ptr, old_layout);
Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0))
Ok(NonNull::slice_from_raw_parts(new_layout.dangling_ptr(), 0))
},
// SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller

View file

@ -367,7 +367,6 @@
//
// Library features (alloc):
// tidy-alphabetical-start
#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
#![feature(clone_from_ref)]
#![feature(get_mut_unchecked)]

View file

@ -682,6 +682,56 @@ impl SystemTime {
pub fn checked_sub(&self, duration: Duration) -> Option<SystemTime> {
self.0.checked_sub_duration(&duration).map(SystemTime)
}
/// Saturating [`SystemTime`] addition, computing `self + duration`,
/// returning [`SystemTime::MAX`] if overflow occurred.
///
/// In the case that the `duration` is smaller than the time precision of
/// the operating system, `self` will be returned.
#[unstable(feature = "time_saturating_systemtime", issue = "151199")]
pub fn saturating_add(&self, duration: Duration) -> SystemTime {
self.checked_add(duration).unwrap_or(SystemTime::MAX)
}
/// Saturating [`SystemTime`] subtraction, computing `self - duration`,
/// returning [`SystemTime::MIN`] if overflow occurred.
///
/// In the case that the `duration` is smaller than the time precision of
/// the operating system, `self` will be returned.
#[unstable(feature = "time_saturating_systemtime", issue = "151199")]
pub fn saturating_sub(&self, duration: Duration) -> SystemTime {
self.checked_sub(duration).unwrap_or(SystemTime::MIN)
}
/// Saturating computation of time elapsed from an earlier point in time,
/// returning [`Duration::ZERO`] in the case that `earlier` is later or
/// equal to `self`.
///
/// # Examples
///
/// ```no_run
/// #![feature(time_saturating_systemtime)]
/// use std::time::{Duration, SystemTime};
///
/// let now = SystemTime::now();
/// let prev = now.saturating_sub(Duration::new(1, 0));
///
/// // now - prev should return non-zero.
/// assert_eq!(now.saturating_duration_since(prev), Duration::new(1, 0));
/// assert!(now.duration_since(prev).is_ok());
///
/// // prev - now should return zero (and fail with the non-saturating).
/// assert_eq!(prev.saturating_duration_since(now), Duration::ZERO);
/// assert!(prev.duration_since(now).is_err());
///
/// // now - now should return zero (and work with the non-saturating).
/// assert_eq!(now.saturating_duration_since(now), Duration::ZERO);
/// assert!(now.duration_since(now).is_ok());
/// ```
#[unstable(feature = "time_saturating_systemtime", issue = "151199")]
pub fn saturating_duration_since(&self, earlier: SystemTime) -> Duration {
self.duration_since(earlier).unwrap_or(Duration::ZERO)
}
}
#[stable(feature = "time2", since = "1.8.0")]

View file

@ -1,5 +1,6 @@
#![feature(duration_constants)]
#![feature(time_systemtime_limits)]
#![feature(time_saturating_systemtime)]
use std::fmt::Debug;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
@ -269,3 +270,41 @@ fn system_time_max_min() {
assert!(SystemTime::MIN.checked_add(MIN_INTERVAL).is_some());
assert!(SystemTime::MIN.checked_sub(MIN_INTERVAL).is_none());
}
#[test]
fn system_time_saturating() {
// Perform saturating addition on SystemTime::MAX to see how it behaves.
assert_eq!(SystemTime::MAX.saturating_add(Duration::ZERO), SystemTime::MAX);
assert_eq!(SystemTime::MAX.saturating_add(Duration::new(1, 0)), SystemTime::MAX);
assert!(SystemTime::MAX.checked_add(Duration::new(1, 0)).is_none());
assert_eq!(
SystemTime::MAX.saturating_sub(Duration::new(1, 0)),
SystemTime::MAX.checked_sub(Duration::new(1, 0)).unwrap()
);
// Perform saturating subtraction on SystemTime::MIn to see how it behaves.
assert_eq!(SystemTime::MIN.saturating_sub(Duration::ZERO), SystemTime::MIN);
assert_eq!(SystemTime::MIN.saturating_sub(Duration::new(1, 0)), SystemTime::MIN);
assert!(SystemTime::MIN.checked_sub(Duration::new(1, 0)).is_none());
assert_eq!(
SystemTime::MIN.saturating_add(Duration::new(1, 0)),
SystemTime::MIN.checked_add(Duration::new(1, 0)).unwrap()
);
// Check saturating_duration_since with various constant values.
assert!(SystemTime::MAX.saturating_duration_since(SystemTime::MIN) >= Duration::ZERO);
assert_eq!(SystemTime::MAX.saturating_duration_since(SystemTime::MAX), Duration::ZERO);
assert!(SystemTime::MAX.duration_since(SystemTime::MAX).is_ok());
assert_eq!(SystemTime::MIN.saturating_duration_since(SystemTime::MAX), Duration::ZERO);
assert!(SystemTime::MIN.duration_since(SystemTime::MAX).is_err());
assert_eq!(
(SystemTime::UNIX_EPOCH + Duration::new(1, 0))
.saturating_duration_since(SystemTime::UNIX_EPOCH),
Duration::new(1, 0)
);
assert_eq!(
SystemTime::UNIX_EPOCH
.saturating_duration_since(SystemTime::UNIX_EPOCH + Duration::new(1, 0)),
Duration::ZERO
);
}

View file

@ -0,0 +1,29 @@
//@ check-pass
#![deny(unused_assignments)]
fn lock() -> impl Drop {
struct Handle;
impl Drop for Handle {
fn drop(&mut self) {}
}
Handle
}
fn bar(_f: impl FnMut(bool)) {}
pub fn foo() {
let mut _handle = None;
bar(move |l| {
if l {
_handle = Some(lock());
} else {
_handle = None;
}
})
}
fn main() {
foo();
}

View file

@ -35,7 +35,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 8,
bits: 8,
signed: true,
},
),
@ -46,7 +46,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 32,
bits: 32,
signed: true,
},
),
@ -57,7 +57,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 64,
bits: 64,
signed: true,
},
),
@ -68,7 +68,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 128,
bits: 128,
signed: true,
},
),
@ -79,7 +79,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 32,
bits: 32,
signed: true,
},
),
@ -90,7 +90,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 8,
bits: 8,
signed: false,
},
),
@ -101,7 +101,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 32,
bits: 32,
signed: false,
},
),
@ -112,7 +112,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 64,
bits: 64,
signed: false,
},
),
@ -123,7 +123,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 128,
bits: 128,
signed: false,
},
),
@ -134,7 +134,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 32,
bits: 32,
signed: false,
},
),

View file

@ -35,7 +35,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 8,
bits: 8,
signed: true,
},
),
@ -46,7 +46,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 32,
bits: 32,
signed: true,
},
),
@ -57,7 +57,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 64,
bits: 64,
signed: true,
},
),
@ -68,7 +68,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 128,
bits: 128,
signed: true,
},
),
@ -79,7 +79,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 64,
bits: 64,
signed: true,
},
),
@ -90,7 +90,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 8,
bits: 8,
signed: false,
},
),
@ -101,7 +101,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 32,
bits: 32,
signed: false,
},
),
@ -112,7 +112,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 64,
bits: 64,
signed: false,
},
),
@ -123,7 +123,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 128,
bits: 128,
signed: false,
},
),
@ -134,7 +134,7 @@ Type {
Type {
kind: Int(
Int {
bit_width: 64,
bits: 64,
signed: false,
},
),