Skip to content

Commit

Permalink
Improved support of collapse_debuginfo attribute for macros.
Browse files Browse the repository at this point in the history
  • Loading branch information
azhogin committed Dec 21, 2023
1 parent 77d1699 commit dc993ca
Show file tree
Hide file tree
Showing 8 changed files with 504 additions and 47 deletions.
10 changes: 1 addition & 9 deletions compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,7 @@ impl DebugContext {
// In order to have a good line stepping behavior in debugger, we overwrite debug
// locations of macro expansions with that of the outermost expansion site (when the macro is
// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided).
let span = if tcx.should_collapse_debuginfo(span) {
span
} else {
// Walk up the macro expansion chain until we reach a non-expanded span.
// We also stop at the function body level because no line stepping can occur
// at the level above that.
rustc_span::hygiene::walk_chain(span, function_span.ctxt())
};

let span = tcx.collapsed_debuginfo(span, function_span.ctxt());
match tcx.sess.source_map().lookup_line(span.lo()) {
Ok(SourceFileAndLine { sf: file, line }) => {
let line_pos = file.lines()[line];
Expand Down
17 changes: 6 additions & 11 deletions compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,21 +228,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
/// In order to have a good line stepping behavior in debugger, we overwrite debug
/// locations of macro expansions with that of the outermost expansion site (when the macro is
/// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided).
fn adjust_span_for_debugging(&self, mut span: Span) -> Span {
fn adjust_span_for_debugging(&self, span: Span) -> Span {
// Bail out if debug info emission is not enabled.
if self.debug_context.is_none() {
return span;
}

if self.cx.tcx().should_collapse_debuginfo(span) {
// Walk up the macro expansion chain until we reach a non-expanded span.
// We also stop at the function body level because no line stepping can occur
// at the level above that.
// Use span of the outermost expansion site, while keeping the original lexical scope.
span = rustc_span::hygiene::walk_chain(span, self.mir.span.ctxt());
}

span
// Walk up the macro expansion chain until we reach a non-expanded span.
// We also stop at the function body level because no line stepping can occur
// at the level above that.
// Use span of the outermost expansion site, while keeping the original lexical scope.
self.cx.tcx().collapsed_debuginfo(span, self.mir.span.ctxt())
}

fn spill_operand_to_stack(
Expand Down
21 changes: 5 additions & 16 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ use rustc_session::lint::LintBuffer;
pub use rustc_session::lint::RegisteredTools;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{ExpnId, ExpnKind, Span};
use rustc_span::{ExpnId, ExpnKind, Span, SyntaxContext};
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
pub use rustc_target::abi::{ReprFlags, ReprOptions};
pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
Expand Down Expand Up @@ -2515,21 +2515,10 @@ impl<'tcx> TyCtxt<'tcx> {
(ident, scope)
}

/// Returns `true` if the debuginfo for `span` should be collapsed to the outermost expansion
/// site. Only applies when `Span` is the result of macro expansion.
///
/// - If the `collapse_debuginfo` feature is enabled then debuginfo is not collapsed by default
/// and only when a macro definition is annotated with `#[collapse_debuginfo]`.
/// - If `collapse_debuginfo` is not enabled, then debuginfo is collapsed by default.
///
/// When `-Zdebug-macros` is provided then debuginfo will never be collapsed.
pub fn should_collapse_debuginfo(self, span: Span) -> bool {
!self.sess.opts.unstable_opts.debug_macros
&& if self.features().collapse_debuginfo {
span.in_macro_expansion_with_collapse_debuginfo()
} else {
span.from_expansion()
}
pub fn collapsed_debuginfo(self, span: Span, upto: SyntaxContext) -> Span {
let collapse_enabled = !self.sess.opts.unstable_opts.debug_macros;
let attr_enabled = self.features().collapse_debuginfo;
rustc_span::hygiene::walk_chain_collapsed(span, upto, collapse_enabled, attr_enabled)
}

#[inline]
Expand Down
55 changes: 52 additions & 3 deletions compiler/rustc_span/src/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ impl HygieneData {
self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
}

fn expn_data(&self, expn_id: ExpnId) -> &ExpnData {
pub fn expn_data(&self, expn_id: ExpnId) -> &ExpnData {
if let Some(expn_id) = expn_id.as_local() {
self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
} else {
Expand Down Expand Up @@ -412,7 +412,7 @@ impl HygieneData {
self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent
}

fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
pub fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
self.syntax_context_data[ctxt.0 as usize].outer_expn
}

Expand Down Expand Up @@ -443,18 +443,52 @@ impl HygieneData {
}

fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
let orig_span = span;
debug!("walk_chain({:?}, {:?})", span, to);
debug!("walk_chain: span ctxt = {:?}", span.ctxt());
while span.from_expansion() && span.ctxt() != to {
while span.ctxt() != to && span.from_expansion() {
let outer_expn = self.outer_expn(span.ctxt());
debug!("walk_chain({:?}): outer_expn={:?}", span, outer_expn);
let expn_data = self.expn_data(outer_expn);
debug!("walk_chain({:?}): expn_data={:?}", span, expn_data);
span = expn_data.call_site;
}
debug!("walk_chain: for span {:?} >>> return span = {:?}", orig_span, span);
span
}

// We need to walk up and update return span if we meet macro instantiation to be collapsed
fn walk_chain_collapsed(
&self,
mut span: Span,
to: SyntaxContext,
collapse_enabled: bool,
attr_enabled: bool,
) -> Span {
if !collapse_enabled {
return span;
}
let orig_span = span;
let mut rv_span = span;

debug!("walk_chain_collapsed({:?}, {:?})", span, to);
debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt());
while span.ctxt() != to && span.from_expansion() {
let outer_expn = self.outer_expn(span.ctxt());
debug!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn);
let expn_data = self.expn_data(outer_expn);
debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data);
span = expn_data.call_site;
if !attr_enabled ||
matches!(expn_data.kind, ExpnKind::Macro(..)) && expn_data.collapse_debuginfo
{
rv_span = span;
}
}
debug!("walk_chain_collapsed: for span {:?} >>> return span = {:?}", orig_span, rv_span);
rv_span
}

fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option<ExpnId> {
let mut scope = None;
while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) {
Expand Down Expand Up @@ -571,6 +605,21 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
HygieneData::with(|data| data.walk_chain(span, to))
}

pub fn walk_chain_collapsed(
span: Span,
to: SyntaxContext,
collapse_enabled: bool,
attr_enabled: bool,
) -> Span {
HygieneData::with(|hdata| {
if collapse_enabled && span.from_expansion() {
hdata.walk_chain_collapsed(span, to, collapse_enabled, attr_enabled)
} else {
span
}
})
}

pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
// The new contexts that need updating are at the end of the list and have `$crate` as a name.
let (len, to_update) = HygieneData::with(|data| {
Expand Down
9 changes: 1 addition & 8 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ use source_map::SourceMap;
pub mod edition;
use edition::Edition;
pub mod hygiene;
use hygiene::Transparency;
pub use hygiene::{DesugaringKind, ExpnKind, MacroKind};
pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext};
use hygiene::{Transparency};
use rustc_data_structures::stable_hasher::HashingControls;
pub mod def_id;
use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, LOCAL_CRATE};
Expand Down Expand Up @@ -568,13 +568,6 @@ impl Span {
self.ctxt() != SyntaxContext::root()
}

/// Returns `true` if `span` originates in a macro's expansion where debuginfo should be
/// collapsed.
pub fn in_macro_expansion_with_collapse_debuginfo(self) -> bool {
let outer_expn = self.ctxt().outer_expn_data();
matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo
}

/// Returns `true` if `span` originates in a derive-macro's expansion.
pub fn in_derive_expansion(self) -> bool {
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
Expand Down
110 changes: 110 additions & 0 deletions tests/debuginfo/collapse-debuginfo-in-non-collapse-macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// ignore-lldb
#![feature(collapse_debuginfo)]

// Test that statement, skipped by macros, is correctly processed in debuginfo

// compile-flags:-g

// === GDB TESTS ===================================================================================

// gdb-command:run
// gdb-command:next
// gdb-check:[...]#loc_rem_call1[...]
// gdb-command:step
// gdb-command:frame
// gdb-check:[...]#loc_call1_pre[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc_in_proxy[...]
// gdb-command:finish
// gdb-check:[...]#loc_rem_call3[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc_add_call1[...]
// gdb-command:step
// gdb-command:frame
// gdb-check:[...]#loc_call1_pre[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc_in_proxy[...]
// gdb-command:finish
// gdb-check:[...]#loc_add_macro[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc_add_call3[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc_reorder_call2[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc_reorder_call3[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc_reorder_call1[...]
// gdb-command:step
// gdb-command:frame
// gdb-check:[...]#loc_call1_pre[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc_in_proxy[...]
// gdb-command:finish
// gdb-check:[...]#loc_exit[...]
// gdb-command:continue

#[collapse_debuginfo]
macro_rules! myprintln {
($($arg:tt)*) => {{
println!($($arg)*);
}};
}

macro_rules! proxy_println {
($($arg:tt)*) => {{
myprintln!($($arg)*); // #loc_in_proxy
}};
}

// Macro accepts 3 statements and removes the 2nd statement
macro_rules! remove_second_statement {
($s1:stmt; $s2:stmt; $s3:stmt;) => { $s1 $s3 }
}

macro_rules! add_second_statement {
($s1:stmt; $s3:stmt;) => { $s1 call2(); $s3 } // #loc_add_macro
}

macro_rules! reorder_statements {
($s1:stmt; $s2:stmt; $s3:stmt;) => { $s2 $s3 $s1 }
}

fn call1() {
let rv = 0; // #loc_call1_pre
proxy_println!("one"); // #loc_call1
}

fn call2() {
proxy_println!("two"); // #loc_call2
}

fn call3() {
proxy_println!("three"); // #loc_call3
}

fn main() {
let ret = 0; // #break, step should go to call1
remove_second_statement! { // #loc_rem_hdr
call1(); // #loc_rem_call1
call2(); // #loc_rem_call2
call3(); // #loc_rem_call3
}
add_second_statement! { // #loc_add_hdr
call1(); // #loc_add_call1
call3(); // #loc_add_call3
}
reorder_statements! { // #loc_reorder_hdr
call1(); // #loc_reorder_call1
call2(); // #loc_reorder_call2
call3(); // #loc_reorder_call3
}
std::process::exit(ret); // #loc_exit
}

0 comments on commit dc993ca

Please sign in to comment.