]>
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 // We disable tail merging here because it can't preserve debuginfo and thus
12 // potentially breaks the backtraces. Also, subtle changes can decide whether
13 // tail merging succeeds, so the test might work today but fail tomorrow due to a
14 // seemingly completely unrelated change.
15 // Unfortunately, LLVM has no "disable" option for this, so we have to set
16 // "enable" to 0 instead.
18 // compile-flags:-g -Cllvm-args=-enable-tail-merge=0
19 // ignore-pretty issue #37195
20 // ignore-emscripten spawning processes is not supported
23 use std
::io
::prelude
::*;
26 #[path = "backtrace-debuginfo-aux.rs"] mod aux;
29 () => ((file
!(), line
!()))
32 macro_rules
! dump_and_die
{
33 ($
($pos
:expr
),*) => ({
34 // FIXME(#18285): we cannot include the current position because
35 // the macro span takes over the last frame's file/line.
36 if cfg
!(any(target_os
= "android",
37 all(target_os
= "linux", target_arch
= "arm"),
38 target_os
= "freebsd",
39 target_os
= "dragonfly",
41 target_os
= "openbsd")) {
42 // skip these platforms as this support isn't implemented yet.
44 dump_filelines(&[$
($pos
),*]);
50 // we can't use a function as it will alter the backtrace
52 ($counter
:expr
; $
($pos
:expr
),*) => ({
54 dump_and_die
!($
($pos
),*)
61 type Pos
= (&'
static str, u32);
63 // this goes to stdout and each line has to be occurred
64 // in the following backtrace to stderr with a correct order.
65 fn dump_filelines(filelines
: &[Pos
]) {
66 // Skip top frame for MSVC, because it sees the macro rather than
67 // the containing function.
68 let skip
= if cfg
!(target_env
= "msvc") {1}
else {0}
;
69 for &(file
, line
) in filelines
.iter().rev().skip(skip
) {
71 let basename
= file
.split(&['
/'
, '
\\'
][..]).last().unwrap();
72 println
!("{}:{}", basename
, line
);
77 fn inner(counter
: &mut i32, main_pos
: Pos
, outer_pos
: Pos
) {
78 check
!(counter
; main_pos
, outer_pos
);
79 check
!(counter
; main_pos
, outer_pos
);
80 let inner_pos
= pos
!(); aux
::callback(|aux_pos
| {
81 check
!(counter
; main_pos
, outer_pos
, inner_pos
, aux_pos
);
83 let inner_pos
= pos
!(); aux
::callback_inlined(|aux_pos
| {
84 check
!(counter
; main_pos
, outer_pos
, inner_pos
, aux_pos
);
88 // LLVM does not yet output the required debug info to support showing inlined
89 // function calls in backtraces when targeting MSVC, so disable inlining in
91 #[cfg_attr(not(target_env = "msvc"), inline(always))]
92 #[cfg_attr(target_env = "msvc", inline(never))]
93 fn inner_inlined(counter
: &mut i32, main_pos
: Pos
, outer_pos
: Pos
) {
94 check
!(counter
; main_pos
, outer_pos
);
95 check
!(counter
; main_pos
, outer_pos
);
97 // Again, disable inlining for MSVC.
98 #[cfg_attr(not(target_env = "msvc"), inline(always))]
99 #[cfg_attr(target_env = "msvc", inline(never))]
100 fn inner_further_inlined(counter
: &mut i32, main_pos
: Pos
, outer_pos
: Pos
, inner_pos
: Pos
) {
101 check
!(counter
; main_pos
, outer_pos
, inner_pos
);
103 inner_further_inlined(counter
, main_pos
, outer_pos
, pos
!());
105 let inner_pos
= pos
!(); aux
::callback(|aux_pos
| {
106 check
!(counter
; main_pos
, outer_pos
, inner_pos
, aux_pos
);
108 let inner_pos
= pos
!(); aux
::callback_inlined(|aux_pos
| {
109 check
!(counter
; main_pos
, outer_pos
, inner_pos
, aux_pos
);
112 // this tests a distinction between two independent calls to the inlined function.
113 // (un)fortunately, LLVM somehow merges two consecutive such calls into one node.
114 inner_further_inlined(counter
, main_pos
, outer_pos
, pos
!());
118 fn outer(mut counter
: i32, main_pos
: Pos
) {
119 inner(&mut counter
, main_pos
, pos
!());
120 inner_inlined(&mut counter
, main_pos
, pos
!());
123 fn check_trace(output
: &str, error
: &str) {
124 // reverse the position list so we can start with the last item (which was the first line)
125 let mut remaining
: Vec
<&str> = output
.lines().map(|s
| s
.trim()).rev().collect();
127 assert
!(error
.contains("stack backtrace"), "no backtrace in the error: {}", error
);
128 for line
in error
.lines() {
129 if !remaining
.is_empty() && line
.contains(remaining
.last().unwrap()) {
133 assert
!(remaining
.is_empty(),
134 "trace does not match position list: {}\n---\n{}", error
, output
);
137 fn run_test(me
: &str) {
139 use std
::process
::Command
;
141 let mut template
= Command
::new(me
);
142 template
.env("RUST_BACKTRACE", "full");
146 let out
= Command
::new(me
)
147 .env("RUST_BACKTRACE", "full")
148 .arg(i
.to_string()).output().unwrap();
149 let output
= str::from_utf8(&out
.stdout
).unwrap();
150 let error
= str::from_utf8(&out
.stderr
).unwrap();
151 if out
.status
.success() {
152 assert
!(output
.contains("done."), "bad output for successful run: {}", output
);
155 check_trace(output
, error
);
163 let args
: Vec
<String
> = env
::args().collect();
165 let case
= args
[1].parse().unwrap();
166 writeln
!(&mut io
::stderr(), "test case {}", case
).unwrap();