Skip to content
Open
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2647,6 +2647,7 @@ pub const unsafe fn const_make_global(ptr: *mut u8) -> *const u8 {
// doesn't honor `#[allow_internal_unstable]`, so for the const feature gate we use the user-facing
// `contracts` feature rather than the perma-unstable `contracts_internals`
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
#[miri::intrinsic_fallback_is_spec]
Copy link
Member

Choose a reason for hiding this comment

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

It seems that no backend actually overwrites this intrinsic. Why is it an intrinsic in the first place...? (Same for contract_check_ensures.)

Copy link
Contributor

Choose a reason for hiding this comment

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

Other verification tools might tho. I need to ping the compiler team about design review of the existing design and long term solution.

#[lang = "contract_check_requires"]
#[rustc_intrinsic]
pub const fn contract_check_requires<C: Fn() -> bool + Copy>(cond: C) {
Expand Down Expand Up @@ -2676,6 +2677,7 @@ pub const fn contract_check_requires<C: Fn() -> bool + Copy>(cond: C) {
// `contracts` feature rather than the perma-unstable `contracts_internals`.
// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion.
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
#[miri::intrinsic_fallback_is_spec]
#[lang = "contract_check_ensures"]
#[rustc_intrinsic]
pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(
Expand Down
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
#![feature(const_destruct)]
#![feature(const_eval_select)]
#![feature(const_select_unpredictable)]
#![feature(contracts)]
#![feature(core_intrinsics)]
#![feature(coverage_attribute)]
#![feature(disjoint_bitor)]
Expand Down
2 changes: 2 additions & 0 deletions library/core/src/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,8 @@ pub const fn align_of<T>() -> usize {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_align_of_val", since = "1.85.0")]
#[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.

Copy link
Member

Choose a reason for hiding this comment

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

I'd still like to find a solution that does not require rustc_allow_const_fn_unstable. As @celinval suggested, we should try to mark the contract functions as #[rustc_const_stable_indirect]; if that works, that's a better solution.

Copy link
Contributor

Choose a reason for hiding this comment

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

@tautschnig did you try to make this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I finally tried adding #[rustc_const_stable_indirect] to contract_check_ensures. Yet I then got:

error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_eval_select)]`
    --> library/core/src/intrinsics/mod.rs:2439:9
[...]
help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]`
     |
2684 + #[rustc_const_unstable(feature = "...", issue = "...")]
2685 | pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(
     |

where the proposed fix won't actually work as the function is already marked with rustc_const_unstable.

#[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::align_of_val(val) }
Expand Down
28 changes: 28 additions & 0 deletions library/core/src/ptr/alignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ impl Alignment {
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[must_use]
#[rustc_allow_const_fn_unstable(contracts)]
#[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() }
Expand All @@ -56,6 +58,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)]
#[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
Expand All @@ -76,6 +83,11 @@ impl Alignment {
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[track_caller]
#[rustc_allow_const_fn_unstable(contracts)]
#[core::contracts::requires(align.is_power_of_two())]
#[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,
Expand All @@ -91,13 +103,19 @@ impl Alignment {
/// Returns the alignment as a [`usize`].
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[rustc_allow_const_fn_unstable(contracts)]
#[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)]
#[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
Expand All @@ -123,6 +141,11 @@ impl Alignment {
/// ```
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
#[core::contracts::requires(self.as_usize().is_power_of_two())]
#[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()
}
Expand Down Expand Up @@ -152,6 +175,11 @@ impl Alignment {
/// ```
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
#[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) })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,37 @@
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let mut _6: std::num::NonZero<usize>;
scope 6 {
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
scope 12 (inlined std::ptr::Alignment::as_nonzero) {
scope 13 {
scope 14 {
scope 15 {
}
}
}
scope 16 (inlined core::contracts::build_check_ensures::<NonZero<usize>, {closure@std::ptr::Alignment::as_nonzero::{closure#0}}>) {
}
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
scope 17 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _7: *const [bool; 0];
scope 10 {
scope 18 {
}
scope 11 (inlined NonZero::<usize>::get) {
scope 19 (inlined NonZero::<usize>::get) {
}
scope 12 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 13 (inlined without_provenance_mut::<[bool; 0]>) {
scope 20 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 21 (inlined without_provenance_mut::<[bool; 0]>) {
}
}
}
}
scope 7 (inlined std::ptr::Alignment::of::<[bool; 0]>) {
scope 8 {
scope 9 {
scope 10 {
}
}
}
scope 11 (inlined core::contracts::build_check_ensures::<std::ptr::Alignment, {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}>) {
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,37 @@
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let mut _6: std::num::NonZero<usize>;
scope 6 {
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
scope 12 (inlined std::ptr::Alignment::as_nonzero) {
scope 13 {
scope 14 {
scope 15 {
}
}
}
scope 16 (inlined core::contracts::build_check_ensures::<NonZero<usize>, {closure@std::ptr::Alignment::as_nonzero::{closure#0}}>) {
}
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
scope 17 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _7: *const [bool; 0];
scope 10 {
scope 18 {
}
scope 11 (inlined NonZero::<usize>::get) {
scope 19 (inlined NonZero::<usize>::get) {
}
scope 12 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 13 (inlined without_provenance_mut::<[bool; 0]>) {
scope 20 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 21 (inlined without_provenance_mut::<[bool; 0]>) {
}
}
}
}
scope 7 (inlined std::ptr::Alignment::of::<[bool; 0]>) {
scope 8 {
scope 9 {
scope 10 {
}
}
}
scope 11 (inlined core::contracts::build_check_ensures::<std::ptr::Alignment, {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}>) {
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,37 @@
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let mut _6: std::num::NonZero<usize>;
scope 6 {
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
scope 12 (inlined std::ptr::Alignment::as_nonzero) {
scope 13 {
scope 14 {
scope 15 {
}
}
}
scope 16 (inlined core::contracts::build_check_ensures::<NonZero<usize>, {closure@std::ptr::Alignment::as_nonzero::{closure#0}}>) {
}
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
scope 17 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _7: *const [bool; 0];
scope 10 {
scope 18 {
}
scope 11 (inlined NonZero::<usize>::get) {
scope 19 (inlined NonZero::<usize>::get) {
}
scope 12 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 13 (inlined without_provenance_mut::<[bool; 0]>) {
scope 20 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 21 (inlined without_provenance_mut::<[bool; 0]>) {
}
}
}
}
scope 7 (inlined std::ptr::Alignment::of::<[bool; 0]>) {
scope 8 {
scope 9 {
scope 10 {
}
}
}
scope 11 (inlined core::contracts::build_check_ensures::<std::ptr::Alignment, {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}>) {
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,37 @@
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let mut _6: std::num::NonZero<usize>;
scope 6 {
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
scope 12 (inlined std::ptr::Alignment::as_nonzero) {
scope 13 {
scope 14 {
scope 15 {
}
}
}
scope 16 (inlined core::contracts::build_check_ensures::<NonZero<usize>, {closure@std::ptr::Alignment::as_nonzero::{closure#0}}>) {
}
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
scope 17 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _7: *const [bool; 0];
scope 10 {
scope 18 {
}
scope 11 (inlined NonZero::<usize>::get) {
scope 19 (inlined NonZero::<usize>::get) {
}
scope 12 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 13 (inlined without_provenance_mut::<[bool; 0]>) {
scope 20 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 21 (inlined without_provenance_mut::<[bool; 0]>) {
}
}
}
}
scope 7 (inlined std::ptr::Alignment::of::<[bool; 0]>) {
scope 8 {
scope 9 {
scope 10 {
}
}
}
scope 11 (inlined core::contracts::build_check_ensures::<std::ptr::Alignment, {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}>) {
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,37 @@
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let mut _6: std::num::NonZero<usize>;
scope 6 {
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
scope 12 (inlined std::ptr::Alignment::as_nonzero) {
scope 13 {
scope 14 {
scope 15 {
}
}
}
scope 16 (inlined core::contracts::build_check_ensures::<NonZero<usize>, {closure@std::ptr::Alignment::as_nonzero::{closure#0}}>) {
}
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
scope 17 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _7: *const [bool; 0];
scope 10 {
scope 18 {
}
scope 11 (inlined NonZero::<usize>::get) {
scope 19 (inlined NonZero::<usize>::get) {
}
scope 12 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 13 (inlined without_provenance_mut::<[bool; 0]>) {
scope 20 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 21 (inlined without_provenance_mut::<[bool; 0]>) {
}
}
}
}
scope 7 (inlined std::ptr::Alignment::of::<[bool; 0]>) {
scope 8 {
scope 9 {
scope 10 {
}
}
}
scope 11 (inlined core::contracts::build_check_ensures::<std::ptr::Alignment, {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}>) {
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,37 @@
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let mut _6: std::num::NonZero<usize>;
scope 6 {
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
scope 12 (inlined std::ptr::Alignment::as_nonzero) {
scope 13 {
scope 14 {
scope 15 {
}
}
}
scope 16 (inlined core::contracts::build_check_ensures::<NonZero<usize>, {closure@std::ptr::Alignment::as_nonzero::{closure#0}}>) {
}
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
scope 17 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _7: *const [bool; 0];
scope 10 {
scope 18 {
}
scope 11 (inlined NonZero::<usize>::get) {
scope 19 (inlined NonZero::<usize>::get) {
}
scope 12 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 13 (inlined without_provenance_mut::<[bool; 0]>) {
scope 20 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 21 (inlined without_provenance_mut::<[bool; 0]>) {
}
}
}
}
scope 7 (inlined std::ptr::Alignment::of::<[bool; 0]>) {
scope 8 {
scope 9 {
scope 10 {
}
}
}
scope 11 (inlined core::contracts::build_check_ensures::<std::ptr::Alignment, {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}>) {
}
}
}
}
Expand Down
Loading
Loading