Skip to main content

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                },
59                args: Box::new(DelimArgs {
60                    dspan: DelimSpan::from_single(sp),
61                    delim: Delimiter::Parenthesis,
62                    tokens: tts,
63                }),
64            })),
65        ),
66    ))
67}
68
69pub(crate) fn use_panic_2021(mut span: Span) -> bool {
70    // To determine the edition, we check the first span up the expansion
71    // stack that does not have #[allow_internal_unstable(edition_panic)].
72    // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.)
73    loop {
74        let expn = span.ctxt().outer_expn_data();
75        if let Some(features) = expn.allow_internal_unstable
76            && features.contains(&sym::edition_panic)
77        {
78            span = expn.call_site;
79            continue;
80        }
81        break expn.edition >= Edition::Edition2021;
82    }
83}