ICE in special `cfg_if` handling
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 7k
- Forks
- 1.1k
- Avg merge
- 2d 13h
- Merged PRs (30d)
- 24
Description
If you invoke any macro named cfg_if with starting with if and not following the rules of the macro of the same name provided by the cfg-if crate, rustfmt will panic.
Here is a minimal example to reproduce the issue:
cfg_if! {
if
}
Output when running RUST_BACKTRACE=1 rustfmt +stable lib.rs:
error: internal compiler error: the following error was constructed but not emitted
error: expected `#`, found `<eof>`
--> lib.rs:2:5
|
2 | if
| ^^
thread 'main' panicked at 'explicit panic', compiler/rustc_errors/src/diagnostic_builder.rs:553:21
stack backtrace:
0: rust_begin_unwind
at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/std/src/panicking.rs:584:5
1: core::panicking::panic_fmt
at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/panicking.rs:143:14
2: core::panicking::panic
at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/panicking.rs:48:5
3: <rustc_errors::diagnostic_builder::DiagnosticBuilderInner as core::ops::drop::Drop>::drop
4: rustfmt_nightly::parse::macros::cfg_if::parse_cfg_if_inner
5: <rustfmt_nightly::modules::visitor::CfgIfVisitor as rustc_ast::visit::Visitor>::visit_mac_call
6: rustc_ast::visit::walk_item::<rustfmt_nightly::modules::visitor::CfgIfVisitor>
7: <rustfmt_nightly::modules::ModResolver>::visit_cfg_if
8: <rustfmt_nightly::modules::ModResolver>::visit_mod_from_ast
9: <rustfmt_nightly::modules::ModResolver>::visit_crate
10: rustfmt_nightly::formatting::format_project::<rustfmt_nightly::Session<std::io::stdio::Stdout>>
11: <scoped_tls::ScopedKey<rustc_span::SessionGlobals>>::with::<<rustfmt_nightly::Session<std::io::stdio::Stdout>>::format_input_inner::{closure#0}, core::result::Result<rustfmt_nightly::FormatReport, rustfmt_nightly::ErrorKind>>
12: <scoped_tls::ScopedKey<rustc_span::SessionGlobals>>::set::<rustc_span::create_session_if_not_set_then<core::result::Result<rustfmt_nightly::FormatReport, rustfmt_nightly::ErrorKind>, <rustfmt_nightly::Session<std::io::stdio::Stdout>>::format_input_inner::{closure#0}>::{closure#0}, core::result::Result<rustfmt_nightly::FormatReport, rustfmt_nightly::ErrorKind>>
13: <rustfmt_nightly::Session<std::io::stdio::Stdout>>::format
14: rustfmt::format_and_emit_report::<std::io::stdio::Stdout>
15: <rustfmt_nightly::Session<std::io::stdio::Stdout>>::override_config::<rustfmt::format::{closure#0}, ()>
16: rustfmt::execute
17: rustfmt::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
And when running RUST_BACKTRACE=1 rustfmt +nightly lib.rs:
error: internal compiler error: the following error was constructed but not emitted
error: expected `#`, found `<eof>`
--> lib.rs:2:5
|
2 | if
| ^^
thread 'main' panicked at 'explicit panic', compiler/rustc_errors/src/diagnostic_builder.rs:568:21
stack backtrace:
0: rust_begin_unwind
at /rustc/2f3ddd9f594adf9773547aa7cedb43c4ac8ffd2f/library/std/src/panicking.rs:584:5
1: core::panicking::panic_fmt
at /rustc/2f3ddd9f594adf9773547aa7cedb43c4ac8ffd2f/library/core/src/panicking.rs:142:14
2: core::panicking::panic
at /rustc/2f3ddd9f594adf9773547aa7cedb43c4ac8ffd2f/library/core/src/panicking.rs:48:5
3: <rustc_errors::diagnostic_builder::DiagnosticBuilderInner as core::ops::drop::Drop>::drop
4: rustfmt_nightly::parse::macros::cfg_if::parse_cfg_if_inner
5: <rustfmt_nightly::modules::visitor::CfgIfVisitor as rustc_ast::visit::Visitor>::visit_mac_call
6: rustc_ast::visit::walk_item::<rustfmt_nightly::modules::visitor::CfgIfVisitor>
7: <rustfmt_nightly::modules::ModResolver>::visit_cfg_if
8: <rustfmt_nightly::modules::ModResolver>::visit_mod_from_ast
9: <rustfmt_nightly::modules::ModResolver>::visit_crate
10: rustfmt_nightly::formatting::format_project::<rustfmt_nightly::Session<std::io::stdio::Stdout>>
11: <scoped_tls::ScopedKey<rustc_span::SessionGlobals>>::with::<<rustfmt_nightly::Session<std::io::stdio::Stdout>>::format_input_inner::{closure#0}, core::result::Result<rustfmt_nightly::FormatReport, rustfmt_nightly::ErrorKind>>
12: <rustfmt_nightly::Session<std::io::stdio::Stdout>>::format
13: rustfmt::format_and_emit_report::<std::io::stdio::Stdout>
14: <rustfmt_nightly::Session<std::io::stdio::Stdout>>::override_config::<rustfmt::format::{closure#0}, ()>
15: rustfmt::execute
16: rustfmt::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Line 7 of each backtrace hints that special support for the cfg_if macro is the culprit.
Update 1:
This can also be triggered by else if, but reproducing it is a bit trickier, because it needs to avoid panicking on the first if:
cfg_if! {
if #[_] { } else if
}
Update 2:
I can file a separate issue for this if that would be best, but for now I'll just tack it on here:
The special cfg_if handling can also deadlock as seen here:
cfg_if! {
if #[_] { if }
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in rustfmt's special cfg_if handling at parse::macros::cfg_if::parse_cfg_if_inner, as identified by the backtrace, and follow its callers through the CfgIfVisitor. Reproduce the panic and deadlock with the examples using rustfmt on stable and nightly. Done means malformed cfg_if invocations no longer panic or deadlock and instead report an error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100