-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Resolve $crate at the expansion-local crate #99445
Conversation
r? @estebank (rust-highfive has picked a reviewer for you, use r? to override) |
Note: #99035 is marked as a regression because |
That's odd that I didn't run into this error locally. I'm worried that this means something is relying on |
This comment has been minimized.
This comment has been minimized.
Okay, I was able to reproduce locally, so I'll at least be able to take a look into this. |
I was able to confirm that something interesting is going on here: I'm not exactly sure how this ever worked in the first place tbqh. Some part of the proc-macro-hack is giving the emitted tokens a span in the declaration crate. With this change, as the macro tracing#![feature(trace_macros)]
trace_macros!(true);
fn main() {
let _ = unic_langid::langid!("en-us");
} With current nightly: ❯ cargo +nightly expand
Checking playground v0.0.0 (D:\git\cad97\playground)
warning: some trace filter directives would enable traces that are disabled statically
| `rustc_expand::mbe::quoted=debug` would enable the DEBUG level for the `rustc_expand::mbe::quoted` target
= note: the static max level is `info`
= help: to enable DEBUG logging, remove the `max_level_info` feature
note: trace_macro
--> src\main.rs:6:13
|
6 | let _ = unic_langid::langid!("en-us");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expanding `langid! { "en-us" }`
= note: to `{
#[derive($crate :: _proc_macro_hack_langid)] #[allow(dead_code)] enum
ProcMacroHack { Value = (stringify! { "en-us" }, 0).1, } proc_macro_call!
()
}`
= note: expanding `proc_macro_call! { }`
= note: to `unsafe
{
$crate :: LanguageIdentifier ::
from_raw_parts_unchecked(unsafe
{ $crate :: subtags :: Language :: from_raw_unchecked(28261u64) }, None,
Some(unsafe
{ $crate :: subtags :: Region :: from_raw_unchecked(21333u32) }), None)
}`
Finished dev [unoptimized + debuginfo] target(s) in 0.14s
#![feature(prelude_import)]
#![feature(trace_macros)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
fn main() {
let _ = {
#[allow(dead_code)]
enum ProcMacroHack {
Value = ("\"en-us\"", 0).1,
}
unsafe {
::unic_langid_macros::LanguageIdentifier::from_raw_parts_unchecked(
unsafe { ::unic_langid_macros::subtags::Language::from_raw_unchecked(28261u64) },
None,
Some(unsafe {
::unic_langid_macros::subtags::Region::from_raw_unchecked(21333u32)
}),
None,
)
}
};
} With this patch: ❯ cargo +stage1 expand
Checking playground v0.0.0 (D:\git\cad97\playground)
DEBUG rustc_expand::mbe::quoted $crate changed its target crate from DefId(19:0) to DefId(0:0)
note: trace_macro
--> src\main.rs:6:13
|
6 | let _ = unic_langid::langid!("en-us");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expanding `langid! { "en-us" }`
= note: to `{
#[derive($crate :: _proc_macro_hack_langid)] #[allow(dead_code)] enum
ProcMacroHack { Value = (stringify! { "en-us" }, 0).1, } proc_macro_call!
()
}`
= note: expanding `proc_macro_call! { }`
= note: to `unsafe
{
$crate :: LanguageIdentifier ::
from_raw_parts_unchecked(unsafe
{ $crate :: subtags :: Language :: from_raw_unchecked(28261u64) }, None,
Some(unsafe
{ $crate :: subtags :: Region :: from_raw_unchecked(21333u32) }), None)
}`
error[E0433]: failed to resolve: could not find `LanguageIdentifier` in the crate root
--> src\main.rs:6:13
|
6 | let _ = unic_langid::langid!("en-us");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in `$crate`
|
= note: this error originates in the macro `proc_macro_call` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this struct
|
3 | use unic_langid::LanguageIdentifier;
|
help: if you import `LanguageIdentifier`, refer to it directly
--> D:\.rust\cargo\registry\src\github.com-1ecc6299db9ec823\unic-langid-macros-0.9.0\src\lib.rs:4:1
4 - #[proc_macro_hack]
4 + #[proc_macro_hack]
|
error[E0433]: failed to resolve: unresolved import
--> src\main.rs:6:13
|
6 | let _ = unic_langid::langid!("en-us");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in `$crate::subtags`
|
= note: this error originates in the macro `proc_macro_call` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this struct
|
3 | use unic_langid::subtags::Language;
|
help: if you import `Language`, refer to it directly
--> D:\.rust\cargo\registry\src\github.com-1ecc6299db9ec823\unic-langid-macros-0.9.0\src\lib.rs:4:1
4 - #[proc_macro_hack]
4 + #[proc_macro_hack]
|
error[E0433]: failed to resolve: unresolved import
--> src\main.rs:6:13
|
6 | let _ = unic_langid::langid!("en-us");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in `$crate::subtags`
|
= note: this error originates in the macro `proc_macro_call` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this struct
|
3 | use unic_langid::subtags::Region;
|
help: if you import `Region`, refer to it directly
--> D:\.rust\cargo\registry\src\github.com-1ecc6299db9ec823\unic-langid-macros-0.9.0\src\lib.rs:4:1
4 - #[proc_macro_hack]
4 + #[proc_macro_hack]
|
For more information about this error, try `rustc --explain E0433`.
#![feature(prelude_import)]
#![feature(trace_macros)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
fn main() {
let _ = {
#[allow(dead_code)]
enum ProcMacroHack {
Value = ("\"en-us\"", 0).1,
}
unsafe {
crate::LanguageIdentifier::from_raw_parts_unchecked(
unsafe { crate::subtags::Language::from_raw_unchecked(28261u64) },
None,
Some(unsafe { crate::subtags::Region::from_raw_unchecked(21333u32) }),
None,
)
}
};
} |
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.
This looks good to me, but I'd feel more comfortable if @petrochenkov took a look at it too.
// FIXME: This is only a guess and it doesn't work correctly for `macro_rules!` | ||
// definitions actually produced by `macro` and `macro` definitions produced by | ||
// `macro_rules!`, but at least such configurations are not stable yet. | ||
ctxt = ctxt.normalize_to_macro_rules(); |
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.
Note: I removed this because it didn't change the behavior of any test (in the default compiler mode x.py test
), not because removing it was necessary.
In general, I'm not certain how much of this arm is still necessary now that we're directly giving $crate
a new mark when gluing it but at the very least removing the branch entirely didn't seem to work.
let mut expn = span.ctxt().outer_expn_data(); | ||
expn.parent = ExpnId::root(); | ||
let span = | ||
span.with_call_site_ctxt(LocalExpnId::fresh(expn, ctx).to_expn_id()); |
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.
Note to self: push the local change you made while testing to use Span::fresh_expansion
rather than with_call_site_ctxt
The job Click to see the possible cause of the failure (guessed by this bot)
|
// as described in `SyntaxContext::apply_mark`, so we ignore prepended opaque marks. | ||
// FIXME: This is only a guess and it doesn't work correctly for `macro_rules!` | ||
// definitions actually produced by `macro` and `macro` definitions produced by | ||
// `macro_rules!`, but at least such configurations are not stable yet. |
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.
We may need to test the 3 combinations: macro_rules in macro_rules (existing), macro_rules inside macro, macro inside macro_rules.
This is a tricky area and I need to look at this, but I won't be able to do it very soon, maybe in a week or two. |
I just want to say that while (I think) this approach works as I desired, this isn't the "ideal" way to handle The "perfect world semantics" of |
I need to refresh hygiene details in my memory before reviewing this PR and #100387, it will require at least one full working day. |
☔ The latest upstream changes (presumably #102644) made this pull request unmergeable. Please resolve the merge conflicts. |
FWIW, I really dislike what this PR does. Imagine that you have the same situation with macros 2.0 and proper def-site macro outer {
macro inner {
crate::Struct // outer_crate::Struct
}
} What would you do to switch macro outer {
macro inner {
#crate::Struct // inner_crate::Struct
}
} , and same with $crate macro outer {
macro inner {
$#crate::Struct // inner_crate::Struct
}
} Switching to call-site hygiene is a separate (not yet implemented) feature, it doesn't seem right to me to bolt it on |
(I'm interested in someone pursuing #99447 (comment) tho.) |
So, I both agree and disagree with this interpretation. I agree that this PR's implementation is suboptimal, but I disagree that My model is that There is no " impl MacroExpansionContext {
fn expand(binder: Ident) -> TokenStream {
if (binder == kw::crate) {
#[cfg(current-behavior)] {
Ident::new(kw::crate, Span::def_site_at(binder))
}
#[cfg(expander-model)] {
Ident::new(kw::crate, Span::def_site_at(self))
}
} else {
self.resolve_binding(binder)
}
}
} |
@CAD97 |
This is pending deciding what the correct behavior is, as far as I'm aware. I opened a Zulip thread to discuss. |
Zulip thread opened for T-lang (I'll add the relevant label to remind me of that) @rustbot label +t-lang |
Copypasting the status from Zulip thread:
|
I was writing a (probably overly long) post about my opinion/status here when I reached a conclusion I hadn't before: Thus, As such, I'm going to close this PR since I now agree that this isn't the correct approach, at least not on its own. The ability to name the crate of a macro expanded macro definition is still desirable, but that can be filed into the same expressive gap as naming the defining module. If we can at least make attempts to use |
Fixes #99035. The glued
$crate
token now gets the resolution context of the local crate when gluing$crate
into a single token. This is almost certainly what is intended by a macro author.This does change the behavior of stable code. Specifically, previously
$crate
would resolve to the crate of thecrate
token, and if a macro uses a tt binder that expands to$
, it is possible for it to replicate the behavior made much more accessible by$$crate
.However, this behavior really isn't all that desirable. If a
crate
token is passed in, it already resolves to its local crate, so turning it into a$crate
token is a resolution no-op. If amacro_rules!
definition wants a def-sitecrate
, it can just write$crate
. The current behavior of$crate
becoming a def-site version of thecrate
token is not useful;$crate
resolving to the gluing crate is.Except... it looks like this is allowing proc-macro-hacked proc-macros to use
$crate
to refer to the declaration crate...