]>
git.proxmox.com Git - rustc.git/blob - src/test/run-pass/backtrace-debuginfo.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 #![feature(rustc_attrs)]
13 // We disable tail merging here because it can't preserve debuginfo and thus
14 // potentially breaks the backtraces. Also, subtle changes can decide whether
15 // tail merging suceeds, so the test might work today but fail tomorrow due to a
16 // seemingly completely unrelated change.
17 // Unfortunately, LLVM has no "disable" option for this, so we have to set
18 // "enable" to 0 instead.
20 // compile-flags:-g -Cllvm-args=-enable-tail-merge=0
21 // ignore-pretty as this critically relies on line numbers
24 use std
::io
::prelude
::*;
27 #[path = "backtrace-debuginfo-aux.rs"] mod aux;
30 () => ((file
!(), line
!()))
33 macro_rules
! dump_and_die
{
34 ($
($pos
:expr
),*) => ({
35 // FIXME(#18285): we cannot include the current position because
36 // the macro span takes over the last frame's file/line.
37 if cfg
!(any(target_os
= "macos",
39 target_os
= "android",
40 all(target_os
= "linux", target_arch
= "arm"),
41 target_os
= "windows",
42 target_os
= "freebsd",
43 target_os
= "dragonfly",
45 target_os
= "openbsd")) {
46 // skip these platforms as this support isn't implemented yet.
48 dump_filelines(&[$
($pos
),*]);
54 // we can't use a function as it will alter the backtrace
56 ($counter
:expr
; $
($pos
:expr
),*) => ({
58 dump_and_die
!($
($pos
),*)
65 type Pos
= (&'
static str, u32);
67 // this goes to stdout and each line has to be occurred
68 // in the following backtrace to stderr with a correct order.
69 fn dump_filelines(filelines
: &[Pos
]) {
70 // Skip top frame for MSVC, because it sees the macro rather than
71 // the containing function.
72 let skip
= if cfg
!(target_env
= "msvc") {1}
else {0}
;
73 for &(file
, line
) in filelines
.iter().rev().skip(skip
) {
75 let basename
= file
.split(&['
/'
, '
\\'
][..]).last().unwrap();
76 println
!("{}:{}", basename
, line
);
81 #[rustc_no_mir] // FIXME #31005 MIR missing debuginfo currently.
82 fn inner(counter
: &mut i32, main_pos
: Pos
, outer_pos
: Pos
) {
83 check
!(counter
; main_pos
, outer_pos
);
84 check
!(counter
; main_pos
, outer_pos
);
85 let inner_pos
= pos
!(); aux
::callback(|aux_pos
| {
86 check
!(counter
; main_pos
, outer_pos
, inner_pos
, aux_pos
);
88 let inner_pos
= pos
!(); aux
::callback_inlined(|aux_pos
| {
89 check
!(counter
; main_pos
, outer_pos
, inner_pos
, aux_pos
);
93 // LLVM does not yet output the required debug info to support showing inlined
94 // function calls in backtraces when targetting MSVC, so disable inlining in
96 #[cfg_attr(not(target_env = "msvc"), inline(always))]
97 #[cfg_attr(target_env = "msvc", inline(never))]
98 #[rustc_no_mir] // FIXME #31005 MIR missing debuginfo currently.
99 fn inner_inlined(counter
: &mut i32, main_pos
: Pos
, outer_pos
: Pos
) {
100 check
!(counter
; main_pos
, outer_pos
);
101 check
!(counter
; main_pos
, outer_pos
);
103 // Again, disable inlining for MSVC.
104 #[cfg_attr(not(target_env = "msvc"), inline(always))]
105 #[cfg_attr(target_env = "msvc", inline(never))]
106 fn inner_further_inlined(counter
: &mut i32, main_pos
: Pos
, outer_pos
: Pos
, inner_pos
: Pos
) {
107 check
!(counter
; main_pos
, outer_pos
, inner_pos
);
109 inner_further_inlined(counter
, main_pos
, outer_pos
, pos
!());
111 let inner_pos
= pos
!(); aux
::callback(|aux_pos
| {
112 check
!(counter
; main_pos
, outer_pos
, inner_pos
, aux_pos
);
114 let inner_pos
= pos
!(); aux
::callback_inlined(|aux_pos
| {
115 check
!(counter
; main_pos
, outer_pos
, inner_pos
, aux_pos
);
118 // this tests a distinction between two independent calls to the inlined function.
119 // (un)fortunately, LLVM somehow merges two consecutive such calls into one node.
120 inner_further_inlined(counter
, main_pos
, outer_pos
, pos
!());
124 #[rustc_no_mir] // FIXME #31005 MIR missing debuginfo currently.
125 fn outer(mut counter
: i32, main_pos
: Pos
) {
126 inner(&mut counter
, main_pos
, pos
!());
127 inner_inlined(&mut counter
, main_pos
, pos
!());
130 fn check_trace(output
: &str, error
: &str) {
131 // reverse the position list so we can start with the last item (which was the first line)
132 let mut remaining
: Vec
<&str> = output
.lines().map(|s
| s
.trim()).rev().collect();
134 assert
!(error
.contains("stack backtrace"), "no backtrace in the error: {}", error
);
135 for line
in error
.lines() {
136 if !remaining
.is_empty() && line
.contains(remaining
.last().unwrap()) {
140 assert
!(remaining
.is_empty(),
141 "trace does not match position list: {}\n---\n{}", error
, output
);
144 fn run_test(me
: &str) {
146 use std
::process
::Command
;
148 let mut template
= Command
::new(me
);
149 template
.env("RUST_BACKTRACE", "1");
153 let out
= Command
::new(me
)
154 .env("RUST_BACKTRACE", "1")
155 .arg(i
.to_string()).output().unwrap();
156 let output
= str::from_utf8(&out
.stdout
).unwrap();
157 let error
= str::from_utf8(&out
.stderr
).unwrap();
158 if out
.status
.success() {
159 assert
!(output
.contains("done."), "bad output for successful run: {}", output
);
162 check_trace(output
, error
);
169 #[rustc_no_mir] // FIXME #31005 MIR missing debuginfo currently.
171 let args
: Vec
<String
> = env
::args().collect();
173 let case
= args
[1].parse().unwrap();
174 writeln
!(&mut io
::stderr(), "test case {}", case
).unwrap();