Avoid computing layout of enums with non-int discriminants#157562
Avoid computing layout of enums with non-int discriminants#157562sjwang05 wants to merge 1 commit into
Conversation
|
This PR changes a file inside |
|
r? @Kivooeo rustbot has assigned @Kivooeo. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
I don't expect the loop to impact perf significantly, since later on in the same function we construct an iterator by calling |
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Avoid computing layout of enums with non-int discriminants
This comment has been minimized.
This comment has been minimized.
183e882 to
0ba35a5
Compare
This comment was marked as resolved.
This comment was marked as resolved.
0ba35a5 to
88d314a
Compare
|
Thanks for pointing that out, the previous version caused a cycle error, so now we just check the cached typeck results to see if those have errors instead of trying to const-eval the discriminant. |
This comment has been minimized.
This comment has been minimized.
|
This PR is still technically a breaking change, since now the following code fails to compile: pub trait Trait {
type Assoc;
}
impl Trait for [u8; 0] {
type Assoc = isize;
}
pub enum Foo {
One = unsafe { std::mem::zeroed::<<[u8; size_of::<Foo>()] as Trait>::Assoc>() },
}Error with this PR |
|
Might be an acceptable breaking change? Not sure. Would require a crater run if we go ahead with this. |
|
Finished benchmarking commit (023d36e): comparison URL. Overall result: no relevant changes - no action neededBenchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up. @rustbot label: -S-waiting-on-perf -perf-regression Instruction countThis perf run didn't have relevant results for this metric. Max RSS (memory usage)This perf run didn't have relevant results for this metric. CyclesResults (primary -2.2%, secondary -3.3%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 514.705s -> 515.476s (0.15%) |
|
Thanks, it turns out that this simpler version causes the same error with this PR for the same reason: use std::mem::size_of;
pub enum Foo {
One = size_of::<[u8; size_of::<Foo>()]>() as isize,
}When type-checking I looked into why this doesn't cause the same query cycles on stable/nightly, and it turns out this code, with 2 variants instead of 1, doesn't compile on both current stable and nightly: use std::mem::size_of;
pub trait Trait {
type Assoc;
}
impl Trait for [u8; 0] {
type Assoc = isize;
}
pub enum Foo {
One = unsafe { std::mem::zeroed::<<[u8; size_of::<Foo>()] as Trait>::Assoc>() },
Two,
}stable playground link It seems like the reason why this happens for 2+ variants but not 1 is because the I do definitely think a crater run is still warranted. |
|
Preparing for crater run. @bors try |
This comment has been minimized.
This comment has been minimized.
Avoid computing layout of enums with non-int discriminants
|
💥 Test timed out after |
|
🚧 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
|
🎉 Experiment
Footnotes
|
|
Given that there's no regressions in crater I think it should be fine to merge as-is? Or it still needs an FCP (t-lang for example)? |
|
I think it'd be fine to merge as-is? Since the multiple-discr case is already broken with the same cycle error; this PR just makes it happen for the single-discr case as well. But I'm not sure either, maybe someone from t-lang or something might think differently. |
|
This makes sense to me. We're signing off on the breaking change (with no observed breakage). Anyone else want in on this FCP? (E.g., @rust-lang/types, @rust-lang/opsem.) Let me know if so and I'll propose again. @rfcbot fcp merge lang |
|
@traviscross has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
This comment was marked as off-topic.
This comment was marked as off-topic.
|
While I think as a pure consistency of the impl thing without real interesting language implications this should just have been a types FCP, I think it's a no-brainer so let's just land it. |
|
I haven't sorted my thoughts here but the vibes feel off to me about doing a lang FCP for having a new edge between two queries in the compiler. I would expect that we wind up introducing new query edges all the time in ways that might cause additional query cycles (though I'm not sure...) and doing a lang FCP every time that happens seems like a lot 🤔 Similarly I don't think it makes sense for types or opsem to be on this FCP? There isn't really anything type system or opsem related, the only thing that's actually being signed off on is the (zero) breakage caused by calling a query at an earlier point in the compiler. This feels like the kind of thing I would be comfortable just passing off to pretty much any T-compiler reviewer 🤔 |
|
Happy to say that trickiness like this with size_of we can break in this case, so @rfcbot reviewed That said, I'm definitely sympathetic to whether there's actually a spec-level question here. I can't imagine that which queries are triggered when and exactly which things trigger cycle errors is something that we're writing into the spec? If so, then maybe there isn't a FCP thing? But also if there's a known breakage caused there should be anyway? Torn. I guess if nothing else just having the FCP so people are warning in TWiR is good. |
|
@rfcbot reviewed |
|
🔔 This is now entering its final comment period, as per the review above. 🔔 |
So I agree that queries are not part of the spec. I do think that "what requires what" at some level should be part of the spec, in so far as it accepts what programs are accepted. |
|
@rfcbot reviewed |
|
The way I see the FCP is that we are approving a change to the language spec, even though that section is currently imaginary (the language is underspecified by the reference). I think the simplest model is one where lang, or one of its delegated subteams, approve those changes. This is consistent with how the types team operates, because they have a dual lang/compiler role. On the lang side, they manage a jagged subset of the design space where the only specification we have is the implementation. In creating the team, lang delegated to their best judgment how to adapt that implementation toward a smoother language over time, one we can better reason about and specify in the long run. I expect that as that continues, they will naturally start to own parts of the reference text. |
View all comments
Currently, enums with explicit non-int discriminants, such as
1..=10, correctly error with E0308 and E0732 during typeck. However,layout_ofnever sees this error, sinceAdtDef::discriminants()falls back to a default value wheneval_explicit_discrreturns anErr, causing the layout of the enum to be broken. If this enum then appears in a promoted, we expect CTFE to fail; however, sincelayout_oftechnically "succeeded," just with a broken layout, our enum isn't inallowed_in_infallible, so CTFE expects it to succeed. CTFE failing then causes us to ICE with"interpret const eval failure of...which is not in required_consts".This PR modifies
layout_of_uncachedincompiler/rustc_ty_utils/src/layout.rsto typeck all explicit enum discriminants before computing layout, and early-returns with aLayoutError::ReferncesErrorif eval fails. CTFE then sees thisLayoutErrorasallowed_in_infallible, avoiding the ICE.fixes #138660