-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Erase all regions before constructing an LLVM type #77196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Fixes rust-lang#55976 Previously, we only erased early-bound regions. However, two types that differ only in their regions (including late-bound regions) are indistinguishable to LLVM, so it's safe to erase all regions.
(rust_highfive has picked a reviewer for you, use r? to override) |
@bors try @rust-timer queue |
Awaiting bors try build completion |
⌛ Trying commit 0446a73 with merge da15df4c276090851136ca9a686285f76cbaaf98... |
☀️ Try build successful - checks-actions, checks-azure |
Queued da15df4c276090851136ca9a686285f76cbaaf98 with parent b984ef6, future comparison URL. |
None of the most relevant people seem to do reviews right now. |
Finished benchmarking try commit (da15df4c276090851136ca9a686285f76cbaaf98): comparison url. Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. Please note that if the perf results are neutral, you should likely undo the rollup=never given below by specifying Importantly, though, if the results of this run are non-neutral do not roll this PR up -- it will mask other regressions or improvements in the roll up. @bors rollup=never |
@eddyb: Are there any changes that you'd like me to make? |
Sorry for not seeing this earlier (please PM on e.g. Zulip if you're blocked on me for anything). Traditionally we've avoided this because projections can observe a difference in bound lifetimes. In other words, this PR introduces unsoundness: it should be possible to cause some transmuting to happen (through safe code) by having the same trait implemented for What we've done instead is aggressive LLVM casting everywhere to handle subtyping (I recall @pnkfelix was involved). At some point (while @RalfJung was trying to do some type checks in miri) I've suggested doing "variance-based erasing of bound lifetimes", along the lines of "projections will introduce invariance and therefore bound lifetimes nested in covariant/contravariant positions should be safe to erase" (assuming the type then doesn't touch the trait system, maybe we should have a variation on I'm tempted to close this, unless you plan to reuse the PR for a different implementation. Feel free to PM me if you want to discuss this further or come up with a test that shows the unsoundness full erasure introduces. r? @nikomatsakis for the time being |
In Zulip PMs with @Aaron1011 I came up with this sketch, but I don't think it was ever tested: trait Trait<T> {
type Assoc;
}
impl<T> Trait<T> for fn(&()) {
type Assoc = T;
}
impl<'a, T> Trait<T> for fn(&'a ()) {
type Assoc = ();
}
#[repr(C)]
struct Union<T, U, F: Trait<U>> {
to: F::Assoc,
from: T,
}
pub fn transmute<T, U>(x: T) -> U {
Union::<Option<T>, Option<U>, fn(&())> { to: None, from: Some(x) }.to.unwrap()
} With full erasure, |
Fixes #55976
Previously, we only erased early-bound regions. However, two types that
differ only in their regions (including late-bound regions) are
indistinguishable to LLVM, so it's safe to erase all regions.