-
-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Fix for ICE: eii: fn / macro rules None in find_attr() #150822
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
|
r? @chenyukang rustbot has assigned @chenyukang. Use |
This comment has been minimized.
This comment has been minimized.
5107b80 to
b56c43f
Compare
This comment has been minimized.
This comment has been minimized.
| extern_item | ||
| } | ||
| EiiImplResolution::Known(decl, _) => decl.eii_extern_target, | ||
| EiiImplResolution::Error(_eg) => continue, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was this _eg a leftover from some logic here? i see the same pattern in many places (where you match for error), could you explain this a little, cuz it's not really obvious to me why we want to skip errors
also it would be nice to clean up this unusable variables a bit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, it's just a good reminder that if we get there, we're allowed to skip it because an error is already emitted.
I tried to separate out the logic of this, but I don't think I prefer it. A method on EiiImplResolution would make sense, but we need the tcx which we don't have in rustc_hir, so the signature would be super awkward, requiring an FnOnce to be passed in or something to get the attributes. I really did consider it but I personally believe this is nicest
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And yea, the eg is technically never used. I just wanted to make sure for myself I wouldn't accidentally skip EIIs without having a very good reason for it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, that makes sense, will continue looking into this pr, not sure how much time it will take, i hopefully might finish it later today (it's a jan 9th and it's a bit late at my place)
i dit a quick glance a first 4-5 commits, looks fine overall
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks kivoo! You're amazing
|
r? me |
b56c43f to
7dcaba2
Compare
7dcaba2 to
7791bc2
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
@rustbot review (rebased on the other PR) |
|
this all looks good to me, i'm in pretty much favour of how the eii is now resolving with this changes let's wait on what ci thinks on this matter |
|
thanks for working on it :) |
Rollup of 9 pull requests Successful merges: - #149318 (Implement partial_sort_unstable for slice) - #150805 (Fix ICE in inline always warning emission.) - #150822 (Fix for ICE: eii: fn / macro rules None in find_attr()) - #150853 (std: sys: fs: uefi: Implement File::read) - #150855 (std: sys: fs: uefi: Implement File::tell) - #150881 (Fix std::fs::copy on WASI by setting proper OpenOptions flags) - #150891 (Fix a trivial typo in def_id.rs) - #150892 (Don't check `[mentions]` paths in submodules from tidy) - #150894 (cg_llvm: add a pause to make comment less confusing) r? @ghost
Rollup merge of #150822 - fix-149981, r=@Kivooeo Fix for ICE: eii: fn / macro rules None in find_attr() Closes #149981 This used to ICE: ```rust macro_rules! foo_impl {} #[eii] fn foo_impl() {} ``` `#[eii]` generates a macro (called `foo_impl`) and a default impl. So the partial expansion used to roughly look like the following: ```rust macro_rules! foo_impl {} // actually resolves here extern "Rust" { fn foo_impl(); } #[eii_extern_target(foo_impl)] macro foo_impl { () => {}; } const _: () = { #[implements_eii(foo_impl)] // assumed to name resolve to the macro v2 above fn foo_impl() {} }; ``` Now, shadowing rules for macrov2 and macrov1 are super weird! Take a look at this: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=23f21421921360478b0ec0276711ad36 So instead of resolving to the macrov2, we resolve the macrov1 named the same thing. A regression test was added to this, and some span_delayed_bugs were added to make sure we catch this in the right places. But that didn't fix the root cause. To make sure this simply cannot happen again, I made it so that we don't even need to do a name resolution for the default. In other words, the new partial expansion looks more like: ```rust macro_rules! foo_impl {} extern "Rust" { fn foo_impl(); // resolves to here now!!! } #[eii_extern_target(foo_impl)] macro foo_impl { () => {}; } const _: () = { #[implements_eii(known_extern_target=foo_impl)] // still name resolved, but directly to the foreign function. fn foo_impl() {} }; ``` The reason this helps is that name resolution for non-macros is much more predictable. It's not possible to have two functions like that with the same name in scope. We used to key externally implementable items off of the defid of the macro, but now the unique identifier is the foreign function's defid which seems much more sane. Finally, I lied a tiny bit because the above partial expansion doesn't actually work. ```rust extern "Rust" { fn foo_impl(); // not to here } const _: () = { #[implements_eii(known_extern_target=foo_impl)] // actually resolves to this function itself fn foo_impl() {} // <--- so to here }; ``` So the last few commits change the expansion to actually be this: ```rust macro_rules! foo_impl {} extern "Rust" { fn foo_impl(); // resolves to here now!!! } #[eii_extern_target(foo_impl)] macro foo_impl { () => {}; } const _: () = { mod dflt { // necessary, otherwise `super` doesn't work use super::*; #[implements_eii(known_extern_target=super::foo_impl)] // now resolves to outside the `dflt` module, so the foreign item. fn foo_impl() {} } }; ``` I apologize to whoever needs to review this, this is very subtle and I hope this makes it clear enough 😭.
Closes #149981
This used to ICE:
#[eii]generates a macro (calledfoo_impl) and a default impl. So the partial expansion used to roughly look like the following:Now, shadowing rules for macrov2 and macrov1 are super weird! Take a look at this: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=23f21421921360478b0ec0276711ad36
So instead of resolving to the macrov2, we resolve the macrov1 named the same thing.
A regression test was added to this, and some span_delayed_bugs were added to make sure we catch this in the right places. But that didn't fix the root cause.
To make sure this simply cannot happen again, I made it so that we don't even need to do a name resolution for the default. In other words, the new partial expansion looks more like:
The reason this helps is that name resolution for non-macros is much more predictable. It's not possible to have two functions like that with the same name in scope.
We used to key externally implementable items off of the defid of the macro, but now the unique identifier is the foreign function's defid which seems much more sane.
Finally, I lied a tiny bit because the above partial expansion doesn't actually work.
So the last few commits change the expansion to actually be this:
I apologize to whoever needs to review this, this is very subtle and I hope this makes it clear enough 😭.