aboutsummaryrefslogtreecommitdiff
path: root/vendor/backtrace/tests
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/backtrace/tests')
-rw-r--r--vendor/backtrace/tests/accuracy/auxiliary.rs15
-rw-r--r--vendor/backtrace/tests/accuracy/main.rs117
-rw-r--r--vendor/backtrace/tests/common/mod.rs14
-rw-r--r--vendor/backtrace/tests/concurrent-panics.rs72
-rw-r--r--vendor/backtrace/tests/current-exe-mismatch.rs134
-rw-r--r--vendor/backtrace/tests/long_fn_name.rs48
-rw-r--r--vendor/backtrace/tests/skip_inner_frames.rs44
-rw-r--r--vendor/backtrace/tests/smoke.rs323
8 files changed, 0 insertions, 767 deletions
diff --git a/vendor/backtrace/tests/accuracy/auxiliary.rs b/vendor/backtrace/tests/accuracy/auxiliary.rs
deleted file mode 100644
index 9c8015d..0000000
--- a/vendor/backtrace/tests/accuracy/auxiliary.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#[inline(never)]
-pub fn callback<F>(f: F)
-where
- F: FnOnce((&'static str, u32)),
-{
- f((file!(), line!()))
-}
-
-#[inline(always)]
-pub fn callback_inlined<F>(f: F)
-where
- F: FnOnce((&'static str, u32)),
-{
- f((file!(), line!()))
-}
diff --git a/vendor/backtrace/tests/accuracy/main.rs b/vendor/backtrace/tests/accuracy/main.rs
deleted file mode 100644
index 149203a..0000000
--- a/vendor/backtrace/tests/accuracy/main.rs
+++ /dev/null
@@ -1,117 +0,0 @@
-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;
- }
- }
- }
- }
- }
-}
diff --git a/vendor/backtrace/tests/common/mod.rs b/vendor/backtrace/tests/common/mod.rs
deleted file mode 100644
index 3c07934..0000000
--- a/vendor/backtrace/tests/common/mod.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-/// Some tests only make sense in contexts where they can re-exec the test
-/// itself. Not all contexts support this, so you can call this method to find
-/// out which case you are in.
-pub fn cannot_reexec_the_test() -> bool {
- // These run in docker containers on CI where they can't re-exec the test,
- // so just skip these for CI. No other reason this can't run on those
- // platforms though.
- // Miri does not have support for re-execing a file
- cfg!(unix)
- && (cfg!(target_arch = "arm")
- || cfg!(target_arch = "aarch64")
- || cfg!(target_arch = "s390x"))
- || cfg!(miri)
-}
diff --git a/vendor/backtrace/tests/concurrent-panics.rs b/vendor/backtrace/tests/concurrent-panics.rs
deleted file mode 100644
index a44a267..0000000
--- a/vendor/backtrace/tests/concurrent-panics.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use std::env;
-use std::panic;
-use std::process::Command;
-use std::sync::atomic::{AtomicBool, Ordering::SeqCst};
-use std::sync::Arc;
-use std::thread;
-
-const PANICS: usize = 100;
-const THREADS: usize = 8;
-const VAR: &str = "__THE_TEST_YOU_ARE_LUKE";
-
-mod common;
-
-fn main() {
- // If we cannot re-exec this test, there's no point in trying to do it.
- if common::cannot_reexec_the_test() {
- println!("test result: ok");
- return;
- }
-
- if env::var(VAR).is_err() {
- parent();
- } else {
- child();
- }
-}
-
-fn parent() {
- let me = env::current_exe().unwrap();
- let result = Command::new(&me)
- .env("RUST_BACKTRACE", "1")
- .env(VAR, "1")
- .output()
- .unwrap();
- if result.status.success() {
- println!("test result: ok");
- return;
- }
- println!("stdout:\n{}", String::from_utf8_lossy(&result.stdout));
- println!("stderr:\n{}", String::from_utf8_lossy(&result.stderr));
- println!("code: {}", result.status);
- panic!();
-}
-
-fn child() {
- let done = Arc::new(AtomicBool::new(false));
- let done2 = done.clone();
- let a = thread::spawn(move || {
- while !done2.load(SeqCst) {
- format!("{:?}", backtrace::Backtrace::new());
- }
- });
-
- let threads = (0..THREADS)
- .map(|_| {
- thread::spawn(|| {
- for _ in 0..PANICS {
- assert!(panic::catch_unwind(|| {
- panic!();
- })
- .is_err());
- }
- })
- })
- .collect::<Vec<_>>();
- for thread in threads {
- thread.join().unwrap();
- }
-
- done.store(true, SeqCst);
- a.join().unwrap();
-}
diff --git a/vendor/backtrace/tests/current-exe-mismatch.rs b/vendor/backtrace/tests/current-exe-mismatch.rs
deleted file mode 100644
index b655827..0000000
--- a/vendor/backtrace/tests/current-exe-mismatch.rs
+++ /dev/null
@@ -1,134 +0,0 @@
-// rust-lang/rust#101913: when you run your program explicitly via `ld.so`,
-// `std::env::current_exe` will return the path of *that* program, and not
-// the Rust program itself.
-
-use std::io::{BufRead, BufReader};
-use std::path::{Path, PathBuf};
-use std::process::Command;
-
-mod common;
-
-fn main() {
- if std::env::var(VAR).is_err() {
- // the parent waits for the child; then we then handle either printing
- // "test result: ok", "test result: ignored", or panicking.
- match parent() {
- Ok(()) => {
- println!("test result: ok");
- }
- Err(EarlyExit::IgnoreTest(_)) => {
- println!("test result: ignored");
- }
- Err(EarlyExit::IoError(e)) => {
- println!("{} parent encoutered IoError: {:?}", file!(), e);
- panic!();
- }
- }
- } else {
- // println!("{} running child", file!());
- child().unwrap();
- }
-}
-
-const VAR: &str = "__THE_TEST_YOU_ARE_LUKE";
-
-#[derive(Debug)]
-enum EarlyExit {
- IgnoreTest(String),
- IoError(std::io::Error),
-}
-
-impl From<std::io::Error> for EarlyExit {
- fn from(e: std::io::Error) -> Self {
- EarlyExit::IoError(e)
- }
-}
-
-fn parent() -> Result<(), EarlyExit> {
- // If we cannot re-exec this test, there's no point in trying to do it.
- if common::cannot_reexec_the_test() {
- return Err(EarlyExit::IgnoreTest("(cannot reexec)".into()));
- }
-
- let me = std::env::current_exe().unwrap();
- let ld_so = find_interpreter(&me)?;
-
- // use interp to invoke current exe, yielding child test.
- //
- // (if you're curious what you might compare this against, you can try
- // swapping in the below definition for `result`, which is the easy case of
- // not using the ld.so interpreter directly that Rust handled fine even
- // prior to resolution of rust-lang/rust#101913.)
- //
- // let result = Command::new(me).env(VAR, "1").output()?;
- let result = Command::new(ld_so).env(VAR, "1").arg(&me).output().unwrap();
-
- if result.status.success() {
- return Ok(());
- }
- println!("stdout:\n{}", String::from_utf8_lossy(&result.stdout));
- println!("stderr:\n{}", String::from_utf8_lossy(&result.stderr));
- println!("code: {}", result.status);
- panic!();
-}
-
-fn child() -> Result<(), EarlyExit> {
- let bt = backtrace::Backtrace::new();
- println!("{:?}", bt);
-
- let mut found_my_name = false;
-
- let my_filename = file!();
- 'frames: for frame in bt.frames() {
- let symbols = frame.symbols();
- if symbols.is_empty() {
- continue;
- }
-
- for sym in symbols {
- if let Some(filename) = sym.filename() {
- if filename.ends_with(my_filename) {
- // huzzah!
- found_my_name = true;
- break 'frames;
- }
- }
- }
- }
-
- assert!(found_my_name);
-
- Ok(())
-}
-
-// we use the `readelf` command to extract the path to the interpreter requested
-// by our binary.
-//
-// if we cannot `readelf` for some reason, or if we fail to parse its output,
-// then we will just give up on this test (and not treat it as a test failure).
-fn find_interpreter(me: &Path) -> Result<PathBuf, EarlyExit> {
- let result = Command::new("readelf")
- .arg("-l")
- .arg(me)
- .output()
- .map_err(|_err| EarlyExit::IgnoreTest("readelf invocation failed".into()))?;
- if result.status.success() {
- let r = BufReader::new(&result.stdout[..]);
- for line in r.lines() {
- let line = line?;
- let line = line.trim();
- let prefix = "[Requesting program interpreter: ";
- if let Some((_, suffix)) = line.split_once(prefix) {
- if let Some((found_path, _)) = suffix.rsplit_once("]") {
- return Ok(found_path.into());
- }
- }
- }
-
- Err(EarlyExit::IgnoreTest(
- "could not find interpreter from readelf output".into(),
- ))
- } else {
- Err(EarlyExit::IgnoreTest("readelf returned non-success".into()))
- }
-}
diff --git a/vendor/backtrace/tests/long_fn_name.rs b/vendor/backtrace/tests/long_fn_name.rs
deleted file mode 100644
index fa4cfda..0000000
--- a/vendor/backtrace/tests/long_fn_name.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-use backtrace::Backtrace;
-
-// 50-character module name
-mod _234567890_234567890_234567890_234567890_234567890 {
- // 50-character struct name
- #[allow(non_camel_case_types)]
- pub struct _234567890_234567890_234567890_234567890_234567890<T>(T);
- impl<T> _234567890_234567890_234567890_234567890_234567890<T> {
- #[allow(dead_code)]
- pub fn new() -> crate::Backtrace {
- crate::Backtrace::new()
- }
- }
-}
-
-// Long function names must be truncated to (MAX_SYM_NAME - 1) characters.
-// Only run this test for msvc, since gnu prints "<no info>" for all frames.
-#[test]
-#[cfg(all(windows, target_env = "msvc"))]
-fn test_long_fn_name() {
- use _234567890_234567890_234567890_234567890_234567890::_234567890_234567890_234567890_234567890_234567890 as S;
-
- // 10 repetitions of struct name, so fully qualified function name is
- // atleast 10 * (50 + 50) * 2 = 2000 characters long.
- // It's actually longer since it also includes `::`, `<>` and the
- // name of the current module
- let bt = S::<S<S<S<S<S<S<S<S<S<i32>>>>>>>>>>::new();
- println!("{:?}", bt);
-
- let mut found_long_name_frame = false;
-
- for frame in bt.frames() {
- let symbols = frame.symbols();
- if symbols.is_empty() {
- continue;
- }
-
- if let Some(function_name) = symbols[0].name() {
- let function_name = function_name.as_str().unwrap();
- if function_name.contains("::_234567890_234567890_234567890_234567890_234567890") {
- found_long_name_frame = true;
- assert!(function_name.len() > 200);
- }
- }
- }
-
- assert!(found_long_name_frame);
-}
diff --git a/vendor/backtrace/tests/skip_inner_frames.rs b/vendor/backtrace/tests/skip_inner_frames.rs
deleted file mode 100644
index 60bba35..0000000
--- a/vendor/backtrace/tests/skip_inner_frames.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-use backtrace::Backtrace;
-
-// This test only works on platforms which have a working `symbol_address`
-// function for frames which reports the starting address of a symbol. As a
-// result it's only enabled on a few platforms.
-const ENABLED: bool = cfg!(all(
- // Windows hasn't really been tested, and macOS doesn't support actually
- // finding an enclosing frame, so disable this
- target_os = "linux",
- // On ARM finding the enclosing function is simply returning the ip itself.
- not(target_arch = "arm"),
-));
-
-#[test]
-fn backtrace_new_unresolved_should_start_with_call_site_trace() {
- if !ENABLED {
- return;
- }
- let mut b = Backtrace::new_unresolved();
- b.resolve();
- println!("{:?}", b);
-
- assert!(!b.frames().is_empty());
-
- let this_ip = backtrace_new_unresolved_should_start_with_call_site_trace as usize;
- println!("this_ip: {:?}", this_ip as *const usize);
- let frame_ip = b.frames().first().unwrap().symbol_address() as usize;
- assert_eq!(this_ip, frame_ip);
-}
-
-#[test]
-fn backtrace_new_should_start_with_call_site_trace() {
- if !ENABLED {
- return;
- }
- let b = Backtrace::new();
- println!("{:?}", b);
-
- assert!(!b.frames().is_empty());
-
- let this_ip = backtrace_new_should_start_with_call_site_trace as usize;
- let frame_ip = b.frames().first().unwrap().symbol_address() as usize;
- assert_eq!(this_ip, frame_ip);
-}
diff --git a/vendor/backtrace/tests/smoke.rs b/vendor/backtrace/tests/smoke.rs
deleted file mode 100644
index 683a6f0..0000000
--- a/vendor/backtrace/tests/smoke.rs
+++ /dev/null
@@ -1,323 +0,0 @@
-use backtrace::Frame;
-use std::thread;
-
-#[test]
-// FIXME: shouldn't ignore this test on i686-msvc, unsure why it's failing
-#[cfg_attr(all(target_arch = "x86", target_env = "msvc"), ignore)]
-#[rustfmt::skip] // we care about line numbers here
-fn smoke_test_frames() {
- frame_1(line!());
- #[inline(never)] fn frame_1(start_line: u32) { frame_2(start_line) }
- #[inline(never)] fn frame_2(start_line: u32) { frame_3(start_line) }
- #[inline(never)] fn frame_3(start_line: u32) { frame_4(start_line) }
- #[inline(never)] fn frame_4(start_line: u32) {
- let mut v = Vec::new();
- backtrace::trace(|cx| {
- v.push(cx.clone());
- true
- });
-
- // Various platforms have various bits of weirdness about their
- // backtraces. To find a good starting spot let's search through the
- // frames
- let target = frame_4 as usize;
- let offset = v
- .iter()
- .map(|frame| frame.symbol_address() as usize)
- .enumerate()
- .filter_map(|(i, sym)| {
- if sym >= target {
- Some((sym, i))
- } else {
- None
- }
- })
- .min()
- .unwrap()
- .1;
- let mut frames = v[offset..].iter();
-
- assert_frame(
- frames.next().unwrap(),
- frame_4 as usize,
- "frame_4",
- "tests/smoke.rs",
- start_line + 6,
- 9,
- );
- assert_frame(
- frames.next().unwrap(),
- frame_3 as usize,
- "frame_3",
- "tests/smoke.rs",
- start_line + 3,
- 52,
- );
- assert_frame(
- frames.next().unwrap(),
- frame_2 as usize,
- "frame_2",
- "tests/smoke.rs",
- start_line + 2,
- 52,
- );
- assert_frame(
- frames.next().unwrap(),
- frame_1 as usize,
- "frame_1",
- "tests/smoke.rs",
- start_line + 1,
- 52,
- );
- assert_frame(
- frames.next().unwrap(),
- smoke_test_frames as usize,
- "smoke_test_frames",
- "",
- 0,
- 0,
- );
- }
-
- fn assert_frame(
- frame: &Frame,
- actual_fn_pointer: usize,
- expected_name: &str,
- expected_file: &str,
- expected_line: u32,
- expected_col: u32,
- ) {
- backtrace::resolve_frame(frame, |sym| {
- print!("symbol ip:{:?} address:{:?} ", frame.ip(), frame.symbol_address());
- if let Some(name) = sym.name() {
- print!("name:{} ", name);
- }
- if let Some(file) = sym.filename() {
- print!("file:{} ", file.display());
- }
- if let Some(lineno) = sym.lineno() {
- print!("lineno:{} ", lineno);
- }
- if let Some(colno) = sym.colno() {
- print!("colno:{} ", colno);
- }
- println!();
- });
-
- let ip = frame.ip() as usize;
- let sym = frame.symbol_address() as usize;
- assert!(ip >= sym);
- assert!(
- sym >= actual_fn_pointer,
- "{:?} < {:?} ({} {}:{}:{})",
- sym as *const usize,
- actual_fn_pointer as *const usize,
- expected_name,
- expected_file,
- expected_line,
- expected_col,
- );
-
- // windows dbghelp is *quite* liberal (and wrong) in many of its reports
- // right now...
- //
- // This assertion can also fail for release builds, so skip it there
- if cfg!(debug_assertions) {
- assert!(sym - actual_fn_pointer < 1024);
- }
-
- let mut resolved = 0;
-
- let mut name = None;
- let mut addr = None;
- let mut col = None;
- let mut line = None;
- let mut file = None;
- backtrace::resolve_frame(frame, |sym| {
- resolved += 1;
- name = sym.name().map(|v| v.to_string());
- addr = sym.addr();
- col = sym.colno();
- line = sym.lineno();
- file = sym.filename().map(|v| v.to_path_buf());
- });
- assert!(resolved > 0);
-
- let name = name.expect("didn't find a name");
-
- // in release mode names get weird as functions can get merged
- // together with `mergefunc`, so only assert this in debug mode
- if cfg!(debug_assertions) {
- assert!(
- name.contains(expected_name),
- "didn't find `{}` in `{}`",
- expected_name,
- name
- );
- }
-
- addr.expect("didn't find a symbol");
-
- if cfg!(debug_assertions) {
- let line = line.expect("didn't find a line number");
- let file = file.expect("didn't find a line number");
- if !expected_file.is_empty() {
- assert!(
- file.ends_with(expected_file),
- "{:?} didn't end with {:?}",
- file,
- expected_file
- );
- }
- if expected_line != 0 {
- assert!(
- line == expected_line,
- "bad line number on frame for `{}`: {} != {}",
- expected_name,
- line,
- expected_line
- );
- }
-
- // dbghelp on MSVC doesn't support column numbers
- if !cfg!(target_env = "msvc") {
- let col = col.expect("didn't find a column number");
- if expected_col != 0 {
- assert!(
- col == expected_col,
- "bad column number on frame for `{}`: {} != {}",
- expected_name,
- col,
- expected_col
- );
- }
- }
- }
- }
-}
-
-#[test]
-fn many_threads() {
- let threads = (0..16)
- .map(|_| {
- thread::spawn(|| {
- for _ in 0..16 {
- backtrace::trace(|frame| {
- backtrace::resolve(frame.ip(), |symbol| {
- let _s = symbol.name().map(|s| s.to_string());
- });
- true
- });
- }
- })
- })
- .collect::<Vec<_>>();
-
- for t in threads {
- t.join().unwrap()
- }
-}
-
-#[test]
-#[cfg(feature = "rustc-serialize")]
-fn is_rustc_serialize() {
- extern crate rustc_serialize;
-
- fn is_encode<T: rustc_serialize::Encodable>() {}
- fn is_decode<T: rustc_serialize::Decodable>() {}
-
- is_encode::<backtrace::Backtrace>();
- is_decode::<backtrace::Backtrace>();
-}
-
-#[test]
-#[cfg(feature = "serde")]
-fn is_serde() {
- extern crate serde;
-
- fn is_serialize<T: serde::ser::Serialize>() {}
- fn is_deserialize<T: serde::de::DeserializeOwned>() {}
-
- is_serialize::<backtrace::Backtrace>();
- is_deserialize::<backtrace::Backtrace>();
-}
-
-#[test]
-fn sp_smoke_test() {
- let mut refs = vec![];
- recursive_stack_references(&mut refs);
- return;
-
- #[inline(never)]
- fn recursive_stack_references(refs: &mut Vec<usize>) {
- assert!(refs.len() < 5);
-
- let x = refs.len();
- refs.push(&x as *const _ as usize);
-
- if refs.len() < 5 {
- recursive_stack_references(refs);
- eprintln!("exiting: {}", x);
- return;
- }
-
- backtrace::trace(make_trace_closure(refs));
- eprintln!("exiting: {}", x);
- }
-
- // NB: the following `make_*` functions are pulled out of line, rather than
- // defining their results as inline closures at their call sites, so that
- // the resulting closures don't have "recursive_stack_references" in their
- // mangled names.
-
- fn make_trace_closure<'a>(
- refs: &'a mut Vec<usize>,
- ) -> impl FnMut(&backtrace::Frame) -> bool + 'a {
- let mut child_sp = None;
- let mut child_ref = None;
- move |frame| {
- eprintln!("\n=== frame ===================================");
-
- let mut is_recursive_stack_references = false;
- backtrace::resolve(frame.ip(), |sym| {
- is_recursive_stack_references |=
- sym.name()
- .and_then(|name| name.as_str())
- .map_or(false, |name| {
- eprintln!("name = {}", name);
- name.contains("recursive_stack_references")
- })
- });
-
- let sp = frame.sp() as usize;
- eprintln!("sp = {:p}", sp as *const u8);
- if sp == 0 {
- // If the SP is null, then we don't have an implementation for
- // getting the SP on this target. Just keep walking the stack,
- // but don't make our assertions about the on-stack pointers and
- // SP values.
- return true;
- }
-
- // The stack grows down.
- if let Some(child_sp) = child_sp {
- assert!(child_sp <= sp);
- }
-
- if is_recursive_stack_references {
- let r = refs.pop().unwrap();
- eprintln!("ref = {:p}", r as *const u8);
- if sp != 0 {
- assert!(r > sp);
- if let Some(child_ref) = child_ref {
- assert!(sp >= child_ref);
- }
- }
- child_ref = Some(r);
- }
-
- child_sp = Some(sp);
- true
- }
- }
-}