diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 79d8abc4b694c..2839c4d77035a 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -488,6 +488,18 @@ macro_rules! expand_if_cached { }; } +/// Don't show the backtrace for query system by default +/// use `RUST_BACKTRACE=full` to show all the backtraces +#[inline(never)] +pub fn __rust_begin_short_backtrace(f: F) -> T +where + F: FnOnce() -> T, +{ + let result = f(); + std::hint::black_box(()); + result +} + // NOTE: `$V` isn't used here, but we still need to match on it so it can be passed to other macros // invoked by `rustc_query_append`. macro_rules! define_queries { @@ -498,21 +510,25 @@ macro_rules! define_queries { use super::*; $( - #[inline(always)] - #[tracing::instrument(level = "trace", skip(tcx))] - pub(super) fn $name<'tcx>( - tcx: TyCtxt<'tcx>, - span: Span, - key: query_keys::$name<'tcx>, - mode: QueryMode, - ) -> Option>> { - get_query_incr( - queries::$name::config(tcx), - QueryCtxt::new(tcx), - span, - key, - mode - ) + // Adding `__rust_end_short_backtrace` marker to backtraces so that we emit the frames + // when `RUST_BACKTRACE=1`, add a new mod with `$name` here is to allow duplicate naming + pub mod $name { + use super::*; + #[inline(never)] + pub fn __rust_end_short_backtrace<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + key: query_keys::$name<'tcx>, + mode: QueryMode, + ) -> Option>> { + get_query_incr( + queries::$name::config(tcx), + QueryCtxt::new(tcx), + span, + key, + mode + ) + } } )* } @@ -521,20 +537,22 @@ macro_rules! define_queries { use super::*; $( - #[inline(always)] - #[tracing::instrument(level = "trace", skip(tcx))] - pub(super) fn $name<'tcx>( - tcx: TyCtxt<'tcx>, - span: Span, - key: query_keys::$name<'tcx>, - __mode: QueryMode, - ) -> Option>> { - Some(get_query_non_incr( - queries::$name::config(tcx), - QueryCtxt::new(tcx), - span, - key, - )) + pub mod $name { + use super::*; + #[inline(never)] + pub fn __rust_end_short_backtrace<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + key: query_keys::$name<'tcx>, + __mode: QueryMode, + ) -> Option>> { + Some(get_query_non_incr( + queries::$name::config(tcx), + QueryCtxt::new(tcx), + span, + key, + )) + } } )* } @@ -542,11 +560,11 @@ macro_rules! define_queries { pub(crate) fn engine(incremental: bool) -> QueryEngine { if incremental { QueryEngine { - $($name: get_query_incr::$name,)* + $($name: get_query_incr::$name::__rust_end_short_backtrace,)* } } else { QueryEngine { - $($name: get_query_non_incr::$name,)* + $($name: get_query_non_incr::$name::__rust_end_short_backtrace,)* } } } @@ -578,10 +596,15 @@ macro_rules! define_queries { query_cache: offset_of!(QueryCaches<'tcx> => $name), cache_on_disk: |tcx, key| ::rustc_middle::query::cached::$name(tcx, key), execute_query: |tcx, key| erase(tcx.$name(key)), - compute: |tcx, key| query_provided_to_value::$name( - tcx, - call_provider!([$($modifiers)*][tcx, $name, key]) - ), + compute: |tcx, key| { + use crate::plumbing::__rust_begin_short_backtrace; + __rust_begin_short_backtrace(|| + query_provided_to_value::$name( + tcx, + call_provider!([$($modifiers)*][tcx, $name, key]) + ) + ) + }, can_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] true false), try_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] { |tcx, key, prev_index, index| { diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index 8752f46ff81e3..6f020940df12f 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -68,13 +68,17 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: } let mut hit = false; - let mut stop = false; backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { hit = true; + + // Any frames between `__rust_begin_short_backtrace` and `__rust_end_short_backtrace` + // are omitted from the backtrace in short mode, `__rust_end_short_backtrace` will be + // called before the panic hook, so we won't ignore any frames if there is no + // invoke of `__rust_begin_short_backtrace`. if print_fmt == PrintFmt::Short { if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { if start && sym.contains("__rust_begin_short_backtrace") { - stop = true; + start = false; return; } if sym.contains("__rust_end_short_backtrace") { @@ -88,9 +92,6 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: res = bt_fmt.frame().symbol(frame, symbol); } }); - if stop { - return false; - } #[cfg(target_os = "nto")] if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { if !hit && start { diff --git a/tests/run-make/short-ice/Makefile b/tests/run-make/short-ice/Makefile new file mode 100644 index 0000000000000..4f33d590237b3 --- /dev/null +++ b/tests/run-make/short-ice/Makefile @@ -0,0 +1,9 @@ +include ../tools.mk + +# ignore-windows + +export RUSTC := $(RUSTC_ORIGINAL) +export TMPDIR := $(TMPDIR) + +all: + bash check.sh diff --git a/tests/run-make/short-ice/check.sh b/tests/run-make/short-ice/check.sh new file mode 100644 index 0000000000000..96cd8fe86bc30 --- /dev/null +++ b/tests/run-make/short-ice/check.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +RUST_BACKTRACE=1 $RUSTC src/lib.rs -Z treat-err-as-bug=1 1>$TMPDIR/rust-test-1.log 2>&1 +RUST_BACKTRACE=full $RUSTC src/lib.rs -Z treat-err-as-bug=1 1>$TMPDIR/rust-test-2.log 2>&1 + +short=$(cat $TMPDIR/rust-test-1.log | wc -l) +full=$(cat $TMPDIR/rust-test-2.log | wc -l) +rustc_query_count=$(cat $TMPDIR/rust-test-1.log | grep rustc_query_ | wc -l) +rustc_query_count_full=$(cat $TMPDIR/rust-test-2.log | grep rustc_query_ | wc -l) + +begin_count=$(cat $TMPDIR/rust-test-2.log | grep __rust_begin_short_backtrace | wc -l) +end_count=$(cat $TMPDIR/rust-test-2.log | grep __rust_end_short_backtrace | wc -l) + +cat $TMPDIR/rust-test-1.log +echo "=====================" +cat $TMPDIR/rust-test-2.log +echo "=====================" + +echo "short backtrace: $short" +echo "full backtrace: $full" +echo "begin_count: $begin_count" +echo "end_count : $end_count" +echo "rustc_query_count: $rustc_query_count" +echo "rustc_query_count_full: $rustc_query_count_full" + +## backtraces to vary a bit depending on platform and configuration options, +## here we make sure that the short backtrace of rustc_query is shorter than the full, +## and marks are in pairs. +if [ $short -lt $full ] && + [ $begin_count -eq $end_count ] && + [ $(($rustc_query_count + 10)) -lt $rustc_query_count_full ] && + [ $rustc_query_count_full -gt 10 ]; then + exit 0 +else + exit 1 +fi diff --git a/tests/run-make/short-ice/src/lib.rs b/tests/run-make/short-ice/src/lib.rs new file mode 100644 index 0000000000000..b23b7f830d739 --- /dev/null +++ b/tests/run-make/short-ice/src/lib.rs @@ -0,0 +1,7 @@ +fn func(s: &str) { + println!("{}", s); +} + +fn main() { + func(1); +} diff --git a/tests/ui/panics/default-backtrace-ice.stderr b/tests/ui/panics/default-backtrace-ice.stderr index ddbfc4e7f3a0c..815ce4dd01528 100644 --- a/tests/ui/panics/default-backtrace-ice.stderr +++ b/tests/ui/panics/default-backtrace-ice.stderr @@ -8,6 +8,8 @@ LL | fn main() { missing_ident; } stack backtrace: (end_short_backtrace) (begin_short_backtrace) +(end_short_backtrace) +(begin_short_backtrace) error: the compiler unexpectedly panicked. this is a bug. diff --git a/tests/ui/panics/short-ice-remove-middle-frames-2.rs b/tests/ui/panics/short-ice-remove-middle-frames-2.rs new file mode 100644 index 0000000000000..38a80f8b6703a --- /dev/null +++ b/tests/ui/panics/short-ice-remove-middle-frames-2.rs @@ -0,0 +1,61 @@ +// compile-flags:-Cstrip=none +// run-fail +// check-run-results +// exec-env:RUST_BACKTRACE=1 +// ignore-android FIXME #17520 +// ignore-wasm no panic support +// ignore-openbsd no support for libbacktrace without filename +// ignore-emscripten no panic +// ignore-sgx Backtraces not symbolized +// ignore-fuchsia Backtraces not symbolized +// ignore-msvc the `__rust_{begin,end}_short_backtrace` symbols aren't reliable. + +/// This test case make sure that we can have multiple pairs of `__rust_{begin,end}_short_backtrace` + +#[inline(never)] +fn __rust_begin_short_backtrace T>(f: F) -> T { + let result = f(); + std::hint::black_box(result) +} + +#[inline(never)] +fn __rust_end_short_backtrace T>(f: F) -> T { + let result = f(); + std::hint::black_box(result) +} + +fn first() { + __rust_end_short_backtrace(|| second()); +} + +fn second() { + third(); // won't show up +} + +fn third() { + fourth(); // won't show up +} + +fn fourth() { + __rust_begin_short_backtrace(|| fifth()); +} + +fn fifth() { + __rust_end_short_backtrace(|| sixth()); +} + +fn sixth() { + seven(); // won't show up +} + +fn seven() { + __rust_begin_short_backtrace(|| eight()); +} + +fn eight() { + panic!("debug!!!"); +} + +fn main() { + first(); +} diff --git a/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr new file mode 100644 index 0000000000000..2592b7479186a --- /dev/null +++ b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr @@ -0,0 +1,11 @@ +thread 'main' panicked at 'debug!!!', $DIR/short-ice-remove-middle-frames-2.rs:56:5 +stack backtrace: + 0: std::panicking::begin_panic + 1: short_ice_remove_middle_frames_2::eight + 2: short_ice_remove_middle_frames_2::seven::{{closure}} + 3: short_ice_remove_middle_frames_2::fifth + 4: short_ice_remove_middle_frames_2::fourth::{{closure}} + 5: short_ice_remove_middle_frames_2::first + 6: short_ice_remove_middle_frames_2::main + 7: core::ops::function::FnOnce::call_once +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/tests/ui/panics/short-ice-remove-middle-frames.rs b/tests/ui/panics/short-ice-remove-middle-frames.rs new file mode 100644 index 0000000000000..c872084f0333e --- /dev/null +++ b/tests/ui/panics/short-ice-remove-middle-frames.rs @@ -0,0 +1,57 @@ +// compile-flags:-Cstrip=none +// run-fail +// check-run-results +// exec-env:RUST_BACKTRACE=1 +// ignore-android FIXME #17520 +// ignore-wasm no panic support +// ignore-openbsd no support for libbacktrace without filename +// ignore-emscripten no panic +// ignore-sgx Backtraces not symbolized +// ignore-fuchsia Backtraces not symbolized +// ignore-msvc the `__rust_{begin,end}_short_backtrace` symbols aren't reliable. + + +#[inline(never)] +fn __rust_begin_short_backtrace T>(f: F) -> T { + let result = f(); + std::hint::black_box(result) +} + +#[inline(never)] +fn __rust_end_short_backtrace T>(f: F) -> T { + let result = f(); + std::hint::black_box(result) +} + +fn first() { + __rust_end_short_backtrace(|| second()); + // do not take effect since we already has a inner call of __rust_end_short_backtrace +} + +fn second() { + __rust_end_short_backtrace(|| third()); +} + +fn third() { + fourth(); // won't show up in backtrace +} + +fn fourth() { + fifth(); // won't show up in backtrace +} + +fn fifth() { + __rust_begin_short_backtrace(|| sixth()); +} + +fn sixth() { + seven(); +} + +fn seven() { + panic!("debug!!!"); +} + +fn main() { + first(); +} diff --git a/tests/ui/panics/short-ice-remove-middle-frames.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr new file mode 100644 index 0000000000000..9c15f2e08feed --- /dev/null +++ b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr @@ -0,0 +1,12 @@ +thread 'main' panicked at 'debug!!!', $DIR/short-ice-remove-middle-frames.rs:52:5 +stack backtrace: + 0: std::panicking::begin_panic + 1: short_ice_remove_middle_frames::seven + 2: short_ice_remove_middle_frames::sixth + 3: short_ice_remove_middle_frames::fifth::{{closure}} + 4: short_ice_remove_middle_frames::second + 5: short_ice_remove_middle_frames::first::{{closure}} + 6: short_ice_remove_middle_frames::first + 7: short_ice_remove_middle_frames::main + 8: core::ops::function::FnOnce::call_once +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.