panic!() with formatting arguments sometimes accepted in const · Issue #139621 · rust-lang/rust (original) (raw)

This issue is a combination of three things:

  1. fn panic_fmt is marked with #[rustc_do_not_const_check] and fully relies on format_args!() with any arguments to not be accepted in const.
  2. Inlining/flattening of format_args!() accidentally exposed as stable through const #139136 - I accidentally marked this function as const, meaning that flattened format_args are accepted in const. This went unnoticed until two weeks ago. Edit: This is actually caused by [generic_assert] Constify methods used by the formatting system #135139
  3. We have a special case for panic!("{}", $expr) that we added at some point to make panic!("{}", my_string) work in const, as a workaround for panic!(my_string) which no longer works as of Rust 2021.

The result is pretty terrible:

const A1: () = if false { panic!("{}", "a") }; const A2: () = if false { panic!("{}", {"a"}) }; const A3: () = if false { panic!("{}", 1) }; // error! const A4: () = if false { panic!("{}", {1}) }; // error! const B1: () = if false { panic!(" {}", "a") }; const B2: () = if false { panic!(" {}", {"a"}) }; // error! const B3: () = if false { panic!(" {}", 1) }; const B4: () = if false { panic!(" {}", {1}) }; // error!

Only the four marked lines error. The others compile fine. 🙃

(The A constants use the "{}" special case for panic!() and end up invoking panic_display for which we have a special const eval check that the argument is a &str. The B constants end up invoking panic_fmt (which does not have any const eval checks) and format_args!().)