diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 6d3163b90b10c..531bcc4985cad 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3159,6 +3159,7 @@ impl Step for TestHelpers { .opt_level(0) .warnings(false) .debug(false) + .flag("-g1") .file(builder.src.join("tests/auxiliary/rust_test_helpers.c")) .compile("rust_test_helpers"); } diff --git a/tests/auxiliary/rust_test_helpers.c b/tests/auxiliary/rust_test_helpers.c index 977ea487a9804..5aee75b91eec9 100644 --- a/tests/auxiliary/rust_test_helpers.c +++ b/tests/auxiliary/rust_test_helpers.c @@ -427,3 +427,18 @@ uint16_t issue_97463_leak_uninit_data(uint32_t a, uint32_t b, uint32_t c) { return data->b; /* leak data */ } + +// Used for testing backtrace inline_tables_only +typedef void (*inline_tables_only_callback) (void *data); + +void inline_tables_only_baz(inline_tables_only_callback cb, void *data) { + cb(data); +} + +void inline_tables_only_bar(inline_tables_only_callback cb, void *data) { + inline_tables_only_baz(cb, data); +} + +void inline_tables_only_foo(inline_tables_only_callback cb, void *data) { + inline_tables_only_bar(cb, data); +} diff --git a/tests/ui/debuginfo/backtrace-inline-tables-only.rs b/tests/ui/debuginfo/backtrace-inline-tables-only.rs new file mode 100644 index 0000000000000..7cdc023de1c5f --- /dev/null +++ b/tests/ui/debuginfo/backtrace-inline-tables-only.rs @@ -0,0 +1,56 @@ +// Test that when debug info only includes line tables that backtrace is still generated +// successfully. This previously failed when compiling with `clang -g1`. +// Part of porting some backtrace tests to rustc. +// ignore-tidy-linelength +//@ ignore-windows +//@ run-pass +//@ compile-flags: -Cdebuginfo=line-tables-only +#![feature(backtrace_frames)] + +use std::backtrace::{self, Backtrace}; +use std::ffi::c_void; +use std::ptr::addr_of_mut; + +pub type Callback = extern "C" fn(data: *mut c_void); + +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + pub fn inline_tables_only_foo(cb: Callback, data: *mut c_void); +} + +extern "C" fn store_backtrace(data: *mut c_void) { + let bt = backtrace::Backtrace::capture(); + unsafe { *data.cast::>() = Some(bt) }; +} + +fn assert_contains( + backtrace: &Backtrace, + expected_name: &str, + expected_file: &str, + expected_line: u32, +) { + // FIXME(jieyouxu): fix this ugly fragile test when `BacktraceFrame` has accessors like... + // `symbols()`. + let backtrace = format!("{:#?}", backtrace); + eprintln!("{}", backtrace); + assert!(backtrace.contains(expected_name), "backtrace does not contain expected name {}", expected_name); + assert!(backtrace.contains(expected_file), "backtrace does not contain expected file {}", expected_file); + assert!(backtrace.contains(&expected_line.to_string()), "backtrace does not contain expected line {}", expected_line); +} + +/// Verifies that when debug info includes only lines tables the generated +/// backtrace is still generated successfully. The test exercises behaviour +/// that failed previously when compiling with clang -g1. +/// +/// The test case uses C rather than rust, since at that time when it was +/// written the debug info generated at level 1 in rustc was essentially +/// the same as at level 2. +fn main() { + std::env::set_var("RUST_BACKTRACE", "1"); + let mut backtrace: Option = None; + unsafe { inline_tables_only_foo(store_backtrace, addr_of_mut!(backtrace).cast::()) }; + let backtrace = backtrace.expect("backtrace"); + assert_contains(&backtrace, "inline_tables_only_foo", "rust_test_helpers.c", 435); + assert_contains(&backtrace, "inline_tables_only_bar", "rust_test_helpers.c", 439); + assert_contains(&backtrace, "inline_tables_only_baz", "rust_test_helpers.c", 443); +}