-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
proc_macro! expansion can refer to items defined in the root w/o importing them #50504
Comments
@petrochenkov do you know if this might be related to #50050? The hygiene here is indeed quite suspicious |
This looks like a different issue to me at a first glance (but we need to check on older releases whether this is a regression or not). |
@petrochenkov oh this is using the |
Looks like this is a bug on stable Rust -- // foo.rs
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::*;
#[proc_macro_derive(Foo)]
pub fn foo1(a: TokenStream) -> TokenStream {
drop(a);
"mod __bar { static mut BAR: Option<Something> = None; }".parse().unwrap()
} // bar.rs
#[macro_use]
extern crate foo;
struct Something;
#[derive(Foo)]
struct Another;
fn main() {}
|
cc @nrc, you may want to take a look at this as well, especially because it's a bug on stable Rust which fixing may cause a lot of regressions |
This looks correct to me - aiui we use call-site hygiene for proc macros, and so we're using the hygiene context from where |
@nrc hm but we've been advocating that "hygiene" in expanded macros for 1.1/1.2 is basically "copy/paste" hygiene, but in this case it's not? |
No, this is very much a limitation of the hygiene algorithm here - in the proper hygiene setup when you create a new scope in a macro, you get a combination of the hygiene info for the new scope plus the 'base scope'. The intuition you want is that the base scope is the call-site (that gives 'copy and paste' hygiene). However, the macros 1.1/1.2 algorithm is essentially the base scope everywhere (i.e., we ignore any scopes introduced by the macro) and the base scope is the call site. |
@nrc |
Even more alarming example: // foo.rs
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::*;
#[proc_macro_derive(Foo)]
pub fn foo1(_: TokenStream) -> TokenStream {
"
struct Outer;
mod inner {
type Inner = Outer; // `Outer` shouldn't be available from here
}
".parse().unwrap()
} // bar.rs
#![allow(unused)]
#[macro_use]
extern crate foo;
#[derive(Foo)] // OK?!
struct Dummy;
fn main() {} I.e. the current implementation of call-site hygiene effectively flattens any module structures existing inside the macro. |
Perhaps we need to add some extra feature gate for macros generating modules? |
Yeah if this is the current state of hygiene then I'd want to definitely gate modules from being in the output of procedural macros and procedural attributes. I'd ideally prefer to aggressviely start warning against modules in the output of custom derive as well. |
I've posted #50587 to help evaluate the impact of forbidding modules from being generated by procedural derive macros |
Given the crater results it seems clear that we cannot retroactively prevent custom derive from generating modules. Current "offenders" are:
My PR purely disallowed I'd still like to gate such features by default for maros 1.2 (attributes and bang macros) as I'd like to avoid worsening this problem further |
I've opened #50820 to separately gate procedural bang and attribute macros, and will leave custom derive alone for now. |
This commit feature gates generating modules and macro definitions in procedural macro expansions. Custom derive is exempt from this check as it would be a large retroactive breaking change (rust-lang#50587). It's hoped that we can hopefully stem the bleeding to figure out a better solution here before opening up the floodgates. The restriction here is specifically targeted at surprising hygiene results [1] that result in non-"copy/paste" behavior. Hygiene and procedural macros is intended to be avoided as much as possible for Macros 1.2 by saying everything is "as if you copy/pasted the code", but modules and macros are sort of weird exceptions to this rule that aren't fully fleshed out. [1]: rust-lang#50504 (comment) cc rust-lang#50504
rustc: Disallow modules and macros in expansions This commit feature gates generating modules and macro definitions in procedural macro expansions. Custom derive is exempt from this check as it would be a large retroactive breaking change (#50587). It's hoped that we can hopefully stem the bleeding to figure out a better solution here before opening up the floodgates. The restriction here is specifically targeted at surprising hygiene results [1] that result in non-"copy/paste" behavior. Hygiene and procedural macros is intended to be avoided as much as possible for Macros 1.2 by saying everything is "as if you copy/pasted the code", but modules and macros are sort of weird exceptions to this rule that aren't fully fleshed out. [1]: #50504 (comment) cc #50504
Looks like this issue is going to be fixed as well as a part of #50050. |
This is not #50050, but a separate issue after all.
EDIT: Expansion IDs remaining unassociated with positions in module system are indeed an issue (fixed in #51952), but the issue was caused by other reason, namely this fallback in name resolution rust/src/librustc_resolve/lib.rs Lines 1948 to 1961 in 0c0315c
that worked for all proc macros 2.0 and declarative macros 2.0. #51952 removes this fallback from all macros except for proc macro derives, in which it's reported as a compatibility warning. |
hygiene: Decouple transparencies from expansion IDs Fixes #50504 in accordance with [this comment](#50504 (comment)).
hygiene: Decouple transparencies from expansion IDs And remove fallback to parent modules during resolution of names in scope. This is a breaking change for users of unstable macros 2.0 (both procedural and declarative), code like this: ```rust #![feature(decl_macro)] macro m($S: ident) { struct $S; mod m { type A = $S; } } fn main() { m!(S); } ``` or equivalent ```rust #![feature(decl_macro)] macro m($S: ident) { mod m { type A = $S; } } fn main() { struct S; m!(S); } ``` stops working due to module boundaries being properly enforced. For proc macro derives this is still reported as a compatibility warning to give `actix_derive`, `diesel_derives` and `palette_derive` time to fix their issues. Fixes rust-lang#50504 in accordance with [this comment](rust-lang#50504 (comment)).
This resolves a warning introduced in rust-lang/rust#51952 that will eventually become a hard error, the latter of which is being tracked in rust-lang/rust#50504.
How can I fix these errors now? warning: cannot find type `users` in this scope
--> src/models.rs:45:37
|
45 | #[derive(Debug, Clone, AsChangeset, Insertable, Serialize, Deserialize)]
| ^^^^^^^^^^ names from parent modules are not accessible without an explicit import
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504> |
@vityafx unfortunately as a user you can't do anything to fix that error, the fix would need to be in diesel's |
Here is an example of how to suppress the warning: |
Nitpicking on @lukedupin solution; maybe better adding:
at the top of your files that trigger the warning. Setting an env variable somehow invalidates the compiler cache, therefore:
and:
are not the same and running one or the another will trigger a full (possible long) rebuild; f.e. your IDE may use |
Stabilize a few secondary macro features - `tool_attributes` - closes rust-lang#44690 - `proc_macro_path_invoc` - this feature was created due to issues with tool attributes (rust-lang#51277), those issues are now fixed (rust-lang#52841) - partially `proc_macro_gen` - this feature was created due to issue rust-lang#50504, the issue is now fixed (rust-lang#51952), so proc macros can generate modules. They still can't generate `macro_rules` items though due to unclear hygiene interactions.
Stabilize a few secondary macro features - `tool_attributes` - closes #44690 - `proc_macro_path_invoc` - this feature was created due to issues with tool attributes (#51277), those issues are now fixed (#52841) - partially `proc_macro_gen` - this feature was created due to issue #50504, the issue is now fixed (#51952), so proc macros can generate modules. They still can't generate `macro_rules` items though due to unclear hygiene interactions.
* removed some (useless?) output * also ran clippy, note there is a warning about: ``` warning: cannot find type `As` in this scope --> src/oracle/query_builder/alias.rs:17:24 | 17 | #[derive(Debug, Clone, QueryId)] | ^^^^^^^ names from parent modules are not accessible without an explicit import | = note: #[warn(proc_macro_derive_resolution_fallback)] on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #50504 <rust-lang/rust#50504> ``` which seems to be fixed with diesel-rs/diesel#1787 which has not been released yet
@apiraino I'd like to add a small but important correction to what you wrote, which suggested using an outer attribute, prefixed with #![allow(proc_macro_derive_resolution_fallback)] This uses an inner attribute, prefixed with |
Btw, I'm getting these kind of warnings also for diesel's AsChangeset, Insertable, Associations, Identifiable, Queryable and QueryableByName. |
I feel like there's a bug with the lint itself. My proc macro expands to the following (example taken from its unit test, slightly modified to demonstrate the problem): // Not a part of actual macro output, but is instead present at call site. I'm parsing the input struct's type
// specificially (the macro is a derive macro), so it's fine to avoid fully qualifying it, since use super::*;
// will take care of everything.
use std::time::SystemTime;
mod entries {
use super::*;
#[doc = "The entry identifier type for the `field` field in the `MyConfigTable` config table."]
pub enum Field {}
impl ::snec::Entry for Field {
type Data = SystemTime; // This is not in the prelude
const NAME: &'static str = "field";
}
};
... The Even though I'm completely not familiar with the implementation of the lint itself, I suspect that the culprit is that it simply checks for relative names which would are valid outside the module. I don't know whether it's implemented like this though, that's just a wild guess. |
Apologies if this has already been reported; I didn't search too hard.
STR
This code compiles but I would expect it not to because the expanded form doesn't compile:
Meta
cc @jseyfried
The text was updated successfully, but these errors were encountered: