3
3
use crate :: visitors:: { for_each_expr, Descend } ;
4
4
5
5
use arrayvec:: ArrayVec ;
6
+ use hir:: { Block , Local , Stmt , StmtKind } ;
6
7
use rustc_ast:: { FormatArgs , FormatArgument , FormatPlaceholder } ;
7
8
use rustc_data_structures:: fx:: FxHashMap ;
8
9
use rustc_hir:: { self as hir, Expr , ExprKind , HirId , Node , QPath } ;
@@ -106,12 +107,7 @@ pub fn macro_backtrace(span: Span) -> impl Iterator<Item = MacroCall> {
106
107
macro_def_id : Some ( def_id) ,
107
108
call_site : span,
108
109
..
109
- } => Some ( MacroCall {
110
- def_id,
111
- kind,
112
- expn,
113
- span,
114
- } ) ,
110
+ } => Some ( MacroCall { def_id, kind, expn, span } ) ,
115
111
_ => None ,
116
112
} )
117
113
}
@@ -133,11 +129,14 @@ pub fn root_macro_call_first_node(cx: &LateContext<'_>, node: &impl HirNode) ->
133
129
134
130
/// Like [`macro_backtrace`], but only returns macro calls where `node` is the "first node" of the
135
131
/// macro call, as in [`first_node_in_macro`].
136
- pub fn first_node_macro_backtrace ( cx : & LateContext < ' _ > , node : & impl HirNode ) -> impl Iterator < Item = MacroCall > {
132
+ pub fn first_node_macro_backtrace (
133
+ cx : & LateContext < ' _ > ,
134
+ node : & impl HirNode ,
135
+ ) -> impl Iterator < Item = MacroCall > {
137
136
let span = node. span ( ) ;
138
- first_node_in_macro ( cx, node)
139
- . into_iter ( )
140
- . flat_map ( move |expn| macro_backtrace ( span ) . take_while ( move |macro_call| macro_call . expn != expn ) )
137
+ first_node_in_macro ( cx, node) . into_iter ( ) . flat_map ( move |expn| {
138
+ macro_backtrace ( span ) . take_while ( move |macro_call| macro_call . expn != expn )
139
+ } )
141
140
}
142
141
143
142
/// If `node` is the "first node" in a macro expansion, returns `Some` with the `ExpnId` of the
@@ -222,17 +221,54 @@ pub enum PanicExpn<'a> {
222
221
/// A single argument that implements `Display` - `panic!("{}", object)`
223
222
Display ( & ' a Expr < ' a > ) ,
224
223
/// Anything else - `panic!("error {}: {}", a, b)`
225
- Format ( & ' a Expr < ' a > ) ,
224
+ Format ( Option < & ' a Expr < ' a > > ) ,
226
225
}
227
226
228
227
impl < ' a > PanicExpn < ' a > {
229
228
pub fn parse ( expr : & ' a Expr < ' a > ) -> Option < Self > {
230
- let ExprKind :: Call ( callee, [ arg, rest @ ..] ) = & expr. kind else {
229
+ // Pattern match on the special single-argument case for const_panic in `panic_2021`.
230
+ if let ExprKind :: Block (
231
+ & Block {
232
+ stmts :
233
+ [
234
+ Stmt { kind : StmtKind :: Item ( ..) , .. } ,
235
+ Stmt {
236
+ kind :
237
+ StmtKind :: Local ( & Local {
238
+ init : Some ( & Expr { kind : ExprKind :: AddrOf ( _, _, arg) , .. } ) ,
239
+ ..
240
+ } ) ,
241
+ ..
242
+ } ,
243
+ Stmt { kind : StmtKind :: Expr ( & Expr { kind : ExprKind :: If ( ..) , .. } ) , .. } ,
244
+ ..,
245
+ ] ,
246
+ ..
247
+ } ,
248
+ ..,
249
+ ) = & expr. kind
250
+ {
251
+ return Some ( Self :: Display ( arg) ) ;
252
+ }
253
+
254
+ let ExprKind :: Call ( callee, args) = & expr. kind else {
231
255
return None ;
232
256
} ;
233
257
let ExprKind :: Path ( QPath :: Resolved ( _, path) ) = & callee. kind else {
234
258
return None ;
235
259
} ;
260
+ let name = path. segments . last ( ) . unwrap ( ) . ident . as_str ( ) ;
261
+
262
+ // These may have no arguments
263
+ match name {
264
+ "panic_cold_explicit" => return Some ( Self :: Empty ) ,
265
+ "panic_cold" => return Some ( Self :: Format ( None ) ) ,
266
+ _ => ( ) ,
267
+ } ;
268
+
269
+ let [ arg, rest @ ..] = args else {
270
+ return None ;
271
+ } ;
236
272
let result = match path. segments . last ( ) . unwrap ( ) . ident . as_str ( ) {
237
273
"panic" if arg. span . ctxt ( ) == expr. span . ctxt ( ) => Self :: Empty ,
238
274
"panic" | "panic_str" => Self :: Str ( arg) ,
@@ -241,8 +277,8 @@ impl<'a> PanicExpn<'a> {
241
277
return None ;
242
278
} ;
243
279
Self :: Display ( e)
244
- } ,
245
- "panic_fmt" => Self :: Format ( arg) ,
280
+ }
281
+ "panic_fmt" => Self :: Format ( Some ( arg) ) ,
246
282
// Since Rust 1.52, `assert_{eq,ne}` macros expand to use:
247
283
// `core::panicking::assert_failed(.., left_val, right_val, None | Some(format_args!(..)));`
248
284
"assert_failed" => {
@@ -254,10 +290,10 @@ impl<'a> PanicExpn<'a> {
254
290
// `msg_arg` is either `None` (no custom message) or `Some(format_args!(..))` (custom message)
255
291
let msg_arg = & rest[ 2 ] ;
256
292
match msg_arg. kind {
257
- ExprKind :: Call ( _, [ fmt_arg] ) => Self :: Format ( fmt_arg) ,
293
+ ExprKind :: Call ( _, [ fmt_arg] ) => Self :: Format ( Some ( fmt_arg) ) ,
258
294
_ => Self :: Empty ,
259
295
}
260
- } ,
296
+ }
261
297
_ => return None ,
262
298
} ;
263
299
Some ( result)
@@ -301,7 +337,9 @@ fn find_assert_args_inner<'a, const N: usize>(
301
337
let macro_id = expn. expn_data ( ) . macro_def_id ?;
302
338
let ( expr, expn) = match cx. tcx . item_name ( macro_id) . as_str ( ) . strip_prefix ( "debug_" ) {
303
339
None => ( expr, expn) ,
304
- Some ( inner_name) => find_assert_within_debug_assert ( cx, expr, expn, Symbol :: intern ( inner_name) ) ?,
340
+ Some ( inner_name) => {
341
+ find_assert_within_debug_assert ( cx, expr, expn, Symbol :: intern ( inner_name) ) ?
342
+ }
305
343
} ;
306
344
let mut args = ArrayVec :: new ( ) ;
307
345
let panic_expn = for_each_expr ( expr, |e| {
@@ -337,7 +375,9 @@ fn find_assert_within_debug_assert<'a>(
337
375
let e_expn = e. span . ctxt ( ) . outer_expn ( ) ;
338
376
if e_expn == expn {
339
377
ControlFlow :: Continue ( Descend :: Yes )
340
- } else if e_expn. expn_data ( ) . macro_def_id . map ( |id| cx. tcx . item_name ( id) ) == Some ( assert_name) {
378
+ } else if e_expn. expn_data ( ) . macro_def_id . map ( |id| cx. tcx . item_name ( id) )
379
+ == Some ( assert_name)
380
+ {
341
381
ControlFlow :: Break ( ( e, e_expn) )
342
382
} else {
343
383
ControlFlow :: Continue ( Descend :: No )
@@ -395,14 +435,20 @@ pub fn collect_ast_format_args(span: Span, format_args: &FormatArgs) {
395
435
396
436
/// Calls `callback` with an AST [`FormatArgs`] node if a `format_args` expansion is found as a
397
437
/// descendant of `expn_id`
398
- pub fn find_format_args ( cx : & LateContext < ' _ > , start : & Expr < ' _ > , expn_id : ExpnId , callback : impl FnOnce ( & FormatArgs ) ) {
438
+ pub fn find_format_args (
439
+ cx : & LateContext < ' _ > ,
440
+ start : & Expr < ' _ > ,
441
+ expn_id : ExpnId ,
442
+ callback : impl FnOnce ( & FormatArgs ) ,
443
+ ) {
399
444
let format_args_expr = for_each_expr ( start, |expr| {
400
445
let ctxt = expr. span . ctxt ( ) ;
401
446
if ctxt. outer_expn ( ) . is_descendant_of ( expn_id) {
402
- if macro_backtrace ( expr. span )
403
- . map ( |macro_call| cx. tcx . item_name ( macro_call. def_id ) )
404
- . any ( |name| matches ! ( name, sym:: const_format_args | sym:: format_args | sym:: format_args_nl) )
405
- {
447
+ if macro_backtrace ( expr. span ) . map ( |macro_call| cx. tcx . item_name ( macro_call. def_id ) ) . any (
448
+ |name| {
449
+ matches ! ( name, sym:: const_format_args | sym:: format_args | sym:: format_args_nl)
450
+ } ,
451
+ ) {
406
452
ControlFlow :: Break ( expr)
407
453
} else {
408
454
ControlFlow :: Continue ( Descend :: Yes )
@@ -425,12 +471,7 @@ pub fn find_format_arg_expr<'hir, 'ast>(
425
471
start : & ' hir Expr < ' hir > ,
426
472
target : & ' ast FormatArgument ,
427
473
) -> Result < & ' hir rustc_hir:: Expr < ' hir > , & ' ast rustc_ast:: Expr > {
428
- let SpanData {
429
- lo,
430
- hi,
431
- ctxt,
432
- parent : _,
433
- } = target. expr . span . data ( ) ;
474
+ let SpanData { lo, hi, ctxt, parent : _ } = target. expr . span . data ( ) ;
434
475
435
476
for_each_expr ( start, |expr| {
436
477
// When incremental compilation is enabled spans gain a parent during AST to HIR lowering,
@@ -456,12 +497,7 @@ pub fn format_placeholder_format_span(placeholder: &FormatPlaceholder) -> Option
456
497
457
498
// `base.hi` is `{...}|`, subtract 1 byte (the length of '}') so that it points before the closing
458
499
// brace `{...|}`
459
- Some ( Span :: new (
460
- placeholder. argument . span ?. hi ( ) ,
461
- base. hi - BytePos ( 1 ) ,
462
- base. ctxt ,
463
- base. parent ,
464
- ) )
500
+ Some ( Span :: new ( placeholder. argument . span ?. hi ( ) , base. hi - BytePos ( 1 ) , base. ctxt , base. parent ) )
465
501
}
466
502
467
503
/// Span covering the format string and values
@@ -473,9 +509,9 @@ pub fn format_placeholder_format_span(placeholder: &FormatPlaceholder) -> Option
473
509
pub fn format_args_inputs_span ( format_args : & FormatArgs ) -> Span {
474
510
match format_args. arguments . explicit_args ( ) {
475
511
[ ] => format_args. span ,
476
- [ .., last] => format_args
477
- . span
478
- . to ( hygiene :: walk_chain ( last . expr . span , format_args . span . ctxt ( ) ) ) ,
512
+ [ .., last] => {
513
+ format_args . span . to ( hygiene :: walk_chain ( last . expr . span , format_args . span . ctxt ( ) ) )
514
+ }
479
515
}
480
516
}
481
517
0 commit comments