Code change:
The program below creates a promoted in a constant via but immediately casts this to a raw pointer. Now having weird values behind raw pointers is fine, but we have an intermediate reference to an invalid value. I don't understand how this compiles considering that the promoted is essentially Apparently we don't validate promoteds. I think we are allowed to fix this and validate promoteds, even though it will be a breaking change, because the user had to create an intermediate reference that pointed to an invalid bool. cc ()
So with the new promotion-as-consts scheme, what does that code "desugar" to?
before promotion as consts: after promotion as consts
Thanks. I agree in both of these cases we should do validation and consider this an error.
Hm, actually, thinking about it again... if we didn't do promotion in that , we'd not show any error. So I am not entirely sure if we really should show an error just because promotion happened? That would mean promoting more things can make compilation fail, which promotion explicitly does not want to happen. Also, right now validity check rejects some things that are not necessarily UB, such as integers in a reference (there's an open issue for this somewhere).
We'll do this in a PR that does nothing else but this change. already made the choice to not validate explicit in , so a PR fixing this issue will just remove the bail out and the comment
I have no idea what you just said but whatever.^^ That link just goes to the top of the diff, not any specific part of it.
Promotion in runtime code may not fail compilation. Promotion in constants should fail compilation imo because it's explicit promotion because you are in a const context
My argument was that it's seems to become kind of arbitrary when we do validation (even inside CTFE context) and when not -- suddenly that depends on details like what exactly promotion is doing. Not sure if that's good. It's certainly entirely random from a user's perspective: some CTFE code that causes UB through invalid values will work fine, other code will cause validation errrors.
Hmm... that's true. ok, so the current strategy of not validating promoteds makes sense and we can revisit the question later (or make validating promoteds just a lint)
I think this is actually closely related to I am not sure if it is worth keeping both of them open. Basically this issue is "we should validate promoteds maybe", and the other issue is "we cannot validate promoteds as we promote some things that are not valid".
Okay it's different kinds of validation -- one is the interior mutability part, done during interning, and the other is type-based validation of the final value.
We no longer promote union field accesses... but we still promote arbitrary calls in / initializers so the issue can be reproduced that way. Also I feel like my argument above only really works for implicit promoteds; explicit promoteds likely should be validated -- but I am not sure if there is an easy way we can make that distinction? It might just not be worth it.
The way it's currently set up we'd need to add that information to . Considering that we want to rework our error/lint stuff around const eval anyway, we should probably do that first, so the callers to the const eval queries can decide such things. Though now that I think of it, validation is orthogonal to reporting errors on it, so idk.
With , it seems like we are moving towards making promotion infallible. I think that means we should also validate promoteds (all of them). So I take back what I said earlier, where I argued against validating promoteds.

Related discussion:
text: Ok(mplace) => { // Since evaluation had no errors, valiate the resulting constant: let validation = try { <del> // FIXME do not validate promoteds until a decision on // https://github.com/rust-lang/rust/issues/67465 and // https://github.com/rust-lang/rust/issues/67534 is made. // Promoteds can contain unexpected `UnsafeCell` and reference `static`s, but their // otherwise restricted form ensures that this is still sound. We just lose the // extra safety net of some of the dynamic checks. They can also contain invalid // values, but since we do not usually check intermediate results of a computation // for validity, it might be surprising to do that here. if cid.promoted.is_none() { let mut ref_tracking = RefTracking::new(mplace); let mut inner = false; while let Some((mplace, path)) = ref_tracking.todo.pop() { let mode = match tcx.static_mutability(cid.instance.def_id()) { Some(_) => CtfeValidationMode::Regular, // a `static` None => CtfeValidationMode::Const { inner }, }; ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?; inner = true; } </del> <ins> let mut ref_tracking = RefTracking::new(mplace); let mut inner = false; while let Some((mplace, path)) = ref_tracking.todo.pop() { let mode = match tcx.static_mutability(cid.instance.def_id()) { Some(_) if cid.promoted.is_some() => { // Promoteds in statics are allowed to point to statics. CtfeValidationMode::Const { inner, allow_static_ptrs: true } } Some(_) => CtfeValidationMode::Regular, // a `static` None => CtfeValidationMode::Const { inner, allow_static_ptrs: false }, }; ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?; inner = true; </ins> } }; if let Err(error) = validation {