summaryrefslogtreecommitdiffstats
path: root/vendor/backtrace/tests/accuracy/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/backtrace/tests/accuracy/main.rs')
-rw-r--r--vendor/backtrace/tests/accuracy/main.rs117
1 files changed, 117 insertions, 0 deletions
diff --git a/vendor/backtrace/tests/accuracy/main.rs b/vendor/backtrace/tests/accuracy/main.rs
new file mode 100644
index 000000000..149203a1b
--- /dev/null
+++ b/vendor/backtrace/tests/accuracy/main.rs
@@ -0,0 +1,117 @@
+mod auxiliary;
+
+macro_rules! pos {
+ () => {
+ (file!(), line!())
+ };
+}
+
+macro_rules! check {
+ ($($pos:expr),*) => ({
+ verify(&[$($pos,)* pos!()]);
+ })
+}
+
+type Pos = (&'static str, u32);
+
+#[test]
+fn doit() {
+ if
+ // Skip musl which is by default statically linked and doesn't support
+ // dynamic libraries.
+ !cfg!(target_env = "musl")
+ // Skip Miri, since it doesn't support dynamic libraries.
+ && !cfg!(miri)
+ {
+ // TODO(#238) this shouldn't have to happen first in this function, but
+ // currently it does.
+ let mut dir = std::env::current_exe().unwrap();
+ dir.pop();
+ if cfg!(windows) {
+ dir.push("dylib_dep.dll");
+ } else if cfg!(target_os = "macos") {
+ dir.push("libdylib_dep.dylib");
+ } else {
+ dir.push("libdylib_dep.so");
+ }
+ unsafe {
+ let lib = libloading::Library::new(&dir).unwrap();
+ let api = lib.get::<extern "C" fn(Pos, fn(Pos, Pos))>(b"foo").unwrap();
+ api(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)]
+#[rustfmt::skip]
+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)]
+#[rustfmt::skip]
+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!());
+}
+
+fn verify(filelines: &[Pos]) {
+ let trace = backtrace::Backtrace::new();
+ println!("-----------------------------------");
+ println!("looking for:");
+ for (file, line) in filelines.iter().rev() {
+ println!("\t{}:{}", file, line);
+ }
+ println!("found:\n{:?}", trace);
+ let mut symbols = trace.frames().iter().flat_map(|frame| frame.symbols());
+ let mut iter = filelines.iter().rev();
+ while let Some((file, line)) = iter.next() {
+ loop {
+ let sym = match symbols.next() {
+ Some(sym) => sym,
+ None => panic!("failed to find {}:{}", file, line),
+ };
+ if let Some(filename) = sym.filename() {
+ if let Some(lineno) = sym.lineno() {
+ if filename.ends_with(file) && lineno == *line {
+ break;
+ }
+ }
+ }
+ }
+ }
+}