Skip to content

Add contracts for all functions in Alignment #136578

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

Draft
wants to merge 4 commits 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
3 changes: 3 additions & 0 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
@@ -3410,6 +3410,7 @@ pub const fn contract_checks() -> bool {
// 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]
#[lang = "contract_check_requires"]
#[rustc_intrinsic]
pub const fn contract_check_requires<C: Fn() -> bool + Copy>(cond: C) {
@@ -3438,6 +3439,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>(cond: C, ret: Ret) -> Ret {
@@ -3459,6 +3461,7 @@ pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(cond: C, re
/// This is the old version of contract_check_ensures kept here for bootstrap only.
#[cfg(bootstrap)]
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
#[miri::intrinsic_fallback_is_spec]
#[rustc_intrinsic]
pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) {
if contract_checks() && !cond(ret) {
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -95,6 +95,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.

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.

#[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(
   |

Copy link
Member

Choose a reason for hiding this comment

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

This is the the same question as #136578 (comment). The error you get from the compiler is different since this function is unstable while align_of_val is stable, but the underlying problem is the same and we should use the same solution.

#[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) })
Original file line number Diff line number Diff line change
@@ -16,23 +16,34 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let mut _6: std::num::NonZero<usize>;
let _6: std::ptr::Alignment;
let mut _7: std::num::NonZero<usize>;
scope 6 {
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
scope 10 (inlined std::ptr::Alignment::as_nonzero) {
let mut _8: {closure@std::ptr::Alignment::as_nonzero::{closure#0}};
let mut _9: std::num::NonZero<usize>;
scope 11 {
}
scope 12 (inlined core::contracts::build_check_ensures::<NonZero<usize>, {closure@std::ptr::Alignment::as_nonzero::{closure#0}}>) {
}
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _7: *const [bool; 0];
scope 10 {
scope 13 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _10: *const [bool; 0];
scope 14 {
}
scope 11 (inlined NonZero::<usize>::get) {
scope 15 (inlined NonZero::<usize>::get) {
}
scope 12 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 13 (inlined without_provenance_mut::<[bool; 0]>) {
scope 16 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 17 (inlined without_provenance_mut::<[bool; 0]>) {
}
}
}
}
scope 7 (inlined std::ptr::Alignment::of::<[bool; 0]>) {
scope 8 {
}
scope 9 (inlined core::contracts::build_check_ensures::<std::ptr::Alignment, {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}>) {
}
}
}
}
@@ -45,33 +56,42 @@
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
_6 = const NonZero::<usize>(core::num::niche_types::NonZeroUsizeInner(1_usize));
_6 = contract_check_ensures::<{closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}, std::ptr::Alignment>(const ZeroSized: {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}, const std::ptr::Alignment::of::<[bool; 0]>::{constant#0}) -> [return: bb2, unwind unreachable];
}

bb1: {
StorageDead(_1);
return;
}

bb2: {
StorageLive(_7);
_7 = const {0x1 as *const [bool; 0]};
_5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
StorageLive(_8);
_8 = {closure@$SRC_DIR/core/src/ptr/alignment.rs:LL:COL} { 0: copy _6 };
StorageLive(_9);
_9 = copy _6 as std::num::NonZero<usize> (Transmute);
_7 = contract_check_ensures::<{closure@std::ptr::Alignment::as_nonzero::{closure#0}}, NonZero<usize>>(move _8, move _9) -> [return: bb3, unwind unreachable];
}

bb3: {
StorageDead(_9);
StorageDead(_8);
StorageLive(_10);
_10 = copy _7 as *const [bool; 0] (Transmute);
_5 = NonNull::<[bool; 0]> { pointer: copy _10 };
StorageDead(_10);
StorageDead(_7);
StorageDead(_6);
_4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
StorageDead(_4);
_2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
_2 = Box::<[bool]>(copy _3, const std::alloc::Global);
StorageDead(_3);
_1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
}

bb1: {
StorageDead(_1);
return;
}
}

ALLOC2 (size: 8, align: 4) { .. }

ALLOC1 (size: 8, align: 4) { .. }

ALLOC0 (size: 8, align: 4) { .. }

Original file line number Diff line number Diff line change
@@ -16,23 +16,34 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let mut _6: std::num::NonZero<usize>;
let _6: std::ptr::Alignment;
let mut _7: std::num::NonZero<usize>;
scope 6 {
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
scope 10 (inlined std::ptr::Alignment::as_nonzero) {
let mut _8: {closure@std::ptr::Alignment::as_nonzero::{closure#0}};
let mut _9: std::num::NonZero<usize>;
scope 11 {
}
scope 12 (inlined core::contracts::build_check_ensures::<NonZero<usize>, {closure@std::ptr::Alignment::as_nonzero::{closure#0}}>) {
}
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _7: *const [bool; 0];
scope 10 {
scope 13 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _10: *const [bool; 0];
scope 14 {
}
scope 11 (inlined NonZero::<usize>::get) {
scope 15 (inlined NonZero::<usize>::get) {
}
scope 12 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 13 (inlined without_provenance_mut::<[bool; 0]>) {
scope 16 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 17 (inlined without_provenance_mut::<[bool; 0]>) {
}
}
}
}
scope 7 (inlined std::ptr::Alignment::of::<[bool; 0]>) {
scope 8 {
}
scope 9 (inlined core::contracts::build_check_ensures::<std::ptr::Alignment, {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}>) {
}
}
}
}
@@ -45,22 +56,7 @@
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
_6 = const NonZero::<usize>(core::num::niche_types::NonZeroUsizeInner(1_usize));
StorageLive(_7);
_7 = const {0x1 as *const [bool; 0]};
_5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
StorageDead(_7);
StorageDead(_6);
_4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
StorageDead(_5);
_3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
StorageDead(_4);
_2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
StorageDead(_3);
_1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
_6 = contract_check_ensures::<{closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}, std::ptr::Alignment>(const ZeroSized: {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}, const std::ptr::Alignment::of::<[bool; 0]>::{constant#0}) -> [return: bb3, unwind continue];
}

bb1: {
@@ -71,11 +67,35 @@
bb2 (cleanup): {
resume;
}
}

ALLOC2 (size: 8, align: 4) { .. }

ALLOC1 (size: 8, align: 4) { .. }
bb3: {
StorageLive(_7);
StorageLive(_8);
_8 = {closure@$SRC_DIR/core/src/ptr/alignment.rs:LL:COL} { 0: copy _6 };
StorageLive(_9);
_9 = copy _6 as std::num::NonZero<usize> (Transmute);
_7 = contract_check_ensures::<{closure@std::ptr::Alignment::as_nonzero::{closure#0}}, NonZero<usize>>(move _8, move _9) -> [return: bb4, unwind continue];
}

ALLOC0 (size: 8, align: 4) { .. }
bb4: {
StorageDead(_9);
StorageDead(_8);
StorageLive(_10);
_10 = copy _7 as *const [bool; 0] (Transmute);
_5 = NonNull::<[bool; 0]> { pointer: copy _10 };
StorageDead(_10);
StorageDead(_7);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
StorageDead(_4);
_2 = Box::<[bool]>(copy _3, const std::alloc::Global);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
}
}

Original file line number Diff line number Diff line change
@@ -16,23 +16,34 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let mut _6: std::num::NonZero<usize>;
let _6: std::ptr::Alignment;
let mut _7: std::num::NonZero<usize>;
scope 6 {
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
scope 10 (inlined std::ptr::Alignment::as_nonzero) {
let mut _8: {closure@std::ptr::Alignment::as_nonzero::{closure#0}};
let mut _9: std::num::NonZero<usize>;
scope 11 {
}
scope 12 (inlined core::contracts::build_check_ensures::<NonZero<usize>, {closure@std::ptr::Alignment::as_nonzero::{closure#0}}>) {
}
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _7: *const [bool; 0];
scope 10 {
scope 13 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _10: *const [bool; 0];
scope 14 {
}
scope 11 (inlined NonZero::<usize>::get) {
scope 15 (inlined NonZero::<usize>::get) {
}
scope 12 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 13 (inlined without_provenance_mut::<[bool; 0]>) {
scope 16 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 17 (inlined without_provenance_mut::<[bool; 0]>) {
}
}
}
}
scope 7 (inlined std::ptr::Alignment::of::<[bool; 0]>) {
scope 8 {
}
scope 9 (inlined core::contracts::build_check_ensures::<std::ptr::Alignment, {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}>) {
}
}
}
}
@@ -45,33 +56,42 @@
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
_6 = const NonZero::<usize>(core::num::niche_types::NonZeroUsizeInner(1_usize));
_6 = contract_check_ensures::<{closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}, std::ptr::Alignment>(const ZeroSized: {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}, const std::ptr::Alignment::of::<[bool; 0]>::{constant#0}) -> [return: bb2, unwind unreachable];
}

bb1: {
StorageDead(_1);
return;
}

bb2: {
StorageLive(_7);
_7 = const {0x1 as *const [bool; 0]};
_5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
StorageLive(_8);
_8 = {closure@$SRC_DIR/core/src/ptr/alignment.rs:LL:COL} { 0: copy _6 };
StorageLive(_9);
_9 = copy _6 as std::num::NonZero<usize> (Transmute);
_7 = contract_check_ensures::<{closure@std::ptr::Alignment::as_nonzero::{closure#0}}, NonZero<usize>>(move _8, move _9) -> [return: bb3, unwind unreachable];
}

bb3: {
StorageDead(_9);
StorageDead(_8);
StorageLive(_10);
_10 = copy _7 as *const [bool; 0] (Transmute);
_5 = NonNull::<[bool; 0]> { pointer: copy _10 };
StorageDead(_10);
StorageDead(_7);
StorageDead(_6);
_4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
StorageDead(_4);
_2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
_2 = Box::<[bool]>(copy _3, const std::alloc::Global);
StorageDead(_3);
_1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
}

bb1: {
StorageDead(_1);
return;
}
}

ALLOC2 (size: 16, align: 8) { .. }

ALLOC1 (size: 16, align: 8) { .. }

ALLOC0 (size: 16, align: 8) { .. }

Original file line number Diff line number Diff line change
@@ -16,23 +16,34 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let mut _6: std::num::NonZero<usize>;
let _6: std::ptr::Alignment;
let mut _7: std::num::NonZero<usize>;
scope 6 {
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
scope 10 (inlined std::ptr::Alignment::as_nonzero) {
let mut _8: {closure@std::ptr::Alignment::as_nonzero::{closure#0}};
let mut _9: std::num::NonZero<usize>;
scope 11 {
}
scope 12 (inlined core::contracts::build_check_ensures::<NonZero<usize>, {closure@std::ptr::Alignment::as_nonzero::{closure#0}}>) {
}
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _7: *const [bool; 0];
scope 10 {
scope 13 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _10: *const [bool; 0];
scope 14 {
}
scope 11 (inlined NonZero::<usize>::get) {
scope 15 (inlined NonZero::<usize>::get) {
}
scope 12 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 13 (inlined without_provenance_mut::<[bool; 0]>) {
scope 16 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 17 (inlined without_provenance_mut::<[bool; 0]>) {
}
}
}
}
scope 7 (inlined std::ptr::Alignment::of::<[bool; 0]>) {
scope 8 {
}
scope 9 (inlined core::contracts::build_check_ensures::<std::ptr::Alignment, {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}>) {
}
}
}
}
@@ -45,40 +56,42 @@
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = const std::ptr::Alignment::of::<[bool; 0]>::{constant#0} as std::num::NonZero<usize> (Transmute);
+ _6 = const NonZero::<usize>(core::num::niche_types::NonZeroUsizeInner(1_usize));
_6 = contract_check_ensures::<{closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}, std::ptr::Alignment>(const ZeroSized: {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}, const std::ptr::Alignment::of::<[bool; 0]>::{constant#0}) -> [return: bb2, unwind unreachable];
}

bb1: {
StorageDead(_1);
return;
}

bb2: {
StorageLive(_7);
- _7 = copy _6 as *const [bool; 0] (Transmute);
- _5 = NonNull::<[bool; 0]> { pointer: copy _7 };
+ _7 = const {0x1 as *const [bool; 0]};
+ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
StorageLive(_8);
_8 = {closure@$SRC_DIR/core/src/ptr/alignment.rs:LL:COL} { 0: copy _6 };
StorageLive(_9);
_9 = copy _6 as std::num::NonZero<usize> (Transmute);
_7 = contract_check_ensures::<{closure@std::ptr::Alignment::as_nonzero::{closure#0}}, NonZero<usize>>(move _8, move _9) -> [return: bb3, unwind unreachable];
}

bb3: {
StorageDead(_9);
StorageDead(_8);
StorageLive(_10);
_10 = copy _7 as *const [bool; 0] (Transmute);
_5 = NonNull::<[bool; 0]> { pointer: copy _10 };
StorageDead(_10);
StorageDead(_7);
StorageDead(_6);
- _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
- _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
StorageDead(_4);
- _2 = Box::<[bool]>(copy _3, const std::alloc::Global);
+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
_2 = Box::<[bool]>(copy _3, const std::alloc::Global);
StorageDead(_3);
- _1 = A { foo: move _2 };
+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
}

bb1: {
StorageDead(_1);
return;
}
}
+
+ ALLOC2 (size: 8, align: 4) { .. }
+
+ ALLOC1 (size: 8, align: 4) { .. }
+
+ ALLOC0 (size: 8, align: 4) { .. }

Original file line number Diff line number Diff line change
@@ -16,23 +16,34 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let mut _6: std::num::NonZero<usize>;
let _6: std::ptr::Alignment;
let mut _7: std::num::NonZero<usize>;
scope 6 {
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
scope 10 (inlined std::ptr::Alignment::as_nonzero) {
let mut _8: {closure@std::ptr::Alignment::as_nonzero::{closure#0}};
let mut _9: std::num::NonZero<usize>;
scope 11 {
}
scope 12 (inlined core::contracts::build_check_ensures::<NonZero<usize>, {closure@std::ptr::Alignment::as_nonzero::{closure#0}}>) {
}
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _7: *const [bool; 0];
scope 10 {
scope 13 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _10: *const [bool; 0];
scope 14 {
}
scope 11 (inlined NonZero::<usize>::get) {
scope 15 (inlined NonZero::<usize>::get) {
}
scope 12 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 13 (inlined without_provenance_mut::<[bool; 0]>) {
scope 16 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 17 (inlined without_provenance_mut::<[bool; 0]>) {
}
}
}
}
scope 7 (inlined std::ptr::Alignment::of::<[bool; 0]>) {
scope 8 {
}
scope 9 (inlined core::contracts::build_check_ensures::<std::ptr::Alignment, {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}>) {
}
}
}
}
@@ -45,29 +56,7 @@
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = const std::ptr::Alignment::of::<[bool; 0]>::{constant#0} as std::num::NonZero<usize> (Transmute);
+ _6 = const NonZero::<usize>(core::num::niche_types::NonZeroUsizeInner(1_usize));
StorageLive(_7);
- _7 = copy _6 as *const [bool; 0] (Transmute);
- _5 = NonNull::<[bool; 0]> { pointer: copy _7 };
+ _7 = const {0x1 as *const [bool; 0]};
+ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
StorageDead(_7);
StorageDead(_6);
- _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
StorageDead(_5);
- _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
StorageDead(_4);
- _2 = Box::<[bool]>(copy _3, const std::alloc::Global);
+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
StorageDead(_3);
- _1 = A { foo: move _2 };
+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
_6 = contract_check_ensures::<{closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}, std::ptr::Alignment>(const ZeroSized: {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}, const std::ptr::Alignment::of::<[bool; 0]>::{constant#0}) -> [return: bb3, unwind continue];
}

bb1: {
@@ -78,11 +67,35 @@
bb2 (cleanup): {
resume;
}

bb3: {
StorageLive(_7);
StorageLive(_8);
_8 = {closure@$SRC_DIR/core/src/ptr/alignment.rs:LL:COL} { 0: copy _6 };
StorageLive(_9);
_9 = copy _6 as std::num::NonZero<usize> (Transmute);
_7 = contract_check_ensures::<{closure@std::ptr::Alignment::as_nonzero::{closure#0}}, NonZero<usize>>(move _8, move _9) -> [return: bb4, unwind continue];
}

bb4: {
StorageDead(_9);
StorageDead(_8);
StorageLive(_10);
_10 = copy _7 as *const [bool; 0] (Transmute);
_5 = NonNull::<[bool; 0]> { pointer: copy _10 };
StorageDead(_10);
StorageDead(_7);
StorageDead(_6);
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
StorageDead(_4);
_2 = Box::<[bool]>(copy _3, const std::alloc::Global);
StorageDead(_3);
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
}
}
+
+ ALLOC2 (size: 8, align: 4) { .. }
+
+ ALLOC1 (size: 8, align: 4) { .. }
+
+ ALLOC0 (size: 8, align: 4) { .. }

Original file line number Diff line number Diff line change
@@ -16,23 +16,34 @@
scope 4 (inlined Unique::<[bool; 0]>::dangling) {
let mut _5: std::ptr::NonNull<[bool; 0]>;
scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
let mut _6: std::num::NonZero<usize>;
let _6: std::ptr::Alignment;
let mut _7: std::num::NonZero<usize>;
scope 6 {
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
scope 10 (inlined std::ptr::Alignment::as_nonzero) {
let mut _8: {closure@std::ptr::Alignment::as_nonzero::{closure#0}};
let mut _9: std::num::NonZero<usize>;
scope 11 {
}
scope 12 (inlined core::contracts::build_check_ensures::<NonZero<usize>, {closure@std::ptr::Alignment::as_nonzero::{closure#0}}>) {
}
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _7: *const [bool; 0];
scope 10 {
scope 13 (inlined NonNull::<[bool; 0]>::without_provenance) {
let _10: *const [bool; 0];
scope 14 {
}
scope 11 (inlined NonZero::<usize>::get) {
scope 15 (inlined NonZero::<usize>::get) {
}
scope 12 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 13 (inlined without_provenance_mut::<[bool; 0]>) {
scope 16 (inlined std::ptr::without_provenance::<[bool; 0]>) {
scope 17 (inlined without_provenance_mut::<[bool; 0]>) {
}
}
}
}
scope 7 (inlined std::ptr::Alignment::of::<[bool; 0]>) {
scope 8 {
}
scope 9 (inlined core::contracts::build_check_ensures::<std::ptr::Alignment, {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}>) {
}
}
}
}
@@ -45,40 +56,42 @@
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = const std::ptr::Alignment::of::<[bool; 0]>::{constant#0} as std::num::NonZero<usize> (Transmute);
+ _6 = const NonZero::<usize>(core::num::niche_types::NonZeroUsizeInner(1_usize));
_6 = contract_check_ensures::<{closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}, std::ptr::Alignment>(const ZeroSized: {closure@std::ptr::Alignment::of<[bool; 0]>::{closure#0}}, const std::ptr::Alignment::of::<[bool; 0]>::{constant#0}) -> [return: bb2, unwind unreachable];
}

bb1: {
StorageDead(_1);
return;
}

bb2: {
StorageLive(_7);
- _7 = copy _6 as *const [bool; 0] (Transmute);
- _5 = NonNull::<[bool; 0]> { pointer: copy _7 };
+ _7 = const {0x1 as *const [bool; 0]};
+ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
StorageLive(_8);
_8 = {closure@$SRC_DIR/core/src/ptr/alignment.rs:LL:COL} { 0: copy _6 };
StorageLive(_9);
_9 = copy _6 as std::num::NonZero<usize> (Transmute);
_7 = contract_check_ensures::<{closure@std::ptr::Alignment::as_nonzero::{closure#0}}, NonZero<usize>>(move _8, move _9) -> [return: bb3, unwind unreachable];
}

bb3: {
StorageDead(_9);
StorageDead(_8);
StorageLive(_10);
_10 = copy _7 as *const [bool; 0] (Transmute);
_5 = NonNull::<[bool; 0]> { pointer: copy _10 };
StorageDead(_10);
StorageDead(_7);
StorageDead(_6);
- _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
_4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
StorageDead(_5);
- _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
_3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
StorageDead(_4);
- _2 = Box::<[bool]>(copy _3, const std::alloc::Global);
+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
_2 = Box::<[bool]>(copy _3, const std::alloc::Global);
StorageDead(_3);
- _1 = A { foo: move _2 };
+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
_1 = A { foo: move _2 };
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
}

bb1: {
StorageDead(_1);
return;
}
}
+
+ ALLOC2 (size: 16, align: 8) { .. }
+
+ ALLOC1 (size: 16, align: 8) { .. }
+
+ ALLOC0 (size: 16, align: 8) { .. }

2 changes: 1 addition & 1 deletion tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs
Original file line number Diff line number Diff line change
@@ -20,6 +20,6 @@ fn main() {
// CHECK: debug a => [[a:_.*]];
// We may check other inlined functions as well...

// CHECK: {{_.*}} = const Box::<[bool]>(
// CHECK: {{_.*}} = {{(const )?}}Box::<[bool]>(
Copy link
Member

Choose a reason for hiding this comment

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

Having to change this is problematic, since apparently the intent of the test was to ensure that this indeed turns into a constant.

Copy link
Author

Choose a reason for hiding this comment

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

Oh, I entirely agree with that. I feel like at this point we are rather exploring the impact of adding those contracts than producing final solutions.

let a: A = A { foo: Box::default() };
}