Question:
Code: <details<summaryBacktrace</summary</details
modify labels: I-ICE C-Bug T-compiler A-mir Regression from 1.34 to 1.35
Additionally, this one ICEs with different error message: () <details<summaryBacktrace</summary</details
This code should not get all the way to codegen without an error
Another, different ICE? <details<summaryBacktrace</summary</summary
Regression somewhere between ...
looks suspicious, cc In particular, maybe is falsly returning here since the expected type is due to the other match arms?

<ins> fn main() { let mut i: i64; // Expected type is an inference variable `?T` // because the `match` is used as a statement. // This is the "initial" type of the `coercion`. match i { // Add `bool` to the overall `coercion`. 0 => true, // Necessary to cause the ICE: 1 => true, // Suppose that we had `let _: bool = match i { ... }`. // In that case, as the expected type would be `bool`, // we would suggest `i == 1` as a fix. // // However, no type error happens when checking `i = 1` because `expected == ?T`, // which will unify with `typeof(i = 1) == ()`. // // However, in #67273, we would delay the unification of this arm with the above // because we used the hitherto accumulated coercion as opposed to the "initial" type. 2 => i = 1, //~^ ERROR match arms have incompatible types _ => (), } } </ins>


Question:
Code: <details<summaryBacktrace</summary</details
modify labels: I-ICE C-Bug T-compiler A-mir Regression from 1.34 to 1.35
Additionally, this one ICEs with different error message: () <details<summaryBacktrace</summary</details
This code should not get all the way to codegen without an error
Another, different ICE? <details<summaryBacktrace</summary</summary
Regression somewhere between ...
looks suspicious, cc In particular, maybe is falsly returning here since the expected type is due to the other match arms?

<ins> error[E0308]: match arms have incompatible types --> $DIR/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs:22:14 | LL | /     match i { LL | |         // Add `bool` to the overall `coercion`. LL | |         0 => true, | |              ---- this is found to be of type `bool` LL | | LL | |         // Necessary to cause the ICE: LL | |         1 => true, | |              ---- this is found to be of type `bool` ...  | LL | |         2 => i = 1, | |              ^^^^^ expected `bool`, found `()` ...  | LL | |         _ => (), LL | |     } | |_____- `match` arms have incompatible types error: aborting due to previous error For more information about this error, try `rustc --explain E0308`. </ins>


Question:
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.

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 {


Question:
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.

pub enum CtfeValidationMode { /// Regular validation, nothing special happening. Regular, <del> /// Validation of a `const`. `inner` says if this is an inner, indirect allocation (as opposed /// to the top-level const allocation). /// Being an inner allocation makes a difference because the top-level allocation of a `const` /// is copied for each use, but the inner allocations are implicitly shared. Const { inner: bool }, </del> <ins> /// Validation of a `const`. /// `inner` says if this is an inner, indirect allocation (as opposed to the top-level const /// allocation). Being an inner allocation makes a difference because the top-level allocation /// of a `const` is copied for each use, but the inner allocations are implicitly shared. /// `allow_static_ptrs` says if pointers to statics are permitted (which is the case for promoteds in statics). Const { inner: bool, allow_static_ptrs: bool }, </ins> } /// State for tracking recursive validation of references


Question:
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.

if let Some(GlobalAlloc::Static(did)) = alloc_kind { assert!(!self.ecx.tcx.is_thread_local_static(did)); assert!(self.ecx.tcx.is_static(did)); <del> if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) { </del> <ins> if matches!( self.ctfe_mode, Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. }) ) { </ins> // See const_eval::machine::MemoryExtra::can_access_statics for why // this check is so important. // This check is reachable when the const just referenced the static,


Question:
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.

// Sanity check: `builtin_deref` does not know any pointers that are not primitive. assert!(op.layout.ty.builtin_deref(true).is_none()); <del> // Special check preventing `UnsafeCell` in constants </del> <ins> // Special check preventing `UnsafeCell` in the inner part of constants </ins> if let Some(def) = op.layout.ty.ty_adt_def() { <del> if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true })) </del> <ins> if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) </ins> && Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() { throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" });


Question:
root: updns-0.0.6: v.
triage: P-high. Nominating for discussion.
self-assigned for investigation in short term (as in, next two or three days). However I suspect someone from will be a better choice to investigate this.
We should try to bisect this
used . Determined: searched nightlies: from nightly-2019-11-26 to nightly-2020-01-03 regressed nightly: nightly-2019-12-01 searched commits: from to  regressed commit:
is a rollup commit of the following PR's: I'm guessing this is due to PR
I'm still working on reducing this down to something that I could put into the playpen. However, one interesting thing I've found locally during my reduction: This version of the will signal an analogous compilation error: but if I lift the first argument out to a separate -binding (i.e. change it to use above, or the sub-expression out to a separate -binding (i.e. change the argument expression to use above), then the error goes away. I'll admit that I don't know all the details of how the fn-transformation works to support , but I strongly suspect that if this kind of local code change can make an error go away, then that represents a weakness somewhere (either in the fn-transformation, or in the borrowck).
Okay in the details block is a standalone version suitable for the : <details</detailsand the error it generates:
So this does seem like somewhat clear (expected?) fallout from PR : a use of a in a generator witness will be recorded as a unsafe pointer , and then is never , but the method requires that the task you give it is . I believe we can readily update the crate in question to avoid using the in the expression under the RHS of . But I do wonder whether we can/should improve the diagnostics here to try to guide the user towards such a solution ...?
I might have worded this too strongly, and/or over-reduced my example. In particular, its easy to move around the access to . But the borrow of may be trickier to deal with.
I'll have a look at addressing this with another approach I considered for . If that doesn't work out then I'll have a look at the error message.
The patch linked is enough to fix the crate in question, but I'm all for finding an in-compiler solution if we can do it soundly.
OK. I'm going to write some things up because I've changed my mind a bunch of times about how/if this can be fixed in MIR building and I don't want to keep forgetting things. Generators store values that if their value needs to be preserved across a yield. These values need to be visible for auto-traits, for example a generator may be resumed on a different thread after it yields, and so cannot be if any of theses values isn't . There are two passes that determine which values can be included in the generator: A pass that runs as part of typeck that walks the HIR to find the types of expressions and then checks for yields in the values scope (as determined by the RegionScopeTree). The types recorded here are stored in the GeneratorWitnesss type contained in the generator, which is then used for auto trait checking. This notably uses the types of expressions that HIR sees. The MIR transform that lowers the generator to a state machine. This determines the values that the generator actually stores. As a check for the compiler, we assert that any types that we capture here are included in the witness type (we don't know all auto traits, so can't check only for them). After statics no longer have a special representation in MIR. They are instead lowered to a dereference of a pointer to the given static: is lowered as if it were: Which becomes: The example above is somewhat deceptive in that the temporary that holds the pointer is used immediately after it's assigned. In this case it cannot end up in the generator since it's not live across any user code. However this isn't true in all cases, index and match expressions allow running user code while the pointer is live: In these cases MIR has to put the temporary pointer into the generator state and promptly ICEs. The obvious solution now is make type checking record the new pointer types in the generator witness in these cases. Unfortunately HIR is not a great tool for specifying "these cases". The methods that the region scope tree provides in HIR are either usually far too large (the "temporary scope") or occasionally too small (the "enclosing scope"). went for the sound but rather approximate approach, leaving us here. One idea might be to try changing MIR building so that the temporary is never live across user code. For example, one might change the lowering as follows However working out how to do this for in a reasonable to implement way is harder. MIR actually already contains an escape hatch for values that are in the MIR but aren't in the HIR in the form of a flag (called ) on the variable. We currently use it for drop flags and boxes created by expressions. It's unclear what exactly the difference is between is. I guess one could argue that auto traits are for layout introspection and this would be further breaking that. I think that's everything for now.
Visiting from triage. were you planning to work on this further?
It's definitely tempting to take advantage of the constraints around statics to just declare these equivalent, and use the flag to get out of this. While I don't see any soundness issues around that, I also don't quite trust myself to get this right :) Can you expand on this? I'm not sure I follow.
Another solution that comes to mind relies on the fact that these pointers never need to be stored in a generator. They are consts, and the temporaries containing them shouldn't ever be mutated. We could add semantics for "const temporaries" to MIR, and never store them inside generators. The semantics would (hopefully) be simple: defined once and assigned a value that doesn't depend on any other temporaries; never mutated or borrowed mutably. We can move the statements defining them to the top of the function inside the generator transform. But that would be adding more semantics and special casing to MIR to fix a change which removed extra semantics and special casing, so I'm not sure if that's what we want :)
The argument is that the given the following auto trait we guarantee that if then there are no raw pointers directly stored in an instance of . If we make that guarantee then using internal in generators would not be OK. I would argue that we're not making such (or really any) guarantees with user defined auto traits.
Yeah, I don't think auto traits should expose layout implementation details of generators. And this really does seem like a pure implementation detail -- it doesn't have any bearing on what kinds of (unsafe) operations are allowed on a generator, like a self-reference would. cc
So, I've been putting off commenting here to let these ideas sit, but let me leave a comment. I think I've reached a conclusion. TL;DR. I think we should mark these types as internal, but I think there are some better options for fixing this in the medium term, and this interaction should be taken into account as part of the "MIR 2.0" effort to rework places. Auto traits weren't really intended as a tool for probing layout, but rather semantic considerations. This is why traits like can be implemented by users. So I don't really think that auto traits give any sort of guarantee about their layout. Rather, this question is about is simply "what are the constituent types exposed by a generator", and this should correspond to the types that user code can directly access. The raw pointers here are not directly accessible. The values that are accessible are the "live values" that the user's code may later use -- and of course the code currently makes the constituent types be a superset of those, based on the AST structure. Of course, the real root cause of this error is a simplifying change to the definition of in MIR. It used to be that a Place had this grammar: but now we changed to just , which is why we are required to introduce the new temporary (and that holds the address of the ). As we've been talking about this change, I've been saying that we should be considering the older definition of as the one that is used by various analyses (and in particular by borrow check). This particular transformation of removing statics doesn't affect borrow check, but we failed to take into account the fact that the set of live variables can effect the definition of what is live in a generator. In particular, compiling for some expression requires a temporary unless corresponds to a place -- those places used to include statics like , but they no longer do. But I think that for analysis purposes, it should appear as if they do. We could fix this in two ways. We could write some code motion / duplication that takes temporaries like that are live across a yield and creates a fresh variable after the yield. The idea would be to make them never* live across a yield. We can do this because that operation is a compile-time constant, really, and thus the value doesn't need to be live across a yield. This might be worth doing as a size optimization regardless. Secondly, some of the proposals we've been kicking around for going further with simplifying include the idea of a distinct sort of temporaries that explicitly represent a "partially constructed that hasn't been used by the user". The idea was to allow borrowck (and other analyses) to trivially reconstruct the . We might want to add this interaction with auto-traits into the consideration for that design, and maybe it takes us some place (e.g., these special temporaries are not considered live for the purposes of auto traits). Having written out both of those options, though, I sort of lean towards the first, at least for this specific issue.
I think these references and raw pointers created by MIR construction should be marked as . They are not visible at the language level. They can be viewed as just prefetching the address of a static, so the compiler could pick any type it likes for it (, , , some compiler internal type) so it must not affect auto trait inference. Drop flags are ignored for similar reasons. You cannot use an auto trait like this to detect them: So I think that should be reverted and the temporary static references should be marked as .
Note: opened instituting this change and I r+'d it, since fixing the regression seems pretty important and time is of the essence; there is general consensus here on the thread; this is only restoring older behavior. In particular, there were some suggestions that this might be a lang team issue; I think there is some 'intersection' and I don't want the perception that I'm trying to shortcircuit discussion. That said, I also think this is primarily a compiler team matter, since it's a deviation from the old behavior, and further this deviation was caused by altering the MIR away from the "natural, Rust-based" definition and towards a lower-level definition.

if let (local, []) = (&place.local, proj_base) { let decl = &self.body.local_decls[*local]; if decl.internal { <del> // Internal locals are used in the `move_val_init` desugaring. // We want to check unsafety against the source info of the // desugaring, rather than the source info of the RHS. self.source_info = self.body.local_decls[*local].source_info; } else if let LocalInfo::StaticRef { def_id, .. } = decl.local_info { if self.tcx.is_mutable_static(def_id) { self.require_unsafe( "use of mutable static", "mutable statics can be mutated by multiple threads: aliasing  violations or data races will cause undefined behavior", UnsafetyViolationKind::General, ); return; } else if self.tcx.is_foreign_item(def_id) { self.require_unsafe( "use of extern static", "extern statics are not controlled by the Rust type system:  invalid data, aliasing violations or data races will cause  undefined behavior", UnsafetyViolationKind::General, ); return; </del> <ins> if let LocalInfo::StaticRef { def_id, .. } = decl.local_info { if self.tcx.is_mutable_static(def_id) { self.require_unsafe( "use of mutable static", "mutable statics can be mutated by multiple threads: aliasing  violations or data races will cause undefined behavior", UnsafetyViolationKind::General, ); return; } else if self.tcx.is_foreign_item(def_id) { self.require_unsafe( "use of extern static", "extern statics are not controlled by the Rust type system:  invalid data, aliasing violations or data races will cause  undefined behavior", UnsafetyViolationKind::General, ); return; } } else { // Internal locals are used in the `move_val_init` desugaring. // We want to check unsafety against the source info of the // desugaring, rather than the source info of the RHS. self.source_info = self.body.local_decls[*local].source_info; </ins> } } }


Question:
root: updns-0.0.6: v.
triage: P-high. Nominating for discussion.
self-assigned for investigation in short term (as in, next two or three days). However I suspect someone from will be a better choice to investigate this.
We should try to bisect this
used . Determined: searched nightlies: from nightly-2019-11-26 to nightly-2020-01-03 regressed nightly: nightly-2019-12-01 searched commits: from to  regressed commit:
is a rollup commit of the following PR's: I'm guessing this is due to PR
I'm still working on reducing this down to something that I could put into the playpen. However, one interesting thing I've found locally during my reduction: This version of the will signal an analogous compilation error: but if I lift the first argument out to a separate -binding (i.e. change it to use above, or the sub-expression out to a separate -binding (i.e. change the argument expression to use above), then the error goes away. I'll admit that I don't know all the details of how the fn-transformation works to support , but I strongly suspect that if this kind of local code change can make an error go away, then that represents a weakness somewhere (either in the fn-transformation, or in the borrowck).
Okay in the details block is a standalone version suitable for the : <details</detailsand the error it generates:
So this does seem like somewhat clear (expected?) fallout from PR : a use of a in a generator witness will be recorded as a unsafe pointer , and then is never , but the method requires that the task you give it is . I believe we can readily update the crate in question to avoid using the in the expression under the RHS of . But I do wonder whether we can/should improve the diagnostics here to try to guide the user towards such a solution ...?
I might have worded this too strongly, and/or over-reduced my example. In particular, its easy to move around the access to . But the borrow of may be trickier to deal with.
I'll have a look at addressing this with another approach I considered for . If that doesn't work out then I'll have a look at the error message.
The patch linked is enough to fix the crate in question, but I'm all for finding an in-compiler solution if we can do it soundly.
OK. I'm going to write some things up because I've changed my mind a bunch of times about how/if this can be fixed in MIR building and I don't want to keep forgetting things. Generators store values that if their value needs to be preserved across a yield. These values need to be visible for auto-traits, for example a generator may be resumed on a different thread after it yields, and so cannot be if any of theses values isn't . There are two passes that determine which values can be included in the generator: A pass that runs as part of typeck that walks the HIR to find the types of expressions and then checks for yields in the values scope (as determined by the RegionScopeTree). The types recorded here are stored in the GeneratorWitnesss type contained in the generator, which is then used for auto trait checking. This notably uses the types of expressions that HIR sees. The MIR transform that lowers the generator to a state machine. This determines the values that the generator actually stores. As a check for the compiler, we assert that any types that we capture here are included in the witness type (we don't know all auto traits, so can't check only for them). After statics no longer have a special representation in MIR. They are instead lowered to a dereference of a pointer to the given static: is lowered as if it were: Which becomes: The example above is somewhat deceptive in that the temporary that holds the pointer is used immediately after it's assigned. In this case it cannot end up in the generator since it's not live across any user code. However this isn't true in all cases, index and match expressions allow running user code while the pointer is live: In these cases MIR has to put the temporary pointer into the generator state and promptly ICEs. The obvious solution now is make type checking record the new pointer types in the generator witness in these cases. Unfortunately HIR is not a great tool for specifying "these cases". The methods that the region scope tree provides in HIR are either usually far too large (the "temporary scope") or occasionally too small (the "enclosing scope"). went for the sound but rather approximate approach, leaving us here. One idea might be to try changing MIR building so that the temporary is never live across user code. For example, one might change the lowering as follows However working out how to do this for in a reasonable to implement way is harder. MIR actually already contains an escape hatch for values that are in the MIR but aren't in the HIR in the form of a flag (called ) on the variable. We currently use it for drop flags and boxes created by expressions. It's unclear what exactly the difference is between is. I guess one could argue that auto traits are for layout introspection and this would be further breaking that. I think that's everything for now.
Visiting from triage. were you planning to work on this further?
It's definitely tempting to take advantage of the constraints around statics to just declare these equivalent, and use the flag to get out of this. While I don't see any soundness issues around that, I also don't quite trust myself to get this right :) Can you expand on this? I'm not sure I follow.
Another solution that comes to mind relies on the fact that these pointers never need to be stored in a generator. They are consts, and the temporaries containing them shouldn't ever be mutated. We could add semantics for "const temporaries" to MIR, and never store them inside generators. The semantics would (hopefully) be simple: defined once and assigned a value that doesn't depend on any other temporaries; never mutated or borrowed mutably. We can move the statements defining them to the top of the function inside the generator transform. But that would be adding more semantics and special casing to MIR to fix a change which removed extra semantics and special casing, so I'm not sure if that's what we want :)
The argument is that the given the following auto trait we guarantee that if then there are no raw pointers directly stored in an instance of . If we make that guarantee then using internal in generators would not be OK. I would argue that we're not making such (or really any) guarantees with user defined auto traits.
Yeah, I don't think auto traits should expose layout implementation details of generators. And this really does seem like a pure implementation detail -- it doesn't have any bearing on what kinds of (unsafe) operations are allowed on a generator, like a self-reference would. cc
So, I've been putting off commenting here to let these ideas sit, but let me leave a comment. I think I've reached a conclusion. TL;DR. I think we should mark these types as internal, but I think there are some better options for fixing this in the medium term, and this interaction should be taken into account as part of the "MIR 2.0" effort to rework places. Auto traits weren't really intended as a tool for probing layout, but rather semantic considerations. This is why traits like can be implemented by users. So I don't really think that auto traits give any sort of guarantee about their layout. Rather, this question is about is simply "what are the constituent types exposed by a generator", and this should correspond to the types that user code can directly access. The raw pointers here are not directly accessible. The values that are accessible are the "live values" that the user's code may later use -- and of course the code currently makes the constituent types be a superset of those, based on the AST structure. Of course, the real root cause of this error is a simplifying change to the definition of in MIR. It used to be that a Place had this grammar: but now we changed to just , which is why we are required to introduce the new temporary (and that holds the address of the ). As we've been talking about this change, I've been saying that we should be considering the older definition of as the one that is used by various analyses (and in particular by borrow check). This particular transformation of removing statics doesn't affect borrow check, but we failed to take into account the fact that the set of live variables can effect the definition of what is live in a generator. In particular, compiling for some expression requires a temporary unless corresponds to a place -- those places used to include statics like , but they no longer do. But I think that for analysis purposes, it should appear as if they do. We could fix this in two ways. We could write some code motion / duplication that takes temporaries like that are live across a yield and creates a fresh variable after the yield. The idea would be to make them never* live across a yield. We can do this because that operation is a compile-time constant, really, and thus the value doesn't need to be live across a yield. This might be worth doing as a size optimization regardless. Secondly, some of the proposals we've been kicking around for going further with simplifying include the idea of a distinct sort of temporaries that explicitly represent a "partially constructed that hasn't been used by the user". The idea was to allow borrowck (and other analyses) to trivially reconstruct the . We might want to add this interaction with auto-traits into the consideration for that design, and maybe it takes us some place (e.g., these special temporaries are not considered live for the purposes of auto traits). Having written out both of those options, though, I sort of lean towards the first, at least for this specific issue.
I think these references and raw pointers created by MIR construction should be marked as . They are not visible at the language level. They can be viewed as just prefetching the address of a static, so the compiler could pick any type it likes for it (, , , some compiler internal type) so it must not affect auto trait inference. Drop flags are ignored for similar reasons. You cannot use an auto trait like this to detect them: So I think that should be reverted and the temporary static references should be marked as .
Note: opened instituting this change and I r+'d it, since fixing the regression seems pretty important and time is of the essence; there is general consensus here on the thread; this is only restoring older behavior. In particular, there were some suggestions that this might be a lang team issue; I think there is some 'intersection' and I don't want the perception that I'm trying to shortcircuit discussion. That said, I also think this is primarily a compiler team matter, since it's a deviation from the old behavior, and further this deviation was caused by altering the MIR away from the "natural, Rust-based" definition and towards a lower-level definition.

} if let ExprKind::StaticRef { def_id, .. } = expr.kind { let is_thread_local = this.hir.tcx().has_attr(def_id, sym::thread_local); <ins> local_decl.internal = true; </ins> local_decl.local_info = LocalInfo::StaticRef { def_id, is_thread_local }; } this.local_decls.push(local_decl)


Question:
root: updns-0.0.6: v.
triage: P-high. Nominating for discussion.
self-assigned for investigation in short term (as in, next two or three days). However I suspect someone from will be a better choice to investigate this.
We should try to bisect this
used . Determined: searched nightlies: from nightly-2019-11-26 to nightly-2020-01-03 regressed nightly: nightly-2019-12-01 searched commits: from to  regressed commit:
is a rollup commit of the following PR's: I'm guessing this is due to PR
I'm still working on reducing this down to something that I could put into the playpen. However, one interesting thing I've found locally during my reduction: This version of the will signal an analogous compilation error: but if I lift the first argument out to a separate -binding (i.e. change it to use above, or the sub-expression out to a separate -binding (i.e. change the argument expression to use above), then the error goes away. I'll admit that I don't know all the details of how the fn-transformation works to support , but I strongly suspect that if this kind of local code change can make an error go away, then that represents a weakness somewhere (either in the fn-transformation, or in the borrowck).
Okay in the details block is a standalone version suitable for the : <details</detailsand the error it generates:
So this does seem like somewhat clear (expected?) fallout from PR : a use of a in a generator witness will be recorded as a unsafe pointer , and then is never , but the method requires that the task you give it is . I believe we can readily update the crate in question to avoid using the in the expression under the RHS of . But I do wonder whether we can/should improve the diagnostics here to try to guide the user towards such a solution ...?
I might have worded this too strongly, and/or over-reduced my example. In particular, its easy to move around the access to . But the borrow of may be trickier to deal with.
I'll have a look at addressing this with another approach I considered for . If that doesn't work out then I'll have a look at the error message.
The patch linked is enough to fix the crate in question, but I'm all for finding an in-compiler solution if we can do it soundly.
OK. I'm going to write some things up because I've changed my mind a bunch of times about how/if this can be fixed in MIR building and I don't want to keep forgetting things. Generators store values that if their value needs to be preserved across a yield. These values need to be visible for auto-traits, for example a generator may be resumed on a different thread after it yields, and so cannot be if any of theses values isn't . There are two passes that determine which values can be included in the generator: A pass that runs as part of typeck that walks the HIR to find the types of expressions and then checks for yields in the values scope (as determined by the RegionScopeTree). The types recorded here are stored in the GeneratorWitnesss type contained in the generator, which is then used for auto trait checking. This notably uses the types of expressions that HIR sees. The MIR transform that lowers the generator to a state machine. This determines the values that the generator actually stores. As a check for the compiler, we assert that any types that we capture here are included in the witness type (we don't know all auto traits, so can't check only for them). After statics no longer have a special representation in MIR. They are instead lowered to a dereference of a pointer to the given static: is lowered as if it were: Which becomes: The example above is somewhat deceptive in that the temporary that holds the pointer is used immediately after it's assigned. In this case it cannot end up in the generator since it's not live across any user code. However this isn't true in all cases, index and match expressions allow running user code while the pointer is live: In these cases MIR has to put the temporary pointer into the generator state and promptly ICEs. The obvious solution now is make type checking record the new pointer types in the generator witness in these cases. Unfortunately HIR is not a great tool for specifying "these cases". The methods that the region scope tree provides in HIR are either usually far too large (the "temporary scope") or occasionally too small (the "enclosing scope"). went for the sound but rather approximate approach, leaving us here. One idea might be to try changing MIR building so that the temporary is never live across user code. For example, one might change the lowering as follows However working out how to do this for in a reasonable to implement way is harder. MIR actually already contains an escape hatch for values that are in the MIR but aren't in the HIR in the form of a flag (called ) on the variable. We currently use it for drop flags and boxes created by expressions. It's unclear what exactly the difference is between is. I guess one could argue that auto traits are for layout introspection and this would be further breaking that. I think that's everything for now.
Visiting from triage. were you planning to work on this further?
It's definitely tempting to take advantage of the constraints around statics to just declare these equivalent, and use the flag to get out of this. While I don't see any soundness issues around that, I also don't quite trust myself to get this right :) Can you expand on this? I'm not sure I follow.
Another solution that comes to mind relies on the fact that these pointers never need to be stored in a generator. They are consts, and the temporaries containing them shouldn't ever be mutated. We could add semantics for "const temporaries" to MIR, and never store them inside generators. The semantics would (hopefully) be simple: defined once and assigned a value that doesn't depend on any other temporaries; never mutated or borrowed mutably. We can move the statements defining them to the top of the function inside the generator transform. But that would be adding more semantics and special casing to MIR to fix a change which removed extra semantics and special casing, so I'm not sure if that's what we want :)
The argument is that the given the following auto trait we guarantee that if then there are no raw pointers directly stored in an instance of . If we make that guarantee then using internal in generators would not be OK. I would argue that we're not making such (or really any) guarantees with user defined auto traits.
Yeah, I don't think auto traits should expose layout implementation details of generators. And this really does seem like a pure implementation detail -- it doesn't have any bearing on what kinds of (unsafe) operations are allowed on a generator, like a self-reference would. cc
So, I've been putting off commenting here to let these ideas sit, but let me leave a comment. I think I've reached a conclusion. TL;DR. I think we should mark these types as internal, but I think there are some better options for fixing this in the medium term, and this interaction should be taken into account as part of the "MIR 2.0" effort to rework places. Auto traits weren't really intended as a tool for probing layout, but rather semantic considerations. This is why traits like can be implemented by users. So I don't really think that auto traits give any sort of guarantee about their layout. Rather, this question is about is simply "what are the constituent types exposed by a generator", and this should correspond to the types that user code can directly access. The raw pointers here are not directly accessible. The values that are accessible are the "live values" that the user's code may later use -- and of course the code currently makes the constituent types be a superset of those, based on the AST structure. Of course, the real root cause of this error is a simplifying change to the definition of in MIR. It used to be that a Place had this grammar: but now we changed to just , which is why we are required to introduce the new temporary (and that holds the address of the ). As we've been talking about this change, I've been saying that we should be considering the older definition of as the one that is used by various analyses (and in particular by borrow check). This particular transformation of removing statics doesn't affect borrow check, but we failed to take into account the fact that the set of live variables can effect the definition of what is live in a generator. In particular, compiling for some expression requires a temporary unless corresponds to a place -- those places used to include statics like , but they no longer do. But I think that for analysis purposes, it should appear as if they do. We could fix this in two ways. We could write some code motion / duplication that takes temporaries like that are live across a yield and creates a fresh variable after the yield. The idea would be to make them never* live across a yield. We can do this because that operation is a compile-time constant, really, and thus the value doesn't need to be live across a yield. This might be worth doing as a size optimization regardless. Secondly, some of the proposals we've been kicking around for going further with simplifying include the idea of a distinct sort of temporaries that explicitly represent a "partially constructed that hasn't been used by the user". The idea was to allow borrowck (and other analyses) to trivially reconstruct the . We might want to add this interaction with auto-traits into the consideration for that design, and maybe it takes us some place (e.g., these special temporaries are not considered live for the purposes of auto traits). Having written out both of those options, though, I sort of lean towards the first, at least for this specific issue.
I think these references and raw pointers created by MIR construction should be marked as . They are not visible at the language level. They can be viewed as just prefetching the address of a static, so the compiler could pick any type it likes for it (, , , some compiler internal type) so it must not affect auto trait inference. Drop flags are ignored for similar reasons. You cannot use an auto trait like this to detect them: So I think that should be reverted and the temporary static references should be marked as .
Note: opened instituting this change and I r+'d it, since fixing the regression seems pretty important and time is of the essence; there is general consensus here on the thread; this is only restoring older behavior. In particular, there were some suggestions that this might be a lang team issue; I think there is some 'intersection' and I don't want the perception that I'm trying to shortcircuit discussion. That said, I also think this is primarily a compiler team matter, since it's a deviation from the old behavior, and further this deviation was caused by altering the MIR away from the "natural, Rust-based" definition and towards a lower-level definition.

} fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { <del> let scope = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); </del> match &expr.kind { ExprKind::Call(callee, args) => match &callee.kind { ExprKind::Path(qpath) => {


Question:
root: updns-0.0.6: v.
triage: P-high. Nominating for discussion.
self-assigned for investigation in short term (as in, next two or three days). However I suspect someone from will be a better choice to investigate this.
We should try to bisect this
used . Determined: searched nightlies: from nightly-2019-11-26 to nightly-2020-01-03 regressed nightly: nightly-2019-12-01 searched commits: from to  regressed commit:
is a rollup commit of the following PR's: I'm guessing this is due to PR
I'm still working on reducing this down to something that I could put into the playpen. However, one interesting thing I've found locally during my reduction: This version of the will signal an analogous compilation error: but if I lift the first argument out to a separate -binding (i.e. change it to use above, or the sub-expression out to a separate -binding (i.e. change the argument expression to use above), then the error goes away. I'll admit that I don't know all the details of how the fn-transformation works to support , but I strongly suspect that if this kind of local code change can make an error go away, then that represents a weakness somewhere (either in the fn-transformation, or in the borrowck).
Okay in the details block is a standalone version suitable for the : <details</detailsand the error it generates:
So this does seem like somewhat clear (expected?) fallout from PR : a use of a in a generator witness will be recorded as a unsafe pointer , and then is never , but the method requires that the task you give it is . I believe we can readily update the crate in question to avoid using the in the expression under the RHS of . But I do wonder whether we can/should improve the diagnostics here to try to guide the user towards such a solution ...?
I might have worded this too strongly, and/or over-reduced my example. In particular, its easy to move around the access to . But the borrow of may be trickier to deal with.
I'll have a look at addressing this with another approach I considered for . If that doesn't work out then I'll have a look at the error message.
The patch linked is enough to fix the crate in question, but I'm all for finding an in-compiler solution if we can do it soundly.
OK. I'm going to write some things up because I've changed my mind a bunch of times about how/if this can be fixed in MIR building and I don't want to keep forgetting things. Generators store values that if their value needs to be preserved across a yield. These values need to be visible for auto-traits, for example a generator may be resumed on a different thread after it yields, and so cannot be if any of theses values isn't . There are two passes that determine which values can be included in the generator: A pass that runs as part of typeck that walks the HIR to find the types of expressions and then checks for yields in the values scope (as determined by the RegionScopeTree). The types recorded here are stored in the GeneratorWitnesss type contained in the generator, which is then used for auto trait checking. This notably uses the types of expressions that HIR sees. The MIR transform that lowers the generator to a state machine. This determines the values that the generator actually stores. As a check for the compiler, we assert that any types that we capture here are included in the witness type (we don't know all auto traits, so can't check only for them). After statics no longer have a special representation in MIR. They are instead lowered to a dereference of a pointer to the given static: is lowered as if it were: Which becomes: The example above is somewhat deceptive in that the temporary that holds the pointer is used immediately after it's assigned. In this case it cannot end up in the generator since it's not live across any user code. However this isn't true in all cases, index and match expressions allow running user code while the pointer is live: In these cases MIR has to put the temporary pointer into the generator state and promptly ICEs. The obvious solution now is make type checking record the new pointer types in the generator witness in these cases. Unfortunately HIR is not a great tool for specifying "these cases". The methods that the region scope tree provides in HIR are either usually far too large (the "temporary scope") or occasionally too small (the "enclosing scope"). went for the sound but rather approximate approach, leaving us here. One idea might be to try changing MIR building so that the temporary is never live across user code. For example, one might change the lowering as follows However working out how to do this for in a reasonable to implement way is harder. MIR actually already contains an escape hatch for values that are in the MIR but aren't in the HIR in the form of a flag (called ) on the variable. We currently use it for drop flags and boxes created by expressions. It's unclear what exactly the difference is between is. I guess one could argue that auto traits are for layout introspection and this would be further breaking that. I think that's everything for now.
Visiting from triage. were you planning to work on this further?
It's definitely tempting to take advantage of the constraints around statics to just declare these equivalent, and use the flag to get out of this. While I don't see any soundness issues around that, I also don't quite trust myself to get this right :) Can you expand on this? I'm not sure I follow.
Another solution that comes to mind relies on the fact that these pointers never need to be stored in a generator. They are consts, and the temporaries containing them shouldn't ever be mutated. We could add semantics for "const temporaries" to MIR, and never store them inside generators. The semantics would (hopefully) be simple: defined once and assigned a value that doesn't depend on any other temporaries; never mutated or borrowed mutably. We can move the statements defining them to the top of the function inside the generator transform. But that would be adding more semantics and special casing to MIR to fix a change which removed extra semantics and special casing, so I'm not sure if that's what we want :)
The argument is that the given the following auto trait we guarantee that if then there are no raw pointers directly stored in an instance of . If we make that guarantee then using internal in generators would not be OK. I would argue that we're not making such (or really any) guarantees with user defined auto traits.
Yeah, I don't think auto traits should expose layout implementation details of generators. And this really does seem like a pure implementation detail -- it doesn't have any bearing on what kinds of (unsafe) operations are allowed on a generator, like a self-reference would. cc
So, I've been putting off commenting here to let these ideas sit, but let me leave a comment. I think I've reached a conclusion. TL;DR. I think we should mark these types as internal, but I think there are some better options for fixing this in the medium term, and this interaction should be taken into account as part of the "MIR 2.0" effort to rework places. Auto traits weren't really intended as a tool for probing layout, but rather semantic considerations. This is why traits like can be implemented by users. So I don't really think that auto traits give any sort of guarantee about their layout. Rather, this question is about is simply "what are the constituent types exposed by a generator", and this should correspond to the types that user code can directly access. The raw pointers here are not directly accessible. The values that are accessible are the "live values" that the user's code may later use -- and of course the code currently makes the constituent types be a superset of those, based on the AST structure. Of course, the real root cause of this error is a simplifying change to the definition of in MIR. It used to be that a Place had this grammar: but now we changed to just , which is why we are required to introduce the new temporary (and that holds the address of the ). As we've been talking about this change, I've been saying that we should be considering the older definition of as the one that is used by various analyses (and in particular by borrow check). This particular transformation of removing statics doesn't affect borrow check, but we failed to take into account the fact that the set of live variables can effect the definition of what is live in a generator. In particular, compiling for some expression requires a temporary unless corresponds to a place -- those places used to include statics like , but they no longer do. But I think that for analysis purposes, it should appear as if they do. We could fix this in two ways. We could write some code motion / duplication that takes temporaries like that are live across a yield and creates a fresh variable after the yield. The idea would be to make them never* live across a yield. We can do this because that operation is a compile-time constant, really, and thus the value doesn't need to be live across a yield. This might be worth doing as a size optimization regardless. Secondly, some of the proposals we've been kicking around for going further with simplifying include the idea of a distinct sort of temporaries that explicitly represent a "partially constructed that hasn't been used by the user". The idea was to allow borrowck (and other analyses) to trivially reconstruct the . We might want to add this interaction with auto-traits into the consideration for that design, and maybe it takes us some place (e.g., these special temporaries are not considered live for the purposes of auto traits). Having written out both of those options, though, I sort of lean towards the first, at least for this specific issue.
I think these references and raw pointers created by MIR construction should be marked as . They are not visible at the language level. They can be viewed as just prefetching the address of a static, so the compiler could pick any type it likes for it (, , , some compiler internal type) so it must not affect auto trait inference. Drop flags are ignored for similar reasons. You cannot use an auto trait like this to detect them: So I think that should be reverted and the temporary static references should be marked as .
Note: opened instituting this change and I r+'d it, since fixing the regression seems pretty important and time is of the essence; there is general consensus here on the thread; this is only restoring older behavior. In particular, there were some suggestions that this might be a lang team issue; I think there is some 'intersection' and I don't want the perception that I'm trying to shortcircuit discussion. That said, I also think this is primarily a compiler team matter, since it's a deviation from the old behavior, and further this deviation was caused by altering the MIR away from the "natural, Rust-based" definition and towards a lower-level definition.

} _ => intravisit::walk_expr(self, expr), }, <del> ExprKind::Path(qpath) => { let res = self.fcx.tables.borrow().qpath_res(qpath, expr.hir_id); if let Res::Def(DefKind::Static, def_id) = res { // Statics are lowered to temporary references or // pointers in MIR, so record that type. let ptr_ty = self.fcx.tcx.static_ptr_ty(def_id); self.record(ptr_ty, scope, Some(expr), expr.span); } } </del> _ => intravisit::walk_expr(self, expr), } self.expr_count += 1; <ins> let scope = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); </ins> // If there are adjustments, then record the final type -- // this is the actual value that is being produced. if let Some(adjusted_ty) = self.fcx.tables.borrow().expr_ty_adjusted_opt(expr) {


Question:
root: updns-0.0.6: v.
triage: P-high. Nominating for discussion.
self-assigned for investigation in short term (as in, next two or three days). However I suspect someone from will be a better choice to investigate this.
We should try to bisect this
used . Determined: searched nightlies: from nightly-2019-11-26 to nightly-2020-01-03 regressed nightly: nightly-2019-12-01 searched commits: from to  regressed commit:
is a rollup commit of the following PR's: I'm guessing this is due to PR
I'm still working on reducing this down to something that I could put into the playpen. However, one interesting thing I've found locally during my reduction: This version of the will signal an analogous compilation error: but if I lift the first argument out to a separate -binding (i.e. change it to use above, or the sub-expression out to a separate -binding (i.e. change the argument expression to use above), then the error goes away. I'll admit that I don't know all the details of how the fn-transformation works to support , but I strongly suspect that if this kind of local code change can make an error go away, then that represents a weakness somewhere (either in the fn-transformation, or in the borrowck).
Okay in the details block is a standalone version suitable for the : <details</detailsand the error it generates:
So this does seem like somewhat clear (expected?) fallout from PR : a use of a in a generator witness will be recorded as a unsafe pointer , and then is never , but the method requires that the task you give it is . I believe we can readily update the crate in question to avoid using the in the expression under the RHS of . But I do wonder whether we can/should improve the diagnostics here to try to guide the user towards such a solution ...?
I might have worded this too strongly, and/or over-reduced my example. In particular, its easy to move around the access to . But the borrow of may be trickier to deal with.
I'll have a look at addressing this with another approach I considered for . If that doesn't work out then I'll have a look at the error message.
The patch linked is enough to fix the crate in question, but I'm all for finding an in-compiler solution if we can do it soundly.
OK. I'm going to write some things up because I've changed my mind a bunch of times about how/if this can be fixed in MIR building and I don't want to keep forgetting things. Generators store values that if their value needs to be preserved across a yield. These values need to be visible for auto-traits, for example a generator may be resumed on a different thread after it yields, and so cannot be if any of theses values isn't . There are two passes that determine which values can be included in the generator: A pass that runs as part of typeck that walks the HIR to find the types of expressions and then checks for yields in the values scope (as determined by the RegionScopeTree). The types recorded here are stored in the GeneratorWitnesss type contained in the generator, which is then used for auto trait checking. This notably uses the types of expressions that HIR sees. The MIR transform that lowers the generator to a state machine. This determines the values that the generator actually stores. As a check for the compiler, we assert that any types that we capture here are included in the witness type (we don't know all auto traits, so can't check only for them). After statics no longer have a special representation in MIR. They are instead lowered to a dereference of a pointer to the given static: is lowered as if it were: Which becomes: The example above is somewhat deceptive in that the temporary that holds the pointer is used immediately after it's assigned. In this case it cannot end up in the generator since it's not live across any user code. However this isn't true in all cases, index and match expressions allow running user code while the pointer is live: In these cases MIR has to put the temporary pointer into the generator state and promptly ICEs. The obvious solution now is make type checking record the new pointer types in the generator witness in these cases. Unfortunately HIR is not a great tool for specifying "these cases". The methods that the region scope tree provides in HIR are either usually far too large (the "temporary scope") or occasionally too small (the "enclosing scope"). went for the sound but rather approximate approach, leaving us here. One idea might be to try changing MIR building so that the temporary is never live across user code. For example, one might change the lowering as follows However working out how to do this for in a reasonable to implement way is harder. MIR actually already contains an escape hatch for values that are in the MIR but aren't in the HIR in the form of a flag (called ) on the variable. We currently use it for drop flags and boxes created by expressions. It's unclear what exactly the difference is between is. I guess one could argue that auto traits are for layout introspection and this would be further breaking that. I think that's everything for now.
Visiting from triage. were you planning to work on this further?
It's definitely tempting to take advantage of the constraints around statics to just declare these equivalent, and use the flag to get out of this. While I don't see any soundness issues around that, I also don't quite trust myself to get this right :) Can you expand on this? I'm not sure I follow.
Another solution that comes to mind relies on the fact that these pointers never need to be stored in a generator. They are consts, and the temporaries containing them shouldn't ever be mutated. We could add semantics for "const temporaries" to MIR, and never store them inside generators. The semantics would (hopefully) be simple: defined once and assigned a value that doesn't depend on any other temporaries; never mutated or borrowed mutably. We can move the statements defining them to the top of the function inside the generator transform. But that would be adding more semantics and special casing to MIR to fix a change which removed extra semantics and special casing, so I'm not sure if that's what we want :)
The argument is that the given the following auto trait we guarantee that if then there are no raw pointers directly stored in an instance of . If we make that guarantee then using internal in generators would not be OK. I would argue that we're not making such (or really any) guarantees with user defined auto traits.
Yeah, I don't think auto traits should expose layout implementation details of generators. And this really does seem like a pure implementation detail -- it doesn't have any bearing on what kinds of (unsafe) operations are allowed on a generator, like a self-reference would. cc
So, I've been putting off commenting here to let these ideas sit, but let me leave a comment. I think I've reached a conclusion. TL;DR. I think we should mark these types as internal, but I think there are some better options for fixing this in the medium term, and this interaction should be taken into account as part of the "MIR 2.0" effort to rework places. Auto traits weren't really intended as a tool for probing layout, but rather semantic considerations. This is why traits like can be implemented by users. So I don't really think that auto traits give any sort of guarantee about their layout. Rather, this question is about is simply "what are the constituent types exposed by a generator", and this should correspond to the types that user code can directly access. The raw pointers here are not directly accessible. The values that are accessible are the "live values" that the user's code may later use -- and of course the code currently makes the constituent types be a superset of those, based on the AST structure. Of course, the real root cause of this error is a simplifying change to the definition of in MIR. It used to be that a Place had this grammar: but now we changed to just , which is why we are required to introduce the new temporary (and that holds the address of the ). As we've been talking about this change, I've been saying that we should be considering the older definition of as the one that is used by various analyses (and in particular by borrow check). This particular transformation of removing statics doesn't affect borrow check, but we failed to take into account the fact that the set of live variables can effect the definition of what is live in a generator. In particular, compiling for some expression requires a temporary unless corresponds to a place -- those places used to include statics like , but they no longer do. But I think that for analysis purposes, it should appear as if they do. We could fix this in two ways. We could write some code motion / duplication that takes temporaries like that are live across a yield and creates a fresh variable after the yield. The idea would be to make them never* live across a yield. We can do this because that operation is a compile-time constant, really, and thus the value doesn't need to be live across a yield. This might be worth doing as a size optimization regardless. Secondly, some of the proposals we've been kicking around for going further with simplifying include the idea of a distinct sort of temporaries that explicitly represent a "partially constructed that hasn't been used by the user". The idea was to allow borrowck (and other analyses) to trivially reconstruct the . We might want to add this interaction with auto-traits into the consideration for that design, and maybe it takes us some place (e.g., these special temporaries are not considered live for the purposes of auto traits). Having written out both of those options, though, I sort of lean towards the first, at least for this specific issue.
I think these references and raw pointers created by MIR construction should be marked as . They are not visible at the language level. They can be viewed as just prefetching the address of a static, so the compiler could pick any type it likes for it (, , , some compiler internal type) so it must not affect auto trait inference. Drop flags are ignored for similar reasons. You cannot use an auto trait like this to detect them: So I think that should be reverted and the temporary static references should be marked as .
Note: opened instituting this change and I r+'d it, since fixing the regression seems pretty important and time is of the essence; there is general consensus here on the thread; this is only restoring older behavior. In particular, there were some suggestions that this might be a lang team issue; I think there is some 'intersection' and I don't want the perception that I'm trying to shortcircuit discussion. That said, I also think this is primarily a compiler team matter, since it's a deviation from the old behavior, and further this deviation was caused by altering the MIR away from the "natural, Rust-based" definition and towards a lower-level definition.

<ins> // build-pass // edition:2018 static mut A: [i32; 5] = [1, 2, 3, 4, 5]; fn is_send_sync<T: Send + Sync>(_: T) {} async fn fun() { let u = unsafe { A[async { 1 }.await] }; unsafe { match A { i if async { true }.await => (), _ => (), } } } fn main() { let index_block = async { let u = unsafe { A[async { 1 }.await] }; }; let match_block = async { unsafe { match A { i if async { true }.await => (), _ => (), } } }; is_send_sync(index_block); is_send_sync(match_block); is_send_sync(fun()); } </ins>


Question:
root: updns-0.0.6: v.
triage: P-high. Nominating for discussion.
self-assigned for investigation in short term (as in, next two or three days). However I suspect someone from will be a better choice to investigate this.
We should try to bisect this
used . Determined: searched nightlies: from nightly-2019-11-26 to nightly-2020-01-03 regressed nightly: nightly-2019-12-01 searched commits: from to  regressed commit:
is a rollup commit of the following PR's: I'm guessing this is due to PR
I'm still working on reducing this down to something that I could put into the playpen. However, one interesting thing I've found locally during my reduction: This version of the will signal an analogous compilation error: but if I lift the first argument out to a separate -binding (i.e. change it to use above, or the sub-expression out to a separate -binding (i.e. change the argument expression to use above), then the error goes away. I'll admit that I don't know all the details of how the fn-transformation works to support , but I strongly suspect that if this kind of local code change can make an error go away, then that represents a weakness somewhere (either in the fn-transformation, or in the borrowck).
Okay in the details block is a standalone version suitable for the : <details</detailsand the error it generates:
So this does seem like somewhat clear (expected?) fallout from PR : a use of a in a generator witness will be recorded as a unsafe pointer , and then is never , but the method requires that the task you give it is . I believe we can readily update the crate in question to avoid using the in the expression under the RHS of . But I do wonder whether we can/should improve the diagnostics here to try to guide the user towards such a solution ...?
I might have worded this too strongly, and/or over-reduced my example. In particular, its easy to move around the access to . But the borrow of may be trickier to deal with.
I'll have a look at addressing this with another approach I considered for . If that doesn't work out then I'll have a look at the error message.
The patch linked is enough to fix the crate in question, but I'm all for finding an in-compiler solution if we can do it soundly.
OK. I'm going to write some things up because I've changed my mind a bunch of times about how/if this can be fixed in MIR building and I don't want to keep forgetting things. Generators store values that if their value needs to be preserved across a yield. These values need to be visible for auto-traits, for example a generator may be resumed on a different thread after it yields, and so cannot be if any of theses values isn't . There are two passes that determine which values can be included in the generator: A pass that runs as part of typeck that walks the HIR to find the types of expressions and then checks for yields in the values scope (as determined by the RegionScopeTree). The types recorded here are stored in the GeneratorWitnesss type contained in the generator, which is then used for auto trait checking. This notably uses the types of expressions that HIR sees. The MIR transform that lowers the generator to a state machine. This determines the values that the generator actually stores. As a check for the compiler, we assert that any types that we capture here are included in the witness type (we don't know all auto traits, so can't check only for them). After statics no longer have a special representation in MIR. They are instead lowered to a dereference of a pointer to the given static: is lowered as if it were: Which becomes: The example above is somewhat deceptive in that the temporary that holds the pointer is used immediately after it's assigned. In this case it cannot end up in the generator since it's not live across any user code. However this isn't true in all cases, index and match expressions allow running user code while the pointer is live: In these cases MIR has to put the temporary pointer into the generator state and promptly ICEs. The obvious solution now is make type checking record the new pointer types in the generator witness in these cases. Unfortunately HIR is not a great tool for specifying "these cases". The methods that the region scope tree provides in HIR are either usually far too large (the "temporary scope") or occasionally too small (the "enclosing scope"). went for the sound but rather approximate approach, leaving us here. One idea might be to try changing MIR building so that the temporary is never live across user code. For example, one might change the lowering as follows However working out how to do this for in a reasonable to implement way is harder. MIR actually already contains an escape hatch for values that are in the MIR but aren't in the HIR in the form of a flag (called ) on the variable. We currently use it for drop flags and boxes created by expressions. It's unclear what exactly the difference is between is. I guess one could argue that auto traits are for layout introspection and this would be further breaking that. I think that's everything for now.
Visiting from triage. were you planning to work on this further?
It's definitely tempting to take advantage of the constraints around statics to just declare these equivalent, and use the flag to get out of this. While I don't see any soundness issues around that, I also don't quite trust myself to get this right :) Can you expand on this? I'm not sure I follow.
Another solution that comes to mind relies on the fact that these pointers never need to be stored in a generator. They are consts, and the temporaries containing them shouldn't ever be mutated. We could add semantics for "const temporaries" to MIR, and never store them inside generators. The semantics would (hopefully) be simple: defined once and assigned a value that doesn't depend on any other temporaries; never mutated or borrowed mutably. We can move the statements defining them to the top of the function inside the generator transform. But that would be adding more semantics and special casing to MIR to fix a change which removed extra semantics and special casing, so I'm not sure if that's what we want :)
The argument is that the given the following auto trait we guarantee that if then there are no raw pointers directly stored in an instance of . If we make that guarantee then using internal in generators would not be OK. I would argue that we're not making such (or really any) guarantees with user defined auto traits.
Yeah, I don't think auto traits should expose layout implementation details of generators. And this really does seem like a pure implementation detail -- it doesn't have any bearing on what kinds of (unsafe) operations are allowed on a generator, like a self-reference would. cc
So, I've been putting off commenting here to let these ideas sit, but let me leave a comment. I think I've reached a conclusion. TL;DR. I think we should mark these types as internal, but I think there are some better options for fixing this in the medium term, and this interaction should be taken into account as part of the "MIR 2.0" effort to rework places. Auto traits weren't really intended as a tool for probing layout, but rather semantic considerations. This is why traits like can be implemented by users. So I don't really think that auto traits give any sort of guarantee about their layout. Rather, this question is about is simply "what are the constituent types exposed by a generator", and this should correspond to the types that user code can directly access. The raw pointers here are not directly accessible. The values that are accessible are the "live values" that the user's code may later use -- and of course the code currently makes the constituent types be a superset of those, based on the AST structure. Of course, the real root cause of this error is a simplifying change to the definition of in MIR. It used to be that a Place had this grammar: but now we changed to just , which is why we are required to introduce the new temporary (and that holds the address of the ). As we've been talking about this change, I've been saying that we should be considering the older definition of as the one that is used by various analyses (and in particular by borrow check). This particular transformation of removing statics doesn't affect borrow check, but we failed to take into account the fact that the set of live variables can effect the definition of what is live in a generator. In particular, compiling for some expression requires a temporary unless corresponds to a place -- those places used to include statics like , but they no longer do. But I think that for analysis purposes, it should appear as if they do. We could fix this in two ways. We could write some code motion / duplication that takes temporaries like that are live across a yield and creates a fresh variable after the yield. The idea would be to make them never* live across a yield. We can do this because that operation is a compile-time constant, really, and thus the value doesn't need to be live across a yield. This might be worth doing as a size optimization regardless. Secondly, some of the proposals we've been kicking around for going further with simplifying include the idea of a distinct sort of temporaries that explicitly represent a "partially constructed that hasn't been used by the user". The idea was to allow borrowck (and other analyses) to trivially reconstruct the . We might want to add this interaction with auto-traits into the consideration for that design, and maybe it takes us some place (e.g., these special temporaries are not considered live for the purposes of auto traits). Having written out both of those options, though, I sort of lean towards the first, at least for this specific issue.
I think these references and raw pointers created by MIR construction should be marked as . They are not visible at the language level. They can be viewed as just prefetching the address of a static, so the compiler could pick any type it likes for it (, , , some compiler internal type) so it must not affect auto trait inference. Drop flags are ignored for similar reasons. You cannot use an auto trait like this to detect them: So I think that should be reverted and the temporary static references should be marked as .
Note: opened instituting this change and I r+'d it, since fixing the regression seems pretty important and time is of the essence; there is general consensus here on the thread; this is only restoring older behavior. In particular, there were some suggestions that this might be a lang team issue; I think there is some 'intersection' and I don't want the perception that I'm trying to shortcircuit discussion. That said, I also think this is primarily a compiler team matter, since it's a deviation from the old behavior, and further this deviation was caused by altering the MIR away from the "natural, Rust-based" definition and towards a lower-level definition.

<ins> // build-pass #![feature(generators)] static mut A: [i32; 5] = [1, 2, 3, 4, 5]; fn is_send_sync<T: Send + Sync>(_: T) {} fn main() { unsafe { let gen_index = static || { let u = A[{ yield; 1 }]; }; let gen_match = static || match A { i if { yield; true } => { () } _ => (), }; is_send_sync(gen_index); is_send_sync(gen_match); } } </ins>


Question: Hello, this is your friendly neighborhood mergebot. After merging PR rust-lang/rust, I observed that the tool clippy-driver no longer builds. A follow-up PR to the repository is needed to fix the fallout. cc do you think you would have time to do the follow-up work? If so, that would be great! cc the PR reviewer, and nominating for compiler team prioritization.

<del> Subproject commit c807fbc8ba41432388b6f590668ba81314c07c32 </del> <ins> Subproject commit d9e38f57c125c5ac50397ec8a006fe49f17cd96c </ins>


Question:
results in: Removing the constgenerics feature flag gets the expected error message: (IIUC that itself is a bug related to ) Using directly outside of a const-context works, which I guess is something const_generics enables that isn't otherwise allowed. Finally, the error message is the same whether or not the code is in a provided method or a impl block; I actually ran into the bug in the later.
I believe this should be fixed by
Now, it shows different ICE(s) ():
Now ICE no longer occurs. I think it's fixed by .

<ins> // build-fail // ignore-emscripten no asm! support // Regression test for #69092 #![feature(asm)] fn main() { unsafe { asm!(".ascii "Xen0""); } //~^ ERROR: <inline asm>:1:9: error: expected string in '.ascii' directive } </ins>


Question:
results in: Removing the constgenerics feature flag gets the expected error message: (IIUC that itself is a bug related to ) Using directly outside of a const-context works, which I guess is something const_generics enables that isn't otherwise allowed. Finally, the error message is the same whether or not the code is in a provided method or a impl block; I actually ran into the bug in the later.
I believe this should be fixed by
Now, it shows different ICE(s) ():
Now ICE no longer occurs. I think it's fixed by .

<ins> error: <inline asm>:1:9: error: expected string in '.ascii' directive .ascii "Xen ^ --> $DIR/issue-69092.rs:8:14 | LL |     unsafe { asm!(".ascii "Xen0""); } |              ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error </ins>


Question:
results in: Removing the constgenerics feature flag gets the expected error message: (IIUC that itself is a bug related to ) Using directly outside of a const-context works, which I guess is something const_generics enables that isn't otherwise allowed. Finally, the error message is the same whether or not the code is in a provided method or a impl block; I actually ran into the bug in the later.
I believe this should be fixed by
Now, it shows different ICE(s) ():
Now ICE no longer occurs. I think it's fixed by .

<ins> // Regression test for #62504 #![feature(const_generics)] #![allow(incomplete_features)] trait HasSize { const SIZE: usize; } impl<const X: usize> HasSize for ArrayHolder<{ X }> { const SIZE: usize = X; } struct ArrayHolder<const X: usize>([u32; X]); impl<const X: usize> ArrayHolder<{ X }> { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) //~^ ERROR: array lengths can't depend on generic parameters } } fn main() { let mut array = ArrayHolder::new(); } </ins>


Question:
results in: Removing the constgenerics feature flag gets the expected error message: (IIUC that itself is a bug related to ) Using directly outside of a const-context works, which I guess is something const_generics enables that isn't otherwise allowed. Finally, the error message is the same whether or not the code is in a provided method or a impl block; I actually ran into the bug in the later.
I believe this should be fixed by
Now, it shows different ICE(s) ():
Now ICE no longer occurs. I think it's fixed by .

<ins> error: array lengths can't depend on generic parameters --> $DIR/issue-62504.rs:18:25 | LL |         ArrayHolder([0; Self::SIZE]) |                         ^^^^^^^^^^ error: aborting due to previous error </ins>


Question:
results in: Removing the constgenerics feature flag gets the expected error message: (IIUC that itself is a bug related to ) Using directly outside of a const-context works, which I guess is something const_generics enables that isn't otherwise allowed. Finally, the error message is the same whether or not the code is in a provided method or a impl block; I actually ran into the bug in the later.
I believe this should be fixed by
Now, it shows different ICE(s) ():
Now ICE no longer occurs. I think it's fixed by .

<ins> // Regression test for #67739 #![allow(incomplete_features)] #![feature(const_generics)] use std::mem; pub trait Trait { type Associated: Sized; fn associated_size(&self) -> usize { [0u8; mem::size_of::<Self::Associated>()]; //~^ ERROR: array lengths can't depend on generic parameters 0 } } fn main() {} </ins>


Question:
results in: Removing the constgenerics feature flag gets the expected error message: (IIUC that itself is a bug related to ) Using directly outside of a const-context works, which I guess is something const_generics enables that isn't otherwise allowed. Finally, the error message is the same whether or not the code is in a provided method or a impl block; I actually ran into the bug in the later.
I believe this should be fixed by
Now, it shows different ICE(s) ():
Now ICE no longer occurs. I think it's fixed by .

<ins> error: array lengths can't depend on generic parameters --> $DIR/issue-67739.rs:12:15 | LL |         [0u8; mem::size_of::<Self::Associated>()]; |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error </ins>


Question:
results in: Removing the constgenerics feature flag gets the expected error message: (IIUC that itself is a bug related to ) Using directly outside of a const-context works, which I guess is something const_generics enables that isn't otherwise allowed. Finally, the error message is the same whether or not the code is in a provided method or a impl block; I actually ran into the bug in the later.
I believe this should be fixed by
Now, it shows different ICE(s) ():
Now ICE no longer occurs. I think it's fixed by .

<ins> // Regression test for #58490 macro_rules! a { ( @1 $i:item ) => { a! { @2 $i } }; ( @2 $i:item ) => { $i }; } mod b { a! { @1 #[macro_export] macro_rules! b { () => () } } #[macro_export] macro_rules! b { () => () } //~^ ERROR: the name `b` is defined multiple times } mod c { #[allow(unused_imports)] use crate::b; } fn main() {} </ins>


Question:
results in: Removing the constgenerics feature flag gets the expected error message: (IIUC that itself is a bug related to ) Using directly outside of a const-context works, which I guess is something const_generics enables that isn't otherwise allowed. Finally, the error message is the same whether or not the code is in a provided method or a impl block; I actually ran into the bug in the later.
I believe this should be fixed by
Now, it shows different ICE(s) ():
Now ICE no longer occurs. I think it's fixed by .

<ins> error[E0428]: the name `b` is defined multiple times --> $DIR/issue-58490.rs:18:5 | LL |         macro_rules! b { () => () } |         -------------- previous definition of the macro `b` here ... LL |     macro_rules! b { () => () } |     ^^^^^^^^^^^^^^ `b` redefined here | = note: `b` must be defined only once in the macro namespace of this module error: aborting due to previous error For more information about this error, try `rustc --explain E0428`. </ins>


Question:
results in: Removing the constgenerics feature flag gets the expected error message: (IIUC that itself is a bug related to ) Using directly outside of a const-context works, which I guess is something const_generics enables that isn't otherwise allowed. Finally, the error message is the same whether or not the code is in a provided method or a impl block; I actually ran into the bug in the later.
I believe this should be fixed by
Now, it shows different ICE(s) ():
Now ICE no longer occurs. I think it's fixed by .

<ins> // check-pass // compile-flags: --emit=mir,link // Regression test for #60390, this ICE requires `--emit=mir` flag. fn main() { enum Inner { Member(u32) }; Inner::Member(0); } </ins>


Question: Hello, this is your friendly neighborhood mergebot. After merging PR rust-lang/rust, I observed that the tool miri no longer builds. A follow-up PR to the repository is needed to fix the fallout. cc do you think you would have time to do the follow-up work? If so, that would be great! cc the PR reviewer, and nominating for compiler team prioritization.

<del> Subproject commit 4da2b2149ca1c6a3331260dfcbb2175c51f2842d </del> <ins> Subproject commit 4e44aa010c4c7d616182a3078cafb39da6f6c0a2 </ins>