You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
rustfmt fails to resolve mod foo; decorated by an attribute macro #6959
#[my_macro] mod foo; (an "outlined" module supplied to an attribute/derive proc
macro) was recently stabilized on nightly by rust-lang/rust#157857.
In this form the module body can be provided by the macro, so there is intentionally
no foo.rs / foo/mod.rs on disk.
rustfmt, however, seems unconditionally try to resolve every mod foo; to a file
on disk and aborts the entire run when the file is missing, regardless of whether
the module is decorated by an attribute macro.
Expected behavior
rustfmt formats the file (or at least leaves the #[my_macro] mod foo; item
untouched and continues) without requiring a foo.rs file to exist on disk,
since the attribute macro provides the module body.
Actual behavior
rustfmt aborts with a module resolution error and exits non-zero:
Error writing files: failed to resolve mod `foo`: /tmp/foo.rs does not exist
Configuration
Nothing special. Nightly rustfmt.
Reproduction Steps
> cat test.rs
#[my_macro]
mod foo;
> rustfmt +nightly --edition 2024 test.rs
Error writing files: failed to resolve mod `foo`: /tmp/foo.rs does not exist
Nightly rust currently accepts this code (after replacing the placeholder with a real proc-macro that supports this syntax).
I had no idea that #[my_macro] was even a thing. Is rust-lang/rust#54727 the right tracking issue for this?
So basically if rustfmt sees a #[my_macro] over a module declaration then it shouldn't try to resolve it? @zhoukezi let me know if I'm understanding that correctly.
As far as I know, rust-lang/rust#54727 is the larger tracking issue for #![feature(proc_macro_hygiene)], of which #[my_macro] mod foo; is a part. #[my_macro] mod foo; itself was discussed in rust-lang/rust#54727 (comment) and independently stabilized in rust-lang/rust#157857. I'm not entirely sure whether rust-lang/rust#54727 is the right reference in your context.
So basically if rustfmt sees a #[my_macro] over a module declaration then it shouldn't try to resolve it?
I think that would address the issue I'm running into. rust-lang/rust#157857 passes mod foo; as tokens directly to #[my_macro], so there's no reason to assume foo.rs exists on disk, or even that the macro will emit any module at all. That said, to be cautious, I'm not sure whether this would affect rustfmt's own internals or other edge cases. mod is admittedly special syntax.
For my use case, the module always really exists (even when annotated with #[my_macro]), so I never ran into this. Annotating the module with #[rustfmt::skip] seems to work to suppress the error.
Maybe rustfmt could just fail more gracefully if it cannot resolve a module, if that module is also annotated with a custom proc macro?
Can rustfmt try to load the module (there's a good chance that the module will indeed be there), and not report anything if the module loading fails?
@petrochenkov I think your idea could work. We could special case the fallback behavior for#[my_macro] to just ignore errors and move on. I feel like it's probably okay to special case things for #[my_macro], but I'm not sure I'd want to ignore module resolution errors in all cases.
In the example above rustfmt will try to load mod foo;, which fails. Even if modules are annotated with #[cfg(false)] rustfmt will try to find the file that the module corresponds to (unless you're running rustfmt with --skip-children or via stdin).
Activity
ytmimi commentedon Jul 16, 2026
I had no idea that
#[my_macro]was even a thing. Is rust-lang/rust#54727 the right tracking issue for this?So basically if rustfmt sees a
#[my_macro]over a module declaration then it shouldn't try to resolve it? @zhoukezi let me know if I'm understanding that correctly.zhoukezi commentedon Jul 20, 2026
@ytmimi
As far as I know, rust-lang/rust#54727 is the larger tracking issue for
#![feature(proc_macro_hygiene)], of which#[my_macro] mod foo;is a part.#[my_macro] mod foo;itself was discussed in rust-lang/rust#54727 (comment) and independently stabilized in rust-lang/rust#157857. I'm not entirely sure whether rust-lang/rust#54727 is the right reference in your context.I think that would address the issue I'm running into. rust-lang/rust#157857 passes
mod foo;as tokens directly to#[my_macro], so there's no reason to assumefoo.rsexists on disk, or even that the macro will emit any module at all. That said, to be cautious, I'm not sure whether this would affect rustfmt's own internals or other edge cases.modis admittedly special syntax.TimNN commentedon Jul 21, 2026
For my use case, the module always really exists (even when annotated with
#[my_macro]), so I never ran into this. Annotating the module with#[rustfmt::skip]seems to work to suppress the error.Maybe rustfmt could just fail more gracefully if it cannot resolve a module, if that module is also annotated with a custom proc macro?
petrochenkov commentedon Jul 21, 2026
Can rustfmt try to load the module (there's a good chance that the module will indeed be there), and not report anything if the module loading fails?
How does rustfmt work with cases like this?
ytmimi commentedon Jul 21, 2026
@petrochenkov I think your idea could work. We could special case the fallback behavior for
#[my_macro]to just ignore errors and move on. I feel like it's probably okay to special case things for#[my_macro], but I'm not sure I'd want to ignore module resolution errors in all cases.In the example above rustfmt will try to load
mod foo;, which fails. Even if modules are annotated with#[cfg(false)]rustfmt will try to find the file that the module corresponds to (unless you're running rustfmt with--skip-childrenor via stdin).Rollup merge of rust-lang#159737 - ytmimi:rustfmt_issue_6959, r=petro…
Rollup merge of rust-lang#159737 - ytmimi:rustfmt_issue_6959, r=petro…
Rollup merge of #159737 - ytmimi:rustfmt_issue_6959, r=petrochenkov