rustc_builtin_macros/
edition_panic.rs

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