Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d8bca01

Browse files
committedNov 3, 2024
remove const-support for align_offset
Operations like is_aligned would return actively wrong results at compile-time, i.e. calling it on the same pointer at compiletime and runtime could yield different results. That's no good. Instead of having hacks to make align_offset kind-of work in const-eval, just use const_eval_select in the few places where it makes sense, which also ensures those places are all aware they need to make sure the fallback behavior is consistent.
1 parent 4c6593f commit d8bca01

12 files changed

+177
-931
lines changed
 

‎core/src/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@
112112
#![feature(asm_experimental_arch)]
113113
#![feature(const_align_of_val)]
114114
#![feature(const_align_of_val_raw)]
115-
#![feature(const_align_offset)]
116115
#![feature(const_alloc_layout)]
117116
#![feature(const_arguments_as_str)]
118117
#![feature(const_black_box)]
@@ -125,7 +124,6 @@
125124
#![feature(const_nonnull_new)]
126125
#![feature(const_option_ext)]
127126
#![feature(const_pin_2)]
128-
#![feature(const_pointer_is_aligned)]
129127
#![feature(const_ptr_is_null)]
130128
#![feature(const_ptr_sub_ptr)]
131129
#![feature(const_raw_ptr_comparison)]

‎core/src/ptr/const_ptr.rs

+4-188
Original file line numberDiff line numberDiff line change
@@ -1358,15 +1358,6 @@ impl<T: ?Sized> *const T {
13581358
/// beyond the allocation that the pointer points into. It is up to the caller to ensure that
13591359
/// the returned offset is correct in all terms other than alignment.
13601360
///
1361-
/// When this is called during compile-time evaluation (which is unstable), the implementation
1362-
/// may return `usize::MAX` in cases where that can never happen at runtime. This is because the
1363-
/// actual alignment of pointers is not known yet during compile-time, so an offset with
1364-
/// guaranteed alignment can sometimes not be computed. For example, a buffer declared as `[u8;
1365-
/// N]` might be allocated at an odd or an even address, but at compile-time this is not yet
1366-
/// known, so the execution has to be correct for either choice. It is therefore impossible to
1367-
/// find an offset that is guaranteed to be 2-aligned. (This behavior is subject to change, as usual
1368-
/// for unstable APIs.)
1369-
///
13701361
/// # Panics
13711362
///
13721363
/// The function panics if `align` is not a power-of-two.
@@ -1395,8 +1386,7 @@ impl<T: ?Sized> *const T {
13951386
#[must_use]
13961387
#[inline]
13971388
#[stable(feature = "align_offset", since = "1.36.0")]
1398-
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
1399-
pub const fn align_offset(self, align: usize) -> usize
1389+
pub fn align_offset(self, align: usize) -> usize
14001390
where
14011391
T: Sized,
14021392
{
@@ -1431,94 +1421,10 @@ impl<T: ?Sized> *const T {
14311421
/// assert!(ptr.is_aligned());
14321422
/// assert!(!ptr.wrapping_byte_add(1).is_aligned());
14331423
/// ```
1434-
///
1435-
/// # At compiletime
1436-
/// **Note: Alignment at compiletime is experimental and subject to change. See the
1437-
/// [tracking issue] for details.**
1438-
///
1439-
/// At compiletime, the compiler may not know where a value will end up in memory.
1440-
/// Calling this function on a pointer created from a reference at compiletime will only
1441-
/// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
1442-
/// is never aligned if cast to a type with a stricter alignment than the reference's
1443-
/// underlying allocation.
1444-
///
1445-
/// ```
1446-
/// #![feature(const_pointer_is_aligned)]
1447-
///
1448-
/// // On some platforms, the alignment of primitives is less than their size.
1449-
/// #[repr(align(4))]
1450-
/// struct AlignedI32(i32);
1451-
/// #[repr(align(8))]
1452-
/// struct AlignedI64(i64);
1453-
///
1454-
/// const _: () = {
1455-
/// let data = AlignedI32(42);
1456-
/// let ptr = &data as *const AlignedI32;
1457-
/// assert!(ptr.is_aligned());
1458-
///
1459-
/// // At runtime either `ptr1` or `ptr2` would be aligned, but at compiletime neither is aligned.
1460-
/// let ptr1 = ptr.cast::<AlignedI64>();
1461-
/// let ptr2 = ptr.wrapping_add(1).cast::<AlignedI64>();
1462-
/// assert!(!ptr1.is_aligned());
1463-
/// assert!(!ptr2.is_aligned());
1464-
/// };
1465-
/// ```
1466-
///
1467-
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
1468-
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
1469-
///
1470-
/// ```
1471-
/// #![feature(const_pointer_is_aligned)]
1472-
///
1473-
/// // On some platforms, the alignment of primitives is less than their size.
1474-
/// #[repr(align(4))]
1475-
/// struct AlignedI32(i32);
1476-
/// #[repr(align(8))]
1477-
/// struct AlignedI64(i64);
1478-
///
1479-
/// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
1480-
/// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
1481-
/// const _: () = assert!(!COMPTIME_PTR.cast::<AlignedI64>().is_aligned());
1482-
/// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::<AlignedI64>().is_aligned());
1483-
///
1484-
/// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
1485-
/// let runtime_ptr = COMPTIME_PTR;
1486-
/// assert_ne!(
1487-
/// runtime_ptr.cast::<AlignedI64>().is_aligned(),
1488-
/// runtime_ptr.wrapping_add(1).cast::<AlignedI64>().is_aligned(),
1489-
/// );
1490-
/// ```
1491-
///
1492-
/// If a pointer is created from a fixed address, this function behaves the same during
1493-
/// runtime and compiletime.
1494-
///
1495-
/// ```
1496-
/// #![feature(const_pointer_is_aligned)]
1497-
///
1498-
/// // On some platforms, the alignment of primitives is less than their size.
1499-
/// #[repr(align(4))]
1500-
/// struct AlignedI32(i32);
1501-
/// #[repr(align(8))]
1502-
/// struct AlignedI64(i64);
1503-
///
1504-
/// const _: () = {
1505-
/// let ptr = 40 as *const AlignedI32;
1506-
/// assert!(ptr.is_aligned());
1507-
///
1508-
/// // For pointers with a known address, runtime and compiletime behavior are identical.
1509-
/// let ptr1 = ptr.cast::<AlignedI64>();
1510-
/// let ptr2 = ptr.wrapping_add(1).cast::<AlignedI64>();
1511-
/// assert!(ptr1.is_aligned());
1512-
/// assert!(!ptr2.is_aligned());
1513-
/// };
1514-
/// ```
1515-
///
1516-
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
15171424
#[must_use]
15181425
#[inline]
15191426
#[stable(feature = "pointer_is_aligned", since = "1.79.0")]
1520-
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
1521-
pub const fn is_aligned(self) -> bool
1427+
pub fn is_aligned(self) -> bool
15221428
where
15231429
T: Sized,
15241430
{
@@ -1555,105 +1461,15 @@ impl<T: ?Sized> *const T {
15551461
///
15561462
/// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8));
15571463
/// ```
1558-
///
1559-
/// # At compiletime
1560-
/// **Note: Alignment at compiletime is experimental and subject to change. See the
1561-
/// [tracking issue] for details.**
1562-
///
1563-
/// At compiletime, the compiler may not know where a value will end up in memory.
1564-
/// Calling this function on a pointer created from a reference at compiletime will only
1565-
/// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
1566-
/// cannot be stricter aligned than the reference's underlying allocation.
1567-
///
1568-
/// ```
1569-
/// #![feature(pointer_is_aligned_to)]
1570-
/// #![feature(const_pointer_is_aligned)]
1571-
///
1572-
/// // On some platforms, the alignment of i32 is less than 4.
1573-
/// #[repr(align(4))]
1574-
/// struct AlignedI32(i32);
1575-
///
1576-
/// const _: () = {
1577-
/// let data = AlignedI32(42);
1578-
/// let ptr = &data as *const AlignedI32;
1579-
///
1580-
/// assert!(ptr.is_aligned_to(1));
1581-
/// assert!(ptr.is_aligned_to(2));
1582-
/// assert!(ptr.is_aligned_to(4));
1583-
///
1584-
/// // At compiletime, we know for sure that the pointer isn't aligned to 8.
1585-
/// assert!(!ptr.is_aligned_to(8));
1586-
/// assert!(!ptr.wrapping_add(1).is_aligned_to(8));
1587-
/// };
1588-
/// ```
1589-
///
1590-
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
1591-
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
1592-
///
1593-
/// ```
1594-
/// #![feature(pointer_is_aligned_to)]
1595-
/// #![feature(const_pointer_is_aligned)]
1596-
///
1597-
/// // On some platforms, the alignment of i32 is less than 4.
1598-
/// #[repr(align(4))]
1599-
/// struct AlignedI32(i32);
1600-
///
1601-
/// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
1602-
/// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
1603-
/// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8));
1604-
/// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8));
1605-
///
1606-
/// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
1607-
/// let runtime_ptr = COMPTIME_PTR;
1608-
/// assert_ne!(
1609-
/// runtime_ptr.is_aligned_to(8),
1610-
/// runtime_ptr.wrapping_add(1).is_aligned_to(8),
1611-
/// );
1612-
/// ```
1613-
///
1614-
/// If a pointer is created from a fixed address, this function behaves the same during
1615-
/// runtime and compiletime.
1616-
///
1617-
/// ```
1618-
/// #![feature(pointer_is_aligned_to)]
1619-
/// #![feature(const_pointer_is_aligned)]
1620-
///
1621-
/// const _: () = {
1622-
/// let ptr = 40 as *const u8;
1623-
/// assert!(ptr.is_aligned_to(1));
1624-
/// assert!(ptr.is_aligned_to(2));
1625-
/// assert!(ptr.is_aligned_to(4));
1626-
/// assert!(ptr.is_aligned_to(8));
1627-
/// assert!(!ptr.is_aligned_to(16));
1628-
/// };
1629-
/// ```
1630-
///
1631-
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
16321464
#[must_use]
16331465
#[inline]
16341466
#[unstable(feature = "pointer_is_aligned_to", issue = "96284")]
1635-
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
1636-
pub const fn is_aligned_to(self, align: usize) -> bool {
1467+
pub fn is_aligned_to(self, align: usize) -> bool {
16371468
if !align.is_power_of_two() {
16381469
panic!("is_aligned_to: align is not a power-of-two");
16391470
}
16401471

1641-
#[inline]
1642-
fn runtime_impl(ptr: *const (), align: usize) -> bool {
1643-
ptr.addr() & (align - 1) == 0
1644-
}
1645-
1646-
#[inline]
1647-
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
1648-
const fn const_impl(ptr: *const (), align: usize) -> bool {
1649-
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
1650-
ptr.align_offset(align) == 0
1651-
}
1652-
1653-
// The cast to `()` is used to
1654-
// 1. deal with fat pointers; and
1655-
// 2. ensure that `align_offset` (in `const_impl`) doesn't actually try to compute an offset.
1656-
const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl)
1472+
self.addr() & (align - 1) == 0
16571473
}
16581474
}
16591475

‎core/src/ptr/mod.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -1852,9 +1852,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
18521852
///
18531853
/// Any questions go to @nagisa.
18541854
#[allow(ptr_to_integer_transmute_in_consts)]
1855-
#[lang = "align_offset"]
1856-
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
1857-
pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
1855+
pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
18581856
// FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
18591857
// 1, where the method versions of these operations are not inlined.
18601858
use intrinsics::{
@@ -1915,11 +1913,7 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz
19151913

19161914
let stride = mem::size_of::<T>();
19171915

1918-
// SAFETY: This is just an inlined `p.addr()` (which is not
1919-
// a `const fn` so we cannot call it).
1920-
// During const eval, we hook this function to ensure that the pointer never
1921-
// has provenance, making this sound.
1922-
let addr: usize = unsafe { mem::transmute(p) };
1916+
let addr: usize = p.addr();
19231917

19241918
// SAFETY: `a` is a power-of-two, therefore non-zero.
19251919
let a_minus_one = unsafe { unchecked_sub(a, 1) };
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.