diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index 08f555b9e52f6..2f77b02be588d 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -1,14 +1,35 @@ use rustc_ast::token::Delimiter; -use rustc_ast::tokenstream::{DelimSpan, TokenStream}; +use rustc_ast::tokenstream::TokenStream; use rustc_ast::*; use rustc_expand::base::*; use rustc_span::edition::Edition; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol, sym}; + +// Use an enum to ensure that no new macro calls are added without also updating the message in the +// optimized path below. +enum InnerCall { + Panic2015, + Panic2021, + Unreachable2015, + Unreachable2021, +} + +impl InnerCall { + fn symbol(&self) -> Symbol { + match self { + Self::Panic2015 => sym::panic_2015, + Self::Panic2021 => sym::panic_2021, + Self::Unreachable2015 => sym::unreachable_2015, + Self::Unreachable2021 => sym::unreachable_2021, + } + } +} /// This expands to either /// - `$crate::panic::panic_2015!(...)` or /// - `$crate::panic::panic_2021!(...)` -/// depending on the edition. +/// depending on the edition. If the entire message is known at compile time, +/// `core::panicking::panic` may be called as an optimization. /// /// This is used for both std::panic!() and core::panic!(). /// @@ -19,25 +40,27 @@ pub(crate) fn expand_panic<'cx>( sp: Span, tts: TokenStream, ) -> MacroExpanderResult<'cx> { - let mac = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 }; + let mac = if use_panic_2021(sp) { InnerCall::Panic2021 } else { InnerCall::Panic2015 }; expand(mac, cx, sp, tts) } /// This expands to either /// - `$crate::panic::unreachable_2015!(...)` or /// - `$crate::panic::unreachable_2021!(...)` -/// depending on the edition. +/// depending on the edition. If the entire message is known at compile time, +/// `core::panicking::panic` may be called as an optimization. pub(crate) fn expand_unreachable<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, ) -> MacroExpanderResult<'cx> { - let mac = if use_panic_2021(sp) { sym::unreachable_2021 } else { sym::unreachable_2015 }; + let mac = + if use_panic_2021(sp) { InnerCall::Unreachable2021 } else { InnerCall::Unreachable2015 }; expand(mac, cx, sp, tts) } fn expand<'cx>( - mac: rustc_span::Symbol, + mac: InnerCall, cx: &'cx ExtCtxt<'_>, sp: Span, tts: TokenStream, @@ -45,24 +68,22 @@ fn expand<'cx>( let sp = cx.with_call_site_ctxt(sp); ExpandResult::Ready(MacEager::expr( - cx.expr( + cx.expr_macro_call( sp, - ExprKind::MacCall(Box::new(MacCall { - path: Path { + cx.macro_call( + sp, + Path { span: sp, segments: cx - .std_path(&[sym::panic, mac]) + .std_path(&[sym::panic, mac.symbol()]) .into_iter() - .map(|ident| PathSegment::from_ident(ident)) + .map(PathSegment::from_ident) .collect(), tokens: None, }, - args: Box::new(DelimArgs { - dspan: DelimSpan::from_single(sp), - delim: Delimiter::Parenthesis, - tokens: tts, - }), - })), + Delimiter::Parenthesis, + tts, + ), ), )) } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e213e1d91a75d..b8f13e4e7c531 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -184,6 +184,7 @@ #![feature(staged_api)] #![feature(stmt_expr_attributes)] #![feature(strict_provenance_lints)] +#![feature(super_let)] #![feature(trait_alias)] #![feature(transparent_unions)] #![feature(try_blocks)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index df24dd43b82eb..d379180abf46f 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1,12 +1,13 @@ #[doc = include_str!("panic.md")] #[macro_export] #[rustc_builtin_macro(core_panic)] -#[allow_internal_unstable(edition_panic)] +#[allow_internal_unstable(edition_panic, panic_internals)] #[stable(feature = "core", since = "1.6.0")] #[rustc_diagnostic_item = "core_panic_macro"] macro_rules! panic { // Expands to either `$crate::panic::panic_2015` or `$crate::panic::panic_2021` - // depending on the edition of the caller. + // depending on the edition of the caller. If the entire message is known at compile time, + // `core::panicking::panic` may be called as an optimization. ($($arg:tt)*) => { /* compiler built-in */ }; @@ -705,7 +706,7 @@ macro_rules! writeln { /// ``` #[macro_export] #[rustc_builtin_macro(unreachable)] -#[allow_internal_unstable(edition_panic)] +#[allow_internal_unstable(edition_panic, panic_internals)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "unreachable_macro"] macro_rules! unreachable { diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 7a42b3d0fc780..dc7e9a7edc796 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -45,7 +45,7 @@ pub macro panic_2015 { #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(panic_internals, const_format_args)] +#[allow_internal_unstable(panic_internals, const_format_args, super_let)] #[rustc_diagnostic_item = "core_panic_2021_macro"] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2021 { @@ -59,7 +59,11 @@ pub macro panic_2021 { ($($t:tt)+) => ({ // Semicolon to prevent temporaries inside the formatting machinery from // being considered alive in the caller after the panic_fmt call. - $crate::panicking::panic_fmt($crate::const_format_args!($($t)+)); + super let args = $crate::const_format_args!($($t)+); + if let $crate::option::Option::Some(s) = args.as_str() { + $crate::panicking::panic(s); + } + $crate::panicking::panic_fmt(args); }), } diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 25e2b7ea13703..1280eccc48861 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -9,11 +9,12 @@ #[macro_export] #[rustc_builtin_macro(std_panic)] #[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable(edition_panic)] +#[allow_internal_unstable(edition_panic, panic_internals)] #[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_macro")] macro_rules! panic { // Expands to either `$crate::panic::panic_2015` or `$crate::panic::panic_2021` - // depending on the edition of the caller. + // depending on the edition of the caller. If the entire message is known at compile time, + // `core::panicking::panic` may be called as an optimization. ($($arg:tt)*) => { /* compiler built-in */ }; diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs index 716334656926d..a726d436caa75 100644 --- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs +++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs @@ -81,7 +81,7 @@ pub struct IncompatibleMsrv { msrv: Msrv, availability_cache: FxHashMap<(DefId, bool), Availability>, check_in_tests: bool, - core_crate: Option, + stdlib_crates: Vec, // The most recently called path. Used to skip checking the path after it's // been checked when visiting the call expression. @@ -96,11 +96,15 @@ impl IncompatibleMsrv { msrv: conf.msrv, availability_cache: FxHashMap::default(), check_in_tests: conf.check_incompatible_msrv_in_tests, - core_crate: tcx + stdlib_crates: tcx .crates(()) .iter() - .find(|krate| tcx.crate_name(**krate) == sym::core) - .copied(), + .filter(|krate| { + let name = tcx.crate_name(**krate); + name == sym::core || name == sym::alloc || name == sym::std + }) + .copied() + .collect(), called_path: None, } } @@ -162,10 +166,14 @@ impl IncompatibleMsrv { // Intentionally not using `.from_expansion()`, since we do still care about macro expansions return; } - // Functions coming from `core` while expanding a macro such as `assert*!()` get to cheat too: the - // macros may have existed prior to the checked MSRV, but their expansion with a recent compiler - // might use recent functions or methods. Compiling with an older compiler would not use those. - if Some(def_id.krate) == self.core_crate && expn_data.macro_def_id.map(|did| did.krate) == self.core_crate { + // Functions coming from standard library crates while expanding a macro such as + // `assert*!()` get to cheat too: the macros may have existed prior to the checked MSRV, but + // their expansion with a recent compiler might use recent functions or methods. Compiling + // with an older compiler would not use those. + if self.stdlib_crates.contains(&def_id.krate) + && let Some(did) = expn_data.macro_def_id + && self.stdlib_crates.contains(&did.krate) + { return; } diff --git a/src/tools/miri/tests/panic/panic1.stderr b/src/tools/miri/tests/panic/panic1.stderr index ff7e287b5a585..c2ece5fb6306a 100644 --- a/src/tools/miri/tests/panic/panic1.stderr +++ b/src/tools/miri/tests/panic/panic1.stderr @@ -4,10 +4,12 @@ panicking from libstd stack backtrace: 0: std::panicking::panic_handler at RUSTLIB/std/src/panicking.rs:LL:CC - 1: std::rt::panic_fmt + 1: core::panicking::panic_fmt at RUSTLIB/core/src/panicking.rs:LL:CC - 2: main + 2: core::panicking::panic + at RUSTLIB/core/src/panicking.rs:LL:CC + 3: main at tests/panic/panic1.rs:LL:CC - 3: >::call_once - shim(fn()) + 4: >::call_once - shim(fn()) at RUSTLIB/core/src/ops/function.rs:LL:CC note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.