How long does a pointer to a `const` last?

If I have something like:

let ptr = {
    const A: [u8; 8] = [0; 8];
    A.as_ptr()
};

Will ptr be valid for reads? Or should I consider it to be invalidated once A is out-of-scope?

IIUC, a pointer to a static will be alive for the entirety of the program (since the data it points to gets compiled as a part of the binary), but I'm not sure about consts.

You understand statics correctly. Unlike statics, consts do not have their own addresses. The docs says about consts, that:

Constants are essentially inlined wherever they are used, meaning that they are copied directly into the relevant context when used.

This behavior is very similar to literals.

So in the general case, the pointer would not be valid.[1]

But, like literals, constant values are also eligible for constant promotion:

Promotion of a value expression to a 'static slot occurs when the expression could be written in a constant and borrowed, and that borrow could be dereferenced where the expression was originally written, without changing the runtime behavior. That is, the promoted expression can be evaluated at compile-time and the resulting value does not contain interior mutability or destructors (these properties are determined based on the value where possible, e.g. &None always has the type &'static Option<_>, as it contains nothing disallowed).

So in this case (of a [u8; 8]) the value gets promoted into a static slot, and the pointer will be valid. I would not recommend relying on promotion though, especially not with unsafe code!


  1. A reference to a constant will have 'static lifetime if the constant value is eligible for promotion; otherwise, a temporary will be created. ↩︎

3 Likes

That’s true, but I would suggest that it might be wiser to not implicitly rely on implicit promotion — to make it harder for edits to the program to accidentally break its required properties. This can even be done without switching to a static item (which would enforce an unnecessary unique address):

let ptr: *const u8 = {
    const A: &'static [u8; 8] = &[0; 8];
    A.as_ptr()
};
6 Likes

I agree, hence my

So in the general case, the pointer would not be valid.

Maybe I should emphasise it a little more.

Thank you both! I knew about constant promotions, but the rules are quite difficult to follow, and I always had a (wrong) assumption that they only happen when references are involved (i.e. it is why you can conjure a &[] out of thin air, and return it from a function with a lifetime tied to one of its params?)

If you're curious, I was asking because this macro in the windows-core crate was making me very uneasy: windows-rs/crates/libs/strings/src/literals.rs at c289f6c719080d4e28d73af2bd7466550c6d5cf4 · microsoft/windows-rs · GitHub

I think I'll file a PR to change the const into a static, if not for anything then at least so at least other people won't find themselves going down this rabbit hole :sweat_smile:

1 Like

I don't think this assumption is very wrong, because it only ever matters when references/pointers are involved.[1]

Note that references are involved in this case too:

fn as_ptr(&self) -> *const T

as_ptr makes a pointer out of a reference.


  1. and the compiler is allowed to deviate from the spec as long as the observable behavior is the same anyway ↩︎

I don't see any pointer to const in that macro. Which line specifically? OUTPUT.as_ptr() is not a pointer to const item, since OUTPUT is a slice instead of an array (like in your OP).

1 Like