Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved support of collapse_debuginfo attribute for macros. #118903

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
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)
}

fn spill_operand_to_stack(
Expand Down
22 changes: 11 additions & 11 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::{hygiene, ExpnId, ExpnKind, Span};
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,21 @@ 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.
/// Returns corrected span if the debuginfo for `span` should be collapsed to the outermost
/// expansion site (with collapse_debuginfo attribute if the corresponding feature enabled).
/// 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]`.
/// and only when a (some enclosing) 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.
petrochenkov marked this conversation as resolved.
Show resolved Hide resolved
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: Span) -> Span {
if self.sess.opts.unstable_opts.debug_macros || !span.from_expansion() {
return span;
}
let collapse_debuginfo_enabled = self.features().collapse_debuginfo;
hygiene::walk_chain_collapsed(span, upto, collapse_debuginfo_enabled)
}

#[inline]
Expand Down
34 changes: 33 additions & 1 deletion compiler/rustc_span/src/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,18 +443,46 @@ impl HygieneData {
}

fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
petrochenkov marked this conversation as resolved.
Show resolved Hide resolved
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() {
petrochenkov marked this conversation as resolved.
Show resolved Hide resolved
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: Span,
collapse_debuginfo_enabled: bool,
) -> Span {
let orig_span = span;
let mut ret_span = span;

debug!("walk_chain_collapsed({:?}, {:?})", span, to);
debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt());
while !span.eq_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 !collapse_debuginfo_enabled || expn_data.collapse_debuginfo {
ret_span = span;
}
}
debug!("walk_chain_collapsed: for span {:?} >>> return span = {:?}", orig_span, ret_span);
ret_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 +599,10 @@ 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: Span, collapse_debuginfo_enabled: bool) -> Span {
HygieneData::with(|hdata| hdata.walk_chain_collapsed(span, to, collapse_debuginfo_enabled))
}

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
7 changes: 0 additions & 7 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
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
124 changes: 124 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,124 @@
// ignore-lldb
#![feature(collapse_debuginfo)]

// Test that statement, skipped/added/reordered by macros, is correctly processed in debuginfo.
// When nested macros instantiations are tagged with collapse_debuginfo attribute,
// debug info should be corrected to the first outer macro instantiation
// without collapse_debuginfo attribute.
// collapse_debuginfo feature enabled.

// compile-flags:-g

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

// gdb-command:run
// gdb-command:next
// gdb-command:frame
// 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:next 2
// 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:next 2
// 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:next 2
// gdb-command:frame
// gdb-command:continue

#[inline(never)]
fn myprintln_impl(text: &str) {
println!("{}", text)
}

#[collapse_debuginfo]
macro_rules! myprintln {
($($arg:tt)*) => {{
myprintln_impl($($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 }
}
petrochenkov marked this conversation as resolved.
Show resolved Hide resolved

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

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
}
Loading
Loading