mod auxiliary; macro_rules! pos { () => { (file!(), line!()) }; } macro_rules! check { ($($pos:expr),*) => ({ verify(&[$($pos,)* pos!()]); }) } type Pos = (&'static str, u32); #[test] fn doit() { 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)] #[cfg_attr(feature = "coresymbolication", inline(never))] #[rustfmt::skip] fn inner_inlined(main_pos: Pos, outer_pos: Pos) { check!(main_pos, outer_pos); check!(main_pos, outer_pos); #[inline(always)] #[cfg_attr(feature = "coresymbolication", inline(never))] 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; } } } } } }