Skip to content

ICE in special cfg_if handling #5413

Open
@mpfaff

Description

@mpfaff

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 }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions