Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix invalid special casing of the unreachable! macro #93179

Merged
merged 2 commits into from
Feb 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/assert.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::panic::use_panic_2021;
use crate::edition_panic::use_panic_2021;
use rustc_ast::ptr::P;
use rustc_ast::token;
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,29 @@ pub fn expand_panic<'cx>(
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
let panic = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 };
let mac = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 };
expand(mac, cx, sp, tts)
}

// This expands to either
// - `$crate::panic::unreachable_2015!(...)` or
// - `$crate::panic::unreachable_2021!(...)`
// depending on the edition.
pub fn expand_unreachable<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
let mac = if use_panic_2021(sp) { sym::unreachable_2021 } else { sym::unreachable_2015 };
expand(mac, cx, sp, tts)
}

fn expand<'cx>(
mac: rustc_span::Symbol,
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
let sp = cx.with_call_site_ctxt(sp);

MacEager::expr(
Expand All @@ -31,7 +52,7 @@ pub fn expand_panic<'cx>(
path: Path {
span: sp,
segments: cx
.std_path(&[sym::panic, panic])
.std_path(&[sym::panic, mac])
.into_iter()
.map(|ident| PathSegment::from_ident(ident))
.collect(),
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_builtin_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ mod concat_bytes;
mod concat_idents;
mod derive;
mod deriving;
mod edition_panic;
mod env;
mod format;
mod format_foreign;
mod global_allocator;
mod log_syntax;
mod panic;
mod source_util;
mod test;
mod trace_macros;
Expand Down Expand Up @@ -82,8 +82,9 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
log_syntax: log_syntax::expand_log_syntax,
module_path: source_util::expand_mod,
option_env: env::expand_option_env,
core_panic: panic::expand_panic,
std_panic: panic::expand_panic,
core_panic: edition_panic::expand_panic,
std_panic: edition_panic::expand_panic,
unreachable: edition_panic::expand_unreachable,
stringify: source_util::expand_stringify,
trace_macros: trace_macros::expand_trace_macros,
}
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,6 @@ language_item_table! {
Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::Exact(0);
PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None;
PanicDisplay, sym::panic_display, panic_display, Target::Fn, GenericRequirement::None;
PanicStr, sym::panic_str, panic_str, Target::Fn, GenericRequirement::None;
ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None;
PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::Exact(0);
PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None;
Expand Down
25 changes: 22 additions & 3 deletions compiler/rustc_lint/src/non_fmt_panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
let f_diagnostic_name = cx.tcx.get_diagnostic_name(def_id);

if Some(def_id) == cx.tcx.lang_items().begin_panic_fn()
|| Some(def_id) == cx.tcx.lang_items().panic_fn()
|| Some(def_id) == cx.tcx.lang_items().panic_str()
|| f_diagnostic_name == Some(sym::panic_str)
{
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
if matches!(
Expand All @@ -61,6 +63,22 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
check_panic(cx, f, arg);
}
}
} else if f_diagnostic_name == Some(sym::unreachable_display) {
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
if cx.tcx.is_diagnostic_item(sym::unreachable_2015_macro, id) {
check_panic(
cx,
f,
// This is safe because we checked above that the callee is indeed
// unreachable_display
match &arg.kind {
// Get the borrowed arg not the borrow
hir::ExprKind::AddrOf(ast::BorrowKind::Ref, _, arg) => arg,
_ => bug!("call to unreachable_display without borrow"),
},
);
}
}
}
}
}
Expand All @@ -85,8 +103,8 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
return;
}

// Find the span of the argument to `panic!()`, before expansion in the
// case of `panic!(some_macro!())`.
// Find the span of the argument to `panic!()` or `unreachable!`, before expansion in the
// case of `panic!(some_macro!())` or `unreachable!(some_macro!())`.
// We don't use source_callsite(), because this `panic!(..)` might itself
// be expanded from another macro, in which case we want to stop at that
// expansion.
Expand Down Expand Up @@ -319,6 +337,7 @@ fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span,
| sym::std_panic_macro
| sym::assert_macro
| sym::debug_assert_macro
| sym::unreachable_macro
) {
break;
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1437,7 +1437,12 @@ symbols! {
unmarked_api,
unpin,
unreachable,
unreachable_2015,
unreachable_2015_macro,
unreachable_2021,
unreachable_2021_macro,
unreachable_code,
unreachable_display,
unreachable_macro,
unrestricted_attribute_tokens,
unsafe_block_in_unsafe_fn,
Expand Down
16 changes: 16 additions & 0 deletions library/core/src/macros/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,22 @@ macro_rules! writeln {
/// unreachable!("The loop should always return");
/// }
/// ```
#[cfg(not(bootstrap))]
#[macro_export]
#[rustc_builtin_macro(unreachable)]
#[allow_internal_unstable(edition_panic)]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "unreachable_macro")]
macro_rules! unreachable {
// Expands to either `$crate::panic::unreachable_2015` or `$crate::panic::unreachable_2021`
// depending on the edition of the caller.
($($arg:tt)*) => {
/* compiler built-in */
};
}

/// unreachable!() macro
#[cfg(bootstrap)]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "unreachable_macro")]
Expand Down
33 changes: 33 additions & 0 deletions library/core/src/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,39 @@ pub macro panic_2021 {
),
}

#[doc(hidden)]
#[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")]
#[allow_internal_unstable(core_panic)]
#[rustc_diagnostic_item = "unreachable_2015_macro"]
#[rustc_macro_transparency = "semitransparent"]
pub macro unreachable_2015 {
() => (
$crate::panicking::panic("internal error: entered unreachable code")
),
// Use of `unreachable_display` for non_fmt_panic lint.
// NOTE: the message ("internal error ...") is embeded directly in unreachable_display
($msg:expr $(,)?) => (
$crate::panicking::unreachable_display(&$msg)
),
($fmt:expr, $($arg:tt)*) => (
$crate::panic!($crate::concat!("internal error: entered unreachable code: ", $fmt), $($arg)*)
),
}

#[doc(hidden)]
#[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")]
#[allow_internal_unstable(core_panic)]
#[rustc_diagnostic_item = "unreachable_2021_macro"]
#[rustc_macro_transparency = "semitransparent"]
pub macro unreachable_2021 {
() => (
$crate::panicking::panic("internal error: entered unreachable code")
),
($($t:tt)+) => (
$crate::panic!("internal error: entered unreachable code: {}", $crate::format_args!($($t)+))
),
}

/// An internal trait used by libstd to pass data from libstd to `panic_unwind`
/// and other panic runtimes. Not intended to be stabilized any time soon, do
/// not use.
Expand Down
10 changes: 9 additions & 1 deletion library/core/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,20 @@ pub const fn panic(expr: &'static str) -> ! {

#[inline]
#[track_caller]
#[lang = "panic_str"] // needed for `non-fmt-panics` lint
#[rustc_diagnostic_item = "panic_str"]
#[rustc_const_unstable(feature = "core_panic", issue = "none")]
pub const fn panic_str(expr: &str) -> ! {
panic_display(&expr);
}

#[cfg(not(bootstrap))]
#[inline]
#[track_caller]
#[rustc_diagnostic_item = "unreachable_display"] // needed for `non-fmt-panics` lint
pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
panic_fmt(format_args!("internal error: entered unreachable code: {}", *x));
}

#[inline]
#[track_caller]
#[lang = "panic_display"] // needed for const-evaluated panics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
let mut _19: *const T; // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68
let mut _20: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84
let mut _21: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84
let mut _22: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _22: !; // in scope 0 at $SRC_DIR/core/src/panic.rs:LL:COL
let mut _23: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29
scope 1 {
debug v => _2; // in scope 1 at $DIR/issue_76432.rs:7:9: 7:10
Expand Down Expand Up @@ -66,16 +66,16 @@
}

bb1: {
StorageLive(_22); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
core::panicking::panic(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_22); // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
core::panicking::panic(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + span: $SRC_DIR/core/src/panic.rs:LL:COL
// + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(Scalar(<ZST>)) }
// ty::Const
// + ty: &str
// + val: Value(Slice { data: Allocation { bytes: [105, 110, 116, 101, 114, 110, 97, 108, 32, 101, 114, 114, 111, 114, 58, 32, 101, 110, 116, 101, 114, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [1099511627775], len: Size { raw: 40 } }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 40 })
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + span: $SRC_DIR/core/src/panic.rs:LL:COL
// + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [105, 110, 116, 101, 114, 110, 97, 108, 32, 101, 114, 114, 111, 114, 58, 32, 101, 110, 116, 101, 114, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [1099511627775], len: Size { raw: 40 } }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 40 }) }
}

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/consts/const-eval/const_panic.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed
LL | const Y: () = std::unreachable!();
| ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:12:15
|
= note: this error originates in the macro `std::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the macro `$crate::panic::unreachable_2015` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0080]: evaluation of constant value failed
--> $DIR/const_panic.rs:15:15
Expand Down Expand Up @@ -68,7 +68,7 @@ error[E0080]: evaluation of constant value failed
LL | const Y_CORE: () = core::unreachable!();
| ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:30:20
|
= note: this error originates in the macro `core::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the macro `$crate::panic::unreachable_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
m-ou-se marked this conversation as resolved.
Show resolved Hide resolved

error[E0080]: evaluation of constant value failed
--> $DIR/const_panic.rs:33:20
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/consts/const-eval/const_panic_2021.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed
LL | const C: () = std::unreachable!();
| ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:12:15
|
= note: this error originates in the macro `std::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the macro `$crate::panic::unreachable_2021` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0080]: evaluation of constant value failed
--> $DIR/const_panic_2021.rs:15:15
Expand Down Expand Up @@ -60,7 +60,7 @@ error[E0080]: evaluation of constant value failed
LL | const C_CORE: () = core::unreachable!();
| ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:27:20
|
= note: this error originates in the macro `core::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the macro `$crate::panic::unreachable_2021` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0080]: evaluation of constant value failed
--> $DIR/const_panic_2021.rs:30:20
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ error[E0080]: evaluation of constant value failed
LL | const Y: () = unreachable!();
| ^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:11:15
|
= note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the macro `$crate::panic::unreachable_2015` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0080]: evaluation of constant value failed
--> $DIR/const_panic_libcore_bin.rs:14:15
Expand Down
13 changes: 13 additions & 0 deletions src/test/ui/macros/unreachable-arg.edition_2021.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: format argument must be a string literal
--> $DIR/unreachable-arg.rs:15:18
|
LL | unreachable!(a);
| ^
|
help: you might be missing a string literal to format with
|
LL | unreachable!("{}", a);
| +++++

error: aborting due to previous error

16 changes: 16 additions & 0 deletions src/test/ui/macros/unreachable-arg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// ignore-emscripten no processes

// revisions: edition_2015 edition_2021
// [edition_2015]edition:2015
// [edition_2021]edition:2021
// [edition_2015]run-fail
// [edition_2021]check-fail
// [edition_2015]error-pattern:internal error: entered unreachable code: hello
// [edition_2021]error-pattern:format argument must be a string literal

#![allow(non_fmt_panics)]

fn main() {
let a = "hello";
unreachable!(a);
}
15 changes: 15 additions & 0 deletions src/test/ui/macros/unreachable-format-arg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// run-fail
// ignore-emscripten no processes

// revisions: edition_2015 edition_2021
// [edition_2015]edition:2015
// [edition_2021]edition:2021
// [edition_2015]error-pattern:internal error: entered unreachable code: x is {x}
// [edition_2021]error-pattern:internal error: entered unreachable code: x is 5

#![allow(non_fmt_panics)]

fn main() {
let x = 5;
unreachable!("x is {x}");
}
12 changes: 12 additions & 0 deletions src/test/ui/macros/unreachable-format-args.edition_2015.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error: there is no argument named `x`
--> $DIR/unreachable-format-args.rs:13:5
|
LL | unreachable!("x is {x} and y is {y}", y = 0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: did you intend to capture a variable `x` from the surrounding scope?
= note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
= note: this error originates in the macro `$crate::concat` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

14 changes: 14 additions & 0 deletions src/test/ui/macros/unreachable-format-args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// ignore-emscripten no processes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you ignoring emscripten in these tests?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did the same as this test unreachable-fmt-msg.rs


// revisions: edition_2015 edition_2021
// [edition_2015]edition:2015
// [edition_2021]edition:2021
// [edition_2015]check-fail
// [edition_2021]run-fail
// [edition_2015]error-pattern:there is no argument named `x`
// [edition_2021]error-pattern:internal error: entered unreachable code: x is 5 and y is 0

fn main() {
let x = 5;
unreachable!("x is {x} and y is {y}", y = 0);
}
Loading