rustc_builtin_macros/
edition_panic.rs

1use rustc_ast::ptr::P;
2use rustc_ast::token::Delimiter;
3use rustc_ast::tokenstream::{DelimSpan, TokenStream};
4use rustc_ast::*;
5use rustc_expand::base::*;
6use rustc_span::edition::Edition;
7use rustc_span::{Span, sym};
8
9/// This expands to either
10/// - `$crate::panic::panic_2015!(...)` or
11/// - `$crate::panic::panic_2021!(...)`
12/// depending on the edition.
13///
14/// This is used for both std::panic!() and core::panic!().
15///
16/// `$crate` will refer to either the `std` or `core` crate depending on which
17/// one we're expanding from.
18pub(crate) fn expand_panic<'cx>(
19    cx: &'cx mut ExtCtxt<'_>,
20    sp: Span,
21    tts: TokenStream,
22) -> MacroExpanderResult<'cx> {
23    let mac = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 };
24    expand(mac, cx, sp, tts)
25}
26
27/// This expands to either
28/// - `$crate::panic::unreachable_2015!(...)` or
29/// - `$crate::panic::unreachable_2021!(...)`
30/// depending on the edition.
31pub(crate) fn expand_unreachable<'cx>(
32    cx: &'cx mut ExtCtxt<'_>,
33    sp: Span,
34    tts: TokenStream,
35) -> MacroExpanderResult<'cx> {
36    let mac = if use_panic_2021(sp) { sym::unreachable_2021 } else { sym::unreachable_2015 };
37    expand(mac, cx, sp, tts)
38}
39
40fn expand<'cx>(
41    mac: rustc_span::Symbol,
42    cx: &'cx ExtCtxt<'_>,
43    sp: Span,
44    tts: TokenStream,
45) -> MacroExpanderResult<'cx> {
46    let sp = cx.with_call_site_ctxt(sp);
47
48    ExpandResult::Ready(MacEager::expr(
49        cx.expr(
50            sp,
51            ExprKind::MacCall(P(MacCall {
52                path: Path {
53                    span: sp,
54                    segments: cx
55                        .std_path(&[sym::panic, mac])
56                        .into_iter()
57                        .map(|ident| PathSegment::from_ident(ident))
58                        .collect(),
59                    tokens: None,
60                },
61                args: P(DelimArgs {
62                    dspan: DelimSpan::from_single(sp),
63                    delim: Delimiter::Parenthesis,
64                    tokens: tts,
65                }),
66            })),
67        ),
68    ))
69}
70
71pub(crate) fn use_panic_2021(mut span: Span) -> bool {
72    // To determine the edition, we check the first span up the expansion
73    // stack that does not have #[allow_internal_unstable(edition_panic)].
74    // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.)
75    loop {
76        let expn = span.ctxt().outer_expn_data();
77        if let Some(features) = expn.allow_internal_unstable {
78            if features.iter().any(|&f| f == sym::edition_panic) {
79                span = expn.call_site;
80                continue;
81            }
82        }
83        break expn.edition >= Edition::Edition2021;
84    }
85}