Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add contracts for all functions in Alignment #136578

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -108,6 +108,7 @@
//
// Library features:
// tidy-alphabetical-start
#![cfg_attr(not(bootstrap), feature(contracts))]
#![feature(array_ptr_get)]
#![feature(asm_experimental_arch)]
#![feature(bigint_helper_methods)]
2 changes: 2 additions & 0 deletions library/core/src/mem/mod.rs
Original file line number Diff line number Diff line change
@@ -476,6 +476,8 @@ pub const fn align_of<T>() -> usize {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_align_of_val", since = "1.85.0")]
#[allow(deprecated)]
#[rustc_allow_const_fn_unstable(contracts)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should add rustc_const_stable_indirect to contract functions instead. @rust-lang/wg-const-eval?

Copy link
Member

@RalfJung RalfJung Mar 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which functions would that affect?

Ah, #136925 anyway needs to be resolved first.

#[cfg_attr(not(bootstrap), core::contracts::ensures(|result: &usize| result.is_power_of_two()))]
pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
// SAFETY: val is a reference, so it's a valid raw pointer
unsafe { intrinsics::min_align_of_val(val) }
34 changes: 34 additions & 0 deletions library/core/src/ptr/alignment.rs
Original file line number Diff line number Diff line change
@@ -43,6 +43,9 @@ impl Alignment {
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[must_use]
#[rustc_allow_const_fn_unstable(contracts)]
#[cfg_attr(not(bootstrap), core::contracts::ensures(
|result: &Alignment| result.as_usize().is_power_of_two()))]
pub const fn of<T>() -> Self {
// This can't actually panic since type alignment is always a power of two.
const { Alignment::new(align_of::<T>()).unwrap() }
@@ -54,6 +57,11 @@ impl Alignment {
/// Note that `0` is not a power of two, nor a valid alignment.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[rustc_allow_const_fn_unstable(contracts)]
#[cfg_attr(not(bootstrap), core::contracts::ensures(
move
|result: &Option<Alignment>| align.is_power_of_two() == result.is_some() &&
(result.is_none() || result.unwrap().as_usize() == align)))]
pub const fn new(align: usize) -> Option<Self> {
if align.is_power_of_two() {
// SAFETY: Just checked it only has one bit set
@@ -73,6 +81,12 @@ impl Alignment {
/// It must *not* be zero.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[cfg_attr(not(bootstrap), rustc_const_unstable(feature = "contracts", issue = "128044"))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't feel right. I don't think you should add rustc_const_unstable here and below.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I don't do this I get:

error: const function that might be (indirectly) exposed to stable cannot use `#[feature(contracts)]`
  --> library/core/src/ptr/alignment.rs:82:5
   |
82 | /     #[cfg_attr(not(bootstrap), core::contracts::ensures(
83 | |             |result: &Alignment| result.as_usize() == align &&
84 | |             result.as_usize().is_power_of_two()))]
   | |__________________________________________________^
   |
help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
   |
82 +     #[rustc_const_unstable(feature = "...", issue = "...")]
83 |     #[cfg_attr(not(bootstrap), core::contracts::ensures(
   |
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
   |
82 +     #[rustc_allow_const_fn_unstable(contracts)]
83 |     #[cfg_attr(not(bootstrap), core::contracts::ensures(
   |

#[cfg_attr(not(bootstrap), core::contracts::requires(align.is_power_of_two()))]
#[cfg_attr(not(bootstrap), core::contracts::ensures(
move
|result: &Alignment| result.as_usize() == align &&
result.as_usize().is_power_of_two()))]
pub const unsafe fn new_unchecked(align: usize) -> Self {
assert_unsafe_precondition!(
check_language_ub,
@@ -88,13 +102,21 @@ impl Alignment {
/// Returns the alignment as a [`usize`].
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[rustc_allow_const_fn_unstable(contracts)]
#[cfg_attr(not(bootstrap), core::contracts::ensures(
|result: &usize| result.is_power_of_two()))]
pub const fn as_usize(self) -> usize {
self.0 as usize
}

/// Returns the alignment as a <code>[NonZero]<[usize]></code>.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[rustc_allow_const_fn_unstable(contracts)]
#[cfg_attr(not(bootstrap), core::contracts::ensures(
move
|result: &NonZero<usize>| result.get().is_power_of_two() &&
result.get() == self.as_usize()))]
pub const fn as_nonzero(self) -> NonZero<usize> {
// This transmutes directly to avoid the UbCheck in `NonZero::new_unchecked`
// since there's no way for the user to trip that check anyway -- the
@@ -120,6 +142,12 @@ impl Alignment {
/// ```
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[cfg_attr(not(bootstrap), rustc_const_unstable(feature = "contracts", issue = "128044"))]
#[cfg_attr(not(bootstrap), core::contracts::requires(self.as_usize().is_power_of_two()))]
#[cfg_attr(not(bootstrap), core::contracts::ensures(
move
|result: &u32| *result < usize::BITS &&
(1usize << *result) == self.as_usize()))]
pub const fn log2(self) -> u32 {
self.as_nonzero().trailing_zeros()
}
@@ -149,6 +177,12 @@ impl Alignment {
/// ```
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[cfg_attr(not(bootstrap), rustc_const_unstable(feature = "contracts", issue = "128044"))]
#[cfg_attr(not(bootstrap), core::contracts::ensures(
move
|result: &usize| *result > 0 &&
*result == !(self.as_usize() -1) &&
self.as_usize() & *result == self.as_usize()))]
pub const fn mask(self) -> usize {
// SAFETY: The alignment is always nonzero, and therefore decrementing won't overflow.
!(unsafe { self.as_usize().unchecked_sub(1) })
Loading