Closed
Description
Feature gate: #![feature(const_pointer_is_aligned)]
This is a tracking issue for using ptr.is_aligned()
and ptr.is_aligned_to(alignment)
in const
contexts.
Public API
impl<T: Sized> *(const|mut) T {
pub const fn is_aligned(self) -> bool;
}
impl<T: ?Sized> *(const|mut) T {
pub const fn is_aligned_to(self, align: usize) -> bool;
}
impl <T> NonNull<T> {
pub const fn is_aligned(self) -> bool;
}
Steps / History
- Implementation: Constify
is_aligned
viaalign_offset
#102795Allowconst
functions to behave differently during constant-evaluation and runtime: Relax const-eval restrictions rfcs#3352Final comment period (FCP)1Stabilization PR
Unresolved Questions
- Do we want this at all or should alignment be runtime only / should users be using a stable const_eval_select instead?Should these be separate functions
guaranteed_aligned{,to}
instead?What behavior should these functions have during const eval? Some options include:- Return
true
if the pointer is guaranteed to be aligned at runtime andfalse
if we don't know whether the pointer is aligned at runtime. This is the current implementation. - Same as above, but only document that the function may spuriously fail (during const eval), similar to
align_offset
. This allows changes to const alignment in the future. - Assign a dummy address to all variables during const eval. Each allocation, including stack variables, would get its own "address space", which overlaps with other const eval address spaces and the runtime address space. This would make const eval alignment behavior similar to runtime, but a runtime pointer derived from a const eval pointer is still differently aligned. Pointer-to-integer casts are still not supported. The implementation for this would just remove this check: https://github.com/rust-lang/rust/blob/005f92d24acde37a02e0d084ce2ca8f40d2ee95a/compiler/rustc_const_eval/src/const_eval/machine.rs#L237
- Same as above, but we also allow pointer-to-integer casts, but not integer-to-pointer casts. Any program that assumes that different variables have different addresses bursts up in flame.
Related Links
- Tracking Issue for (runtime)
is_aligned
: Tracking Issue for pointer_is_aligned_to #96284 - Tracking Issue for const
align_offset
: Tracking Issue forconst_align_offset
#90962
Activity
is_aligned
viaalign_offset
#102795the8472 commentedon Nov 18, 2022
What would const code need this for?
lukas-code commentedon Nov 19, 2022
Const alignment in general
Const code doesn't need to check for alignment. The are, however, algorithms that depend on alignment at runtime and also make sense in const. In the standard library we have
str::from_utf8
and[u8]::is_ascii
for example.To make these functions work in const we have two options:
const_eval_select
between them.This feature (
const_pointer_is_aligned
) together withconst_align_offset
tries to address the second bullet point.ptr.is_aligned()
specificallyThe main motivation for const
is_aligned
is catching errors early via assertions. Currently, the standard library uses the internal macroassert_unsafe_precondition!
in many places to assert a condition when debug assertions are enabled and at runtime only. Most of these conditions are something likeptr.is_aligned() && !ptr.is_null()
and can therefore not be checked at compiletime.This feature allows to replace almost all of the
assert_unsafe_precondition!
with something likedebug_or_const_assert!
in the future, which can produce better error messages.Consider this program for example: (playground)
The current error message looks like this:
In the future it might look like this instead:
Edit: I realize now, that this particular example is better solved by #104616, but the idea still applies for downstream crates that want to do a
debug_assert!(ptr.is_aligned())
or are required to do "runtime" alignment checks, like safe_transmute for example.Auto merge of rust-lang#102795 - lukas-code:constify-is-aligned-via-a…
Auto merge of #102795 - lukas-code:constify-is-aligned-via-align-offs…
RalfJung commentedon Dec 2, 2022
Also see the discussion here -- having
is_aligned
suddenly and silently "misbehave" when called in aconst fn
seems like a pretty bug footgun and we should probably not do that.I think something like a new
const fn is_guaranteed_aligned
makes a lot more sense.lukas-code commentedon Dec 3, 2022
If we add
is_guaranteed_aligned
, should that returnOption<bool>
, likeguaranteed_eq
? I can't think of a situation where it would be useful to check if a pointer is guaranteed to be unaligned.If it just returns
bool
, then we'd have two basically identical functions in the standard library, but it might still be worth for documenting "this function might behave unexpectedly at compiletime".As for potential footguns, the only thing I can think of is relying on
Or the same thing extended for larger alignments. For example in this buggy
align_to
implementation. After #104616, this will result in a loud compiler error instead of a silent bug. (This error should probably add a hint why the memory has alignment 1, even after offsetting the pointer.)buggy program & error message
In my opinion, every program that uses
is_aligned
for anything other than "if this isn't aligned, return an error/panic" should probably be usingalign_offset
or{read/write}_unaligned
instead.RalfJung commentedon Dec 3, 2022
Yeah I was thinking the function name would help serve as a warning sign.
Cc @thomcc who brought this up in Zulip.
the8472 commentedon Dec 3, 2022
Imo this is preferable. The alignment checks are only needed for performance optimizations that aren't relevant at comptime. The const version can be very naive code.
Note that we don't even ship the standard library with debug asserts enabled. So for now these are mostly CI aids. It doesn't seem right to extend the public API surface to enable this at const time, especially since alignment at const time is underdetermined, unlike runtime alignment.
Wouldn't a
debug_assert_rt!()
do the job too?Auto merge of #102795 - lukas-code:constify-is-aligned-via-align-offs…
const_align_offset
#909626 remaining items