@@ -13,10 +13,11 @@ use syntax::{
13
13
14
14
use crate :: {
15
15
db:: ExpandDatabase ,
16
- hygiene:: span_with_def_site_ctxt,
17
- name, quote,
16
+ hygiene:: { span_with_call_site_ctxt, span_with_def_site_ctxt} ,
17
+ name:: { self , known} ,
18
+ quote,
18
19
tt:: { self , DelimSpan } ,
19
- ExpandError , ExpandResult , HirFileIdExt , MacroCallId , MacroCallLoc ,
20
+ ExpandError , ExpandResult , HirFileIdExt , MacroCallId ,
20
21
} ;
21
22
22
23
macro_rules! register_builtin {
@@ -196,32 +197,38 @@ fn stringify_expand(
196
197
}
197
198
198
199
fn assert_expand (
199
- _db : & dyn ExpandDatabase ,
200
- _id : MacroCallId ,
200
+ db : & dyn ExpandDatabase ,
201
+ id : MacroCallId ,
201
202
tt : & tt:: Subtree ,
202
203
span : Span ,
203
204
) -> ExpandResult < tt:: Subtree > {
204
- let args = parse_exprs_with_sep ( tt, ',' , span) ;
205
+ let call_site_span = span_with_call_site_ctxt ( db, span, id) ;
206
+ let args = parse_exprs_with_sep ( tt, ',' , call_site_span) ;
205
207
let dollar_crate = tt:: Ident { text : SmolStr :: new_inline ( "$crate" ) , span } ;
206
208
let expanded = match & * args {
207
209
[ cond, panic_args @ ..] => {
208
210
let comma = tt:: Subtree {
209
- delimiter : tt:: Delimiter :: invisible_spanned ( span ) ,
211
+ delimiter : tt:: Delimiter :: invisible_spanned ( call_site_span ) ,
210
212
token_trees : vec ! [ tt:: TokenTree :: Leaf ( tt:: Leaf :: Punct ( tt:: Punct {
211
213
char : ',' ,
212
214
spacing: tt:: Spacing :: Alone ,
213
- span,
215
+ span: call_site_span ,
214
216
} ) ) ] ,
215
217
} ;
216
218
let cond = cond. clone ( ) ;
217
219
let panic_args = itertools:: Itertools :: intersperse ( panic_args. iter ( ) . cloned ( ) , comma) ;
218
- quote ! { span =>{
220
+ let mac = if use_panic_2021 ( db, span) {
221
+ quote ! { call_site_span => #dollar_crate:: panic:: panic_2021!( ##panic_args) }
222
+ } else {
223
+ quote ! { call_site_span => #dollar_crate:: panic!( ##panic_args) }
224
+ } ;
225
+ quote ! { call_site_span =>{
219
226
if !( #cond) {
220
- #dollar_crate :: panic! ( ##panic_args ) ;
227
+ #mac ;
221
228
}
222
229
} }
223
230
}
224
- [ ] => quote ! { span =>{ } } ,
231
+ [ ] => quote ! { call_site_span =>{ } } ,
225
232
} ;
226
233
227
234
ExpandResult :: ok ( expanded)
@@ -337,17 +344,23 @@ fn panic_expand(
337
344
tt : & tt:: Subtree ,
338
345
span : Span ,
339
346
) -> ExpandResult < tt:: Subtree > {
340
- let loc: MacroCallLoc = db. lookup_intern_macro_call ( id) ;
341
347
let dollar_crate = tt:: Ident { text : SmolStr :: new_inline ( "$crate" ) , span } ;
348
+ let call_site_span = span_with_call_site_ctxt ( db, span, id) ;
349
+
350
+ let mac =
351
+ if use_panic_2021 ( db, call_site_span) { known:: panic_2021 } else { known:: panic_2015 } ;
352
+
342
353
// Expand to a macro call `$crate::panic::panic_{edition}`
343
- let mut call = if db. crate_graph ( ) [ loc. krate ] . edition >= Edition :: Edition2021 {
344
- quote ! ( span =>#dollar_crate:: panic:: panic_2021!)
345
- } else {
346
- quote ! ( span =>#dollar_crate:: panic:: panic_2015!)
347
- } ;
354
+ let mut call = quote ! ( call_site_span =>#dollar_crate:: panic:: #mac!) ;
348
355
349
356
// Pass the original arguments
350
- call. token_trees . push ( tt:: TokenTree :: Subtree ( tt. clone ( ) ) ) ;
357
+ let mut subtree = tt. clone ( ) ;
358
+ subtree. delimiter = tt:: Delimiter {
359
+ open : call_site_span,
360
+ close : call_site_span,
361
+ kind : tt:: DelimiterKind :: Parenthesis ,
362
+ } ;
363
+ call. token_trees . push ( tt:: TokenTree :: Subtree ( subtree) ) ;
351
364
ExpandResult :: ok ( call)
352
365
}
353
366
@@ -357,20 +370,50 @@ fn unreachable_expand(
357
370
tt : & tt:: Subtree ,
358
371
span : Span ,
359
372
) -> ExpandResult < tt:: Subtree > {
360
- let loc: MacroCallLoc = db. lookup_intern_macro_call ( id) ;
361
- // Expand to a macro call `$crate::panic::unreachable_{edition}`
362
373
let dollar_crate = tt:: Ident { text : SmolStr :: new_inline ( "$crate" ) , span } ;
363
- let mut call = if db. crate_graph ( ) [ loc. krate ] . edition >= Edition :: Edition2021 {
364
- quote ! ( span =>#dollar_crate:: panic:: unreachable_2021!)
374
+ let call_site_span = span_with_call_site_ctxt ( db, span, id) ;
375
+
376
+ let mac = if use_panic_2021 ( db, call_site_span) {
377
+ known:: unreachable_2021
365
378
} else {
366
- quote ! ( span =>#dollar_crate :: panic :: unreachable_2015! )
379
+ known :: unreachable_2015
367
380
} ;
368
381
382
+ // Expand to a macro call `$crate::panic::panic_{edition}`
383
+ let mut call = quote ! ( call_site_span =>#dollar_crate:: panic:: #mac!) ;
384
+
369
385
// Pass the original arguments
370
- call. token_trees . push ( tt:: TokenTree :: Subtree ( tt. clone ( ) ) ) ;
386
+ let mut subtree = tt. clone ( ) ;
387
+ subtree. delimiter = tt:: Delimiter {
388
+ open : call_site_span,
389
+ close : call_site_span,
390
+ kind : tt:: DelimiterKind :: Parenthesis ,
391
+ } ;
392
+ call. token_trees . push ( tt:: TokenTree :: Subtree ( subtree) ) ;
371
393
ExpandResult :: ok ( call)
372
394
}
373
395
396
+ fn use_panic_2021 ( db : & dyn ExpandDatabase , span : Span ) -> bool {
397
+ // To determine the edition, we check the first span up the expansion
398
+ // stack that does not have #[allow_internal_unstable(edition_panic)].
399
+ // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.)
400
+ loop {
401
+ let Some ( expn) = db. lookup_intern_syntax_context ( span. ctx ) . outer_expn else {
402
+ break false ;
403
+ } ;
404
+ let expn = db. lookup_intern_macro_call ( expn) ;
405
+ // FIXME: Record allow_internal_unstable in the macro def (not been done yet because it
406
+ // would consume quite a bit extra memory for all call locs...)
407
+ // if let Some(features) = expn.def.allow_internal_unstable {
408
+ // if features.iter().any(|&f| f == sym::edition_panic) {
409
+ // span = expn.call_site;
410
+ // continue;
411
+ // }
412
+ // }
413
+ break expn. def . edition >= Edition :: Edition2021 ;
414
+ }
415
+ }
416
+
374
417
fn unquote_str ( lit : & tt:: Literal ) -> Option < String > {
375
418
let lit = ast:: make:: tokens:: literal ( & lit. to_string ( ) ) ;
376
419
let token = ast:: String :: cast ( lit) ?;
0 commit comments