Skip to content

ACP ptr::is_aligned_for::<T>() #140979

New issue

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

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

Already on GitHub? # to your account

Closed
mathisbot opened this issue May 13, 2025 · 0 comments
Closed

ACP ptr::is_aligned_for::<T>() #140979

mathisbot opened this issue May 13, 2025 · 0 comments

Comments

@mathisbot
Copy link
Contributor

ACP: ptr::is_aligned_for::<U>

Summary

This proposal introduces a new method, ptr::is_aligned_for::<U>(self) -> bool, on raw pointers.
It streamlines alignment checks when casting pointers to a different type by eliminating the need for an intermediate, lint-triggering cast.
The new API mirrors the implementation of ptr::is_aligned, using the alignment of the target type U.

Motivation

Currently, checking that a pointer is properly aligned for a target type requires a cast prior to invoking ptr.is_aligned().
This can trigger the Clippy lint clippy::cast_ptr_alignment, which users must manually silence even though their check is valid.

Another solution is to call ptr::is_aligned_to with align_of::<U>(),
which is still unstable (see #96284) for matters of runtime checks.
This method deals with exactly the same goal as ptr::is_aligned, i.e. ensuring that the pointer alignment is valid (for aligned reads/writes) after a cast.
As the alignment would be provided by align_of, the problem of invalid alignments discussed in #96284 are not relevant here.

Motivating examples

type Pixel = u32;

struct Screen {
    raw_buffer: &'static mut [Pixel]
}

impl Screen {
    pub fn new(raw_buffer: &'static mut [u8], Self) {
        let pixel_ptr = {
            let buffer_ptr = raw_buffer.as_mut_ptr();
            assert!(buffer_ptr.is_aligned_for::<Pixel>(), "Buffer is not aligned for Pixel");
            buffer_ptr.cast::<Pixel>()
        };

        // We can now safely create a slice from the pointer
        // as both the alignment and address are valid
        let pixel_slice = unsafe {
            core::slice::from_raw_parts_mut(
                pixel_ptr,
                raw_buffer.len() / size_of::<Pixel>()
            ) 
        };
    }
}

Note: Rewriting Screen::new with a new signature (i.e. making raw_buffer a &'static mut [Pixel]) would only relocate the problem.

The above code can currently only be written as:

let pixel_ptr = {
    let buffer_ptr = raw_buffer.as_mut_ptr();
    assert!(buffer_ptr.cast::<Pixel>().is_aligned(), "Buffer is not aligned for Pixel");
    buffer_ptr.cast::<Pixel>()
};

which I think is less readable.

I am sure that there are examples dealing with FFI that would benefit from this as well (such as when dealing with C-void pointers).

API Design

impl<T: Sized> *const T {
    #[must_use]
    #[inline]
    pub fn is_aligned_for<U: Sized>(self) -> bool;
}

impl<T: Sized> *mut T {
    #[must_use]
    #[inline]
    pub fn is_aligned_for<U: Sized>(self) -> bool;
}

impl<T: Sized> NonNull<T> {
    #[must_use]
    #[inline]
    pub fn is_aligned_for<U: Sized>(self) -> bool;
}

References

I would be delighted to open the PR myself if this ACP is accepted and if no one wants to do it first.

@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label May 13, 2025
@jieyouxu jieyouxu removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label May 14, 2025
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants