Skip to content

NonNull methods for pointer offset, add, sub #72429

Closed
@bluss

Description

@bluss

It would be beneficial to low-level code to add methods like offset, add, sub non NonNull<T>, so that pointer offsetting can be done without converting back and forth to raw pointers. These methods would be unsafe just like the corresponding raw pointer methods, return NonNull<T> and have the same semantics.

These methods will work well because such pointer offsetting is only valid inside the same allocated object; when offsetting it is not allowed to "leave" the current object, it can because of that never result in a null pointer. (For example, LLVM documents that an inbounds GEP on a non-null pointer must not result in a null pointer.)

For this reason, the safety rules that need to be followed for correct use of <NonNull<T>>::offset are the same as for <*mut T>::offset, and the method can be offered on the same terms, as an unsafe method.

This is for the moment implemented in at least one crate - rawpointer and was a necessary feature for using NonNull<T> in ndarray.

Example implementation

impl<T> NonNull<T> {
    /// Use the same documentation as the corresponding raw pointer method
    pub unsafe fn offset(self, i: isize) -> Self {
        // offset must be inside the same allocated object or one past the end, and can that way
        // never result in a null pointer
        NonNull::new_unchecked(self.as_ptr().offset(i))
    }

    pub unsafe fn add(self, i: usize) -> Self {
        NonNull::new_unchecked(self.as_ptr().add(i))
    }

    pub unsafe fn sub(self, i: usize) -> Self {
        NonNull::new_unchecked(self.as_ptr().sub(i))
    }
}

The drawback of these methods is that while raw pointer offset has tricky requirements (offset inside the same allocation) due to the code generation back-end, the new nonnull offset methods will add extra requirements on top of that (Rust-level value validity); that these two restrictions go hand in hand, is just a consequence of the current back-end. Would it be possible to imagine a "nicer" Rust that didn't have these UB traps for pointer offsetting?

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-feature-requestCategory: A feature request, i.e: not implemented / a PR.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions