@@ -19,12 +19,11 @@ use std::cell::Cell;
1919
2020use crate :: maybe_pqp_cg_ssa:: traits:: BuilderMethods ;
2121
22- // HACK(eddyb) Rust 2021 `panic!` always uses `format_args!`, even
23- // in the simple case that used to pass a `&str` constant, which
24- // would not remain reachable in the SPIR-V - but `format_args!` is
25- // more complex and neither immediate (`fmt::Arguments` is too big)
26- // nor simplified in MIR (e.g. promoted to a constant) in any way,
27- // so we have to try and remove the `fmt::Arguments::new` call here.
22+ // HACK(eddyb) even after `core::fmt::Arguments::from_str` became common
23+ // for const-string panics, `core`/`std` still lower many panic paths
24+ // (e.g. `assert_unsafe_precondition!`) through `fmt::Arguments::new*`
25+ // constructors. We still need this decompiler to strip those builder
26+ // call sequences and recover panic messages/arguments when possible.
2827#[ derive( Default ) ]
2928pub struct DecodedFormatArgs < ' tcx > {
3029 /// If fully constant, the `pieces: &'a [&'static str]` input
@@ -302,6 +301,11 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
302301 }
303302 }
304303
304+ let value_id = |value : SpirvValue | match value. kind {
305+ SpirvValueKind :: Def ( id) | SpirvValueKind :: IllegalConst ( id) => Some ( id) ,
306+ _ => None ,
307+ } ;
308+
305309 // HACK(eddyb) `panic_explicit` doesn't take any regular arguments,
306310 // only an (implicit) `&'static panic::Location<'static>`.
307311 if args. len ( ) == 1 {
@@ -314,20 +318,13 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
314318 }
315319
316320 // HACK(eddyb) some entry-points only take a `&str`, not `fmt::Arguments`.
317- if let [
318- SpirvValue {
319- kind : SpirvValueKind :: Def ( a_id) ,
320- ty : a_ty,
321- } ,
322- SpirvValue {
323- kind : SpirvValueKind :: Def ( b_id) ,
324- ty : b_ty,
325- } ,
326- ref other_args @ ..,
327- ] = args[ ..]
321+ if let [ a, b, other_args @ ..] = args
322+ && let ( Some ( a_id) , Some ( b_id) ) = ( value_id ( * a) , value_id ( * b) )
328323 {
329- // Optional `force_no_backtrace` and/or `&'static panic::Location<'static>`.
330- if other_args. len ( ) <= 2
324+ let [ a_ty, b_ty] = [ a. ty , b. ty ] ;
325+
326+ // Optional panic flags and/or `&'static panic::Location<'static>`.
327+ if other_args. len ( ) <= 3
331328 && let Some ( const_msg) = const_str_as_utf8 ( & [ a_id, b_id] )
332329 {
333330 decoded_format_args. const_pieces = Some ( [ const_msg] . into_iter ( ) . collect ( ) ) ;
@@ -336,7 +333,7 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
336333
337334 // Dynamic `&str` panic messages (e.g. `panic_display(&msg)` where
338335 // `msg` isn't a directly recoverable constant).
339- if other_args. len ( ) <= 2
336+ if other_args. len ( ) <= 3
340337 && matches ! ( cx. lookup_type( a_ty) , SpirvType :: Pointer { .. } )
341338 && matches ! ( cx. lookup_type( b_ty) , SpirvType :: Integer ( ..) )
342339 {
@@ -350,23 +347,16 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
350347 // (`template: *const u8`, `args: *const fmt::rt::Argument`), instead of
351348 // being passed as one aggregate value.
352349 let split_fmt_args = match * args {
353- [
354- SpirvValue {
355- kind : SpirvValueKind :: Def ( template_id) ,
356- ty : template_ty_id,
357- } ,
358- SpirvValue {
359- kind : SpirvValueKind :: Def ( rt_args_or_tagged_len_id) ,
360- ty : rt_args_or_tagged_len_ty_id,
361- } ,
362- ref trailing @ ..,
363- ] if trailing. len ( ) <= 2
364- && matches ! ( cx. lookup_type( template_ty_id) , SpirvType :: Pointer { .. } )
365- && matches ! (
366- cx. lookup_type( rt_args_or_tagged_len_ty_id) ,
367- SpirvType :: Pointer { .. } | SpirvType :: Integer ( ..)
368- )
369- && const_str_as_utf8 ( & [ template_id, rt_args_or_tagged_len_id] ) . is_none ( ) =>
350+ [ template, rt_args_or_tagged_len, ref trailing @ ..]
351+ if trailing. len ( ) <= 3
352+ && matches ! ( cx. lookup_type( template. ty) , SpirvType :: Pointer { .. } )
353+ && matches ! (
354+ cx. lookup_type( rt_args_or_tagged_len. ty) ,
355+ SpirvType :: Pointer { .. } | SpirvType :: Integer ( ..)
356+ )
357+ && let ( Some ( template_id) , Some ( rt_args_or_tagged_len_id) ) =
358+ ( value_id ( template) , value_id ( rt_args_or_tagged_len) )
359+ && const_str_as_utf8 ( & [ template_id, rt_args_or_tagged_len_id] ) . is_none ( ) =>
370360 {
371361 let looks_like_bool = matches ! (
372362 cx. builder. lookup_const_by_id( rt_args_or_tagged_len_id) ,
@@ -377,9 +367,9 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
377367 } else {
378368 Some ( (
379369 template_id,
380- template_ty_id ,
370+ template . ty ,
381371 rt_args_or_tagged_len_id,
382- rt_args_or_tagged_len_ty_id ,
372+ rt_args_or_tagged_len . ty ,
383373 ) )
384374 }
385375 }
@@ -389,21 +379,8 @@ impl<'tcx> DecodedFormatArgs<'tcx> {
389379 let format_args_id = if split_fmt_args. is_none ( ) {
390380 match * args {
391381 // HACK(eddyb) `panic_nounwind_fmt` takes an extra argument.
392- [
393- SpirvValue {
394- kind : SpirvValueKind :: Def ( format_args_id) ,
395- ..
396- } ,
397- _, // `&'static panic::Location<'static>`
398- ]
399- | [
400- SpirvValue {
401- kind : SpirvValueKind :: Def ( format_args_id) ,
402- ..
403- } ,
404- _, // `force_no_backtrace: bool`
405- _, // `&'static panic::Location<'static>`
406- ] => format_args_id,
382+ [ format_args, ref trailing @ ..] if trailing. len ( ) <= 3 => value_id ( format_args)
383+ . ok_or_else ( || FormatArgsNotRecognized ( "panic entry-point call args" . into ( ) ) ) ?,
407384
408385 _ => {
409386 return Err ( FormatArgsNotRecognized (
0 commit comments