Skip to content

Commit dd01a16

Browse files
committed
Auto merge of #106275 - Nilstrieb:const-eval-select-me-some-compile-time, r=thomcc
Use some more `const_eval_select` in pointer methods for compile times Builds on top of #105435 `is_aligned_to` is _huge_ with calling `align_offset`, so this should cut it down a lot. This shows up in #65031 (comment)
2 parents 726bbfc + a8f5045 commit dd01a16

File tree

2 files changed

+66
-22
lines changed

2 files changed

+66
-22
lines changed

library/core/src/ptr/const_ptr.rs

+33-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::*;
22
use crate::cmp::Ordering::{self, Equal, Greater, Less};
3-
use crate::intrinsics;
3+
use crate::intrinsics::{self, const_eval_select};
44
use crate::mem;
55
use crate::slice::{self, SliceIndex};
66

@@ -34,12 +34,23 @@ impl<T: ?Sized> *const T {
3434
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
3535
#[inline]
3636
pub const fn is_null(self) -> bool {
37-
// Compare via a cast to a thin pointer, so fat pointers are only
38-
// considering their "data" part for null-ness.
39-
match (self as *const u8).guaranteed_eq(null()) {
40-
None => false,
41-
Some(res) => res,
37+
#[inline]
38+
fn runtime_impl(ptr: *const u8) -> bool {
39+
ptr.addr() == 0
4240
}
41+
42+
#[inline]
43+
const fn const_impl(ptr: *const u8) -> bool {
44+
// Compare via a cast to a thin pointer, so fat pointers are only
45+
// considering their "data" part for null-ness.
46+
match (ptr).guaranteed_eq(null_mut()) {
47+
None => false,
48+
Some(res) => res,
49+
}
50+
}
51+
52+
// SAFETY: The two versions are equivalent at runtime.
53+
unsafe { const_eval_select((self as *const u8,), const_impl, runtime_impl) }
4354
}
4455

4556
/// Casts to a pointer of another type.
@@ -1587,11 +1598,22 @@ impl<T: ?Sized> *const T {
15871598
panic!("is_aligned_to: align is not a power-of-two");
15881599
}
15891600

1590-
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
1591-
// The cast to `()` is used to
1592-
// 1. deal with fat pointers; and
1593-
// 2. ensure that `align_offset` doesn't actually try to compute an offset.
1594-
self.cast::<()>().align_offset(align) == 0
1601+
#[inline]
1602+
fn runtime_impl(ptr: *const (), align: usize) -> bool {
1603+
ptr.addr() & (align - 1) == 0
1604+
}
1605+
1606+
#[inline]
1607+
const fn const_impl(ptr: *const (), align: usize) -> bool {
1608+
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
1609+
// The cast to `()` is used to
1610+
// 1. deal with fat pointers; and
1611+
// 2. ensure that `align_offset` doesn't actually try to compute an offset.
1612+
ptr.align_offset(align) == 0
1613+
}
1614+
1615+
// SAFETY: The two versions are equivalent at runtime.
1616+
unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) }
15951617
}
15961618
}
15971619

library/core/src/ptr/mut_ptr.rs

+33-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::*;
22
use crate::cmp::Ordering::{self, Equal, Greater, Less};
3-
use crate::intrinsics;
3+
use crate::intrinsics::{self, const_eval_select};
44
use crate::slice::{self, SliceIndex};
55

66
impl<T: ?Sized> *mut T {
@@ -33,12 +33,23 @@ impl<T: ?Sized> *mut T {
3333
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
3434
#[inline]
3535
pub const fn is_null(self) -> bool {
36-
// Compare via a cast to a thin pointer, so fat pointers are only
37-
// considering their "data" part for null-ness.
38-
match (self as *mut u8).guaranteed_eq(null_mut()) {
39-
None => false,
40-
Some(res) => res,
36+
#[inline]
37+
fn runtime_impl(ptr: *mut u8) -> bool {
38+
ptr.addr() == 0
4139
}
40+
41+
#[inline]
42+
const fn const_impl(ptr: *mut u8) -> bool {
43+
// Compare via a cast to a thin pointer, so fat pointers are only
44+
// considering their "data" part for null-ness.
45+
match (ptr).guaranteed_eq(null_mut()) {
46+
None => false,
47+
Some(res) => res,
48+
}
49+
}
50+
51+
// SAFETY: The two versions are equivalent at runtime.
52+
unsafe { const_eval_select((self as *mut u8,), const_impl, runtime_impl) }
4253
}
4354

4455
/// Casts to a pointer of another type.
@@ -1859,11 +1870,22 @@ impl<T: ?Sized> *mut T {
18591870
panic!("is_aligned_to: align is not a power-of-two");
18601871
}
18611872

1862-
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
1863-
// The cast to `()` is used to
1864-
// 1. deal with fat pointers; and
1865-
// 2. ensure that `align_offset` doesn't actually try to compute an offset.
1866-
self.cast::<()>().align_offset(align) == 0
1873+
#[inline]
1874+
fn runtime_impl(ptr: *mut (), align: usize) -> bool {
1875+
ptr.addr() & (align - 1) == 0
1876+
}
1877+
1878+
#[inline]
1879+
const fn const_impl(ptr: *mut (), align: usize) -> bool {
1880+
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
1881+
// The cast to `()` is used to
1882+
// 1. deal with fat pointers; and
1883+
// 2. ensure that `align_offset` doesn't actually try to compute an offset.
1884+
ptr.align_offset(align) == 0
1885+
}
1886+
1887+
// SAFETY: The two versions are equivalent at runtime.
1888+
unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) }
18671889
}
18681890
}
18691891

0 commit comments

Comments
 (0)