about summary refs log tree commit diff
path: root/tests/ui/backtrace/dylib-dep.rs
blob: 05fdb9afef80da27c9e81dc7730e69e706fa0bda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Check that backtrace info is correctly generated for dynamic libraries and is usable by a
// rust binary.
// Part of porting some backtrace tests to rustc: <https://github.com/rust-lang/rust/issues/122899>.
// Original test:
// <https://github.com/rust-lang/backtrace-rs/tree/6fa4b85b9962c3e1be8c2e5cc605cd078134152b/crates/dylib-dep>
// ignore-tidy-linelength
//@ ignore-android FIXME #17520
//@ ignore-fuchsia Backtraces not symbolized
//@ ignore-musl musl doesn't support dynamic libraries (at least when the original test was written).
//@ needs-unwind
//@ ignore-backends: gcc
//@ compile-flags: -g -Copt-level=0 -Cstrip=none -Cforce-frame-pointers=yes
//@ ignore-emscripten Requires custom symbolization code
//@ aux-crate: dylib_dep_helper=dylib-dep-helper.rs
//@ aux-crate: auxiliary=dylib-dep-helper-aux.rs
//@ run-pass

#![allow(improper_ctypes)]
#![allow(improper_ctypes_definitions)]

extern crate dylib_dep_helper;
extern crate auxiliary;

use std::backtrace::Backtrace;

macro_rules! pos {
    () => {
        (file!(), line!())
    };
}

#[collapse_debuginfo(yes)]
macro_rules! check {
    ($($pos:expr),*) => ({
        verify(&[$($pos,)* pos!()]);
    })
}

fn verify(filelines: &[Pos]) {
    let trace = Backtrace::capture();
    eprintln!("-----------------------------------");
    eprintln!("looking for:");
    for (file, line) in filelines.iter().rev() {
        eprintln!("\t{file}:{line}");
    }
    eprintln!("found:\n{trace:#?}");
    let mut iter = filelines.iter().rev();
    // FIXME(jieyouxu): use proper `BacktraceFrame` accessors when it becomes available. Right now,
    // this depends on the debug format of `Backtrace` which is of course fragile.
    let backtrace = format!("{:#?}", trace);
    while let Some((file, line)) = iter.next() {
        // FIXME(jieyouxu): make this test use proper accessors on `BacktraceFrames` once it has
        // them.
        assert!(backtrace.contains(file), "expected backtrace to contain {}", file);
        assert!(backtrace.contains(&line.to_string()), "expected backtrace to contain {}", line);
    }
}

type Pos = (&'static str, u32);

extern "C" {
    #[link_name = "foo"]
    fn foo(p: Pos, cb: fn(Pos, Pos));
}

fn main() {
    std::env::set_var("RUST_BACKTRACE", "1");

    unsafe {
        foo(pos!(), |a, b| {
            check!(a, b)
        })
    }

    outer(pos!());
}

#[inline(never)]
fn outer(main_pos: Pos) {
    inner(main_pos, pos!());
    inner_inlined(main_pos, pos!());
}

#[inline(never)]
fn inner(main_pos: Pos, outer_pos: Pos) {
    check!(main_pos, outer_pos);
    check!(main_pos, outer_pos);
    let inner_pos = pos!(); auxiliary::callback(|aux_pos| {
        check!(main_pos, outer_pos, inner_pos, aux_pos);
    });
    let inner_pos = pos!(); auxiliary::callback_inlined(|aux_pos| {
        check!(main_pos, outer_pos, inner_pos, aux_pos);
    });
}

#[inline(always)]
fn inner_inlined(main_pos: Pos, outer_pos: Pos) {
    check!(main_pos, outer_pos);
    check!(main_pos, outer_pos);

    #[inline(always)]
    fn inner_further_inlined(main_pos: Pos, outer_pos: Pos, inner_pos: Pos) {
        check!(main_pos, outer_pos, inner_pos);
    }
    inner_further_inlined(main_pos, outer_pos, pos!());

    let inner_pos = pos!(); auxiliary::callback(|aux_pos| {
        check!(main_pos, outer_pos, inner_pos, aux_pos);
    });
    let inner_pos = pos!(); auxiliary::callback_inlined(|aux_pos| {
        check!(main_pos, outer_pos, inner_pos, aux_pos);
    });

    // this tests a distinction between two independent calls to the inlined function.
    // (un)fortunately, LLVM somehow merges two consecutive such calls into one node.
    inner_further_inlined(main_pos, outer_pos, pos!());
}