Change:
_memory_extra: &(), _alloc_id: AllocId, allocation: &Allocation<Self::PointerTag, Self::AllocExtra>, <del> static_def_id: Option<DefId>, </del> <ins> _static_def_id: Option<DefId>, </ins> is_write: bool, ) -> InterpResult<'tcx> { if is_write { throw_machine_stop_str!("can't write to global"); } <del> // If the static allocation is mutable or if it has relocations (it may be legal to mutate // the memory behind that in the future), then we can't const prop it. </del> <ins> // If the static allocation is mutable, then we can't const prop it as its content // might be different at runtime. </ins> if allocation.mutability == Mutability::Mut { <del> throw_machine_stop_str!("can't eval mutable globals in ConstProp"); } if static_def_id.is_some() && allocation.relocations().len() > 0 { throw_machine_stop_str!("can't eval statics with pointers in ConstProp"); </del> <ins> throw_machine_stop_str!("can't access mutable globals in ConstProp"); </ins> } Ok(())

Discussion:
const-prop checks statics for whether they contain relocations, and if they do, it refuses to read from them. It is not clear why that happens. Cc
I just realized the condition is , so maybe the allocation in question was not even mutable but had relocations in it. I am testing that now. I do not understand the argument given in the code for why relocations are a problem: If the memory behind that pointer is mutable, we will notice that when that allocation is being accessed. Why do we have to bail out so early? Is it because the hook used to only be called for statics, not all global allocations?
Also the mystery about why validation is even happening is answered here: I think I understand why, conservatively, this does validation... can this ever fail? Validation is quite picky about the kinds of errors in expects can happen, and with const-prop having a machine that bails out early on many operations, that could be a problem. The reason validation is so picky is to make sure we get good errors, which const-prop does not care about (the errors are not shown to the user), but it re-uses the same machinery.
Okay so the actual problem turned out to be relocations. There is no bug here, we can reject all reads from mutable globals (phew). What remains open is why we check for the presence of relocations at all. you that I mentioned above, would be great if you could explain it a bit more. :)
: But I'm not quite sure why...
Basically I want to avoid the following (assume it compiles with more boilerplate) from optimizing to Since we can't ever know what users are up to with their code, the presence of relocations was the easiest way to avoid any kind of troubles there. Furthermore, assuming we just forbid raw pointers from being derefed in const prop, we'd still have problems with the following getting const propped:: I want to prevent const prop from creating any kind of mutable global memory that we may end up pointing to. While we can probably devise a smart scheme, right now it seems better to just forbid any relocations.
that sounds to me like an indirect way to do the check that we can now do much more reliably and directly: This is done for all accesses to globals (things stored in ).

So if a constant global points to a mutable one, the check will fire when the mutable global actually gets accessed.
that's true. Makes more sense to handle the first case like that.
But how does that help with the second example I gave?
The second example does not involve any global though? So nothing we do in that hook will have any effect? I am confused.^^
The problem is that it would magically create a global if we used const prop here. Basically the same problems apply that we have with promotion (except that it's not a problem if we regress optimizations as they aren't "stable")
But again, what does the hook have to do with that? It won't prevent creation of that global, just access to it. I also cannot imagine how const-prop could do anything in your example... doesn't have a known value. And in a case like it would be entirely okay to replace by . Of course with it would not be okay, but then that is exactly the same as using mutable references -- and it has nothing to do with globals. So I fail to see the relevance of any of this for the discussion at hand.
I'm not worried about . I'm worried about const propping into , so is eliminated entirely. optimized to I'm not sure how we're supposed to prevent this without banning relocations in propagated constants.
I don't see why we would even try to do that, that seems like a really odd transformation? And certainly, if any code is responsible for getting things like that right, it's the code that constructs new constants, not the code that reads from existing constants? You still didn't explain how the prevents anything like that. It prevents reading from constants that have relocation, but you keep talking about constructing new constants that have relocations. My confusion remains: what does anything you say have to do with what the issue is about, namely ?
Ah, that's where the confusion comes from. Let's start with a code example again: If we const prop the at some point (or construct your own lockfree datastructure that doesn't use any intrinsics), we have now changed behaviour because we never read the runtime value of (0) but instead the initializer value (42).
(Sorry for the double-post, GH keeps submitting comments for me way before I am done. Probably some silly trigger-happy shortcut.)

Indeed, that would be a problem. And that problem is caught by which would reject any read from a mutable global allocation such as . Which additional problem necessitates the additional check that follows next?
Oh. I see now. Yea, we don't need the second check, any later const prop will do the mutability check and bail out, no matter the number and kind of indirections. We can remove the check
That's what I thought, thanks. :)