Skip to content

Commit 2fa1ecf

Browse files
committed
Improved support of collapse_debuginfo attribute for macroses. Enabled by default for builtin and core/std macroses.
1 parent 77d1699 commit 2fa1ecf

File tree

12 files changed

+389
-37
lines changed

12 files changed

+389
-37
lines changed

compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,7 @@ impl DebugContext {
6868
// In order to have a good line stepping behavior in debugger, we overwrite debug
6969
// locations of macro expansions with that of the outermost expansion site (when the macro is
7070
// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided).
71-
let span = if tcx.should_collapse_debuginfo(span) {
72-
span
73-
} else {
74-
// Walk up the macro expansion chain until we reach a non-expanded span.
75-
// We also stop at the function body level because no line stepping can occur
76-
// at the level above that.
77-
rustc_span::hygiene::walk_chain(span, function_span.ctxt())
78-
};
79-
71+
let span = tcx.collapsed_debuginfo(span, function_span.ctxt());
8072
match tcx.sess.source_map().lookup_line(span.lo()) {
8173
Ok(SourceFileAndLine { sf: file, line }) => {
8274
let line_pos = file.lines()[line];

compiler/rustc_codegen_ssa/src/mir/debuginfo.rs

+6-11
Original file line numberDiff line numberDiff line change
@@ -228,21 +228,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
228228
/// In order to have a good line stepping behavior in debugger, we overwrite debug
229229
/// locations of macro expansions with that of the outermost expansion site (when the macro is
230230
/// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided).
231-
fn adjust_span_for_debugging(&self, mut span: Span) -> Span {
231+
fn adjust_span_for_debugging(&self, span: Span) -> Span {
232232
// Bail out if debug info emission is not enabled.
233233
if self.debug_context.is_none() {
234234
return span;
235235
}
236-
237-
if self.cx.tcx().should_collapse_debuginfo(span) {
238-
// Walk up the macro expansion chain until we reach a non-expanded span.
239-
// We also stop at the function body level because no line stepping can occur
240-
// at the level above that.
241-
// Use span of the outermost expansion site, while keeping the original lexical scope.
242-
span = rustc_span::hygiene::walk_chain(span, self.mir.span.ctxt());
243-
}
244-
245-
span
236+
// Walk up the macro expansion chain until we reach a non-expanded span.
237+
// We also stop at the function body level because no line stepping can occur
238+
// at the level above that.
239+
// Use span of the outermost expansion site, while keeping the original lexical scope.
240+
self.cx.tcx().collapsed_debuginfo(span, self.mir.span.ctxt())
246241
}
247242

248243
fn spill_operand_to_stack(

compiler/rustc_expand/src/base.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,8 @@ impl SyntaxExtension {
783783
let local_inner_macros = attr::find_by_name(attrs, sym::macro_export)
784784
.and_then(|macro_export| macro_export.meta_item_list())
785785
.is_some_and(|l| attr::list_contains_name(&l, sym::local_inner_macros));
786-
let collapse_debuginfo = attr::contains_name(attrs, sym::collapse_debuginfo);
786+
let collapse_debuginfo = attr::contains_name(attrs, sym::collapse_debuginfo)
787+
|| attr::contains_name(attrs, sym::rustc_builtin_macro);
787788
tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
788789

789790
let (builtin_name, helper_attrs) = attr::find_by_name(attrs, sym::rustc_builtin_macro)

compiler/rustc_middle/src/ty/mod.rs

+32-4
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ use rustc_query_system::ich::StableHashingContext;
4848
use rustc_serialize::{Decodable, Encodable};
4949
use rustc_session::lint::LintBuffer;
5050
pub use rustc_session::lint::RegisteredTools;
51-
use rustc_span::hygiene::MacroKind;
51+
use rustc_span::hygiene::{HygieneData, MacroKind};
5252
use rustc_span::symbol::{kw, sym, Ident, Symbol};
53-
use rustc_span::{ExpnId, ExpnKind, Span};
53+
use rustc_span::{ExpnId, ExpnKind, Span, SyntaxContext};
5454
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
5555
pub use rustc_target::abi::{ReprFlags, ReprOptions};
5656
pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
@@ -2515,6 +2515,28 @@ impl<'tcx> TyCtxt<'tcx> {
25152515
(ident, scope)
25162516
}
25172517

2518+
/// Returns `true` if `span` originates in a macro's expansion where debuginfo should be
2519+
/// collapsed.
2520+
pub fn in_macro_expansion_with_collapse_debuginfo(
2521+
self,
2522+
span: Span,
2523+
hdata: &HygieneData,
2524+
) -> bool {
2525+
if span.from_expansion() {
2526+
let outer = hdata.expn_data(hdata.outer_expn(span.ctxt())).clone();
2527+
let in_std_macro = match outer.macro_def_id {
2528+
Some(macro_def_id) => {
2529+
let crate_name = self.crate_name(macro_def_id.krate);
2530+
crate_name == sym::std || crate_name == sym::core
2531+
}
2532+
None => false,
2533+
};
2534+
!matches!(outer.kind, ExpnKind::Macro(..)) || outer.collapse_debuginfo || in_std_macro
2535+
} else {
2536+
false
2537+
}
2538+
}
2539+
25182540
/// Returns `true` if the debuginfo for `span` should be collapsed to the outermost expansion
25192541
/// site. Only applies when `Span` is the result of macro expansion.
25202542
///
@@ -2523,15 +2545,21 @@ impl<'tcx> TyCtxt<'tcx> {
25232545
/// - If `collapse_debuginfo` is not enabled, then debuginfo is collapsed by default.
25242546
///
25252547
/// When `-Zdebug-macros` is provided then debuginfo will never be collapsed.
2526-
pub fn should_collapse_debuginfo(self, span: Span) -> bool {
2548+
pub fn should_collapse_debuginfo(self, hdata: &HygieneData, span: Span) -> bool {
25272549
!self.sess.opts.unstable_opts.debug_macros
25282550
&& if self.features().collapse_debuginfo {
2529-
span.in_macro_expansion_with_collapse_debuginfo()
2551+
self.in_macro_expansion_with_collapse_debuginfo(span, hdata)
25302552
} else {
25312553
span.from_expansion()
25322554
}
25332555
}
25342556

2557+
pub fn collapsed_debuginfo(self, span: Span, upto: SyntaxContext) -> Span {
2558+
rustc_span::hygiene::walk_chain_collapsed(span, upto, |hdata, span| {
2559+
self.should_collapse_debuginfo(hdata, span)
2560+
})
2561+
}
2562+
25352563
#[inline]
25362564
pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
25372565
matches!(

compiler/rustc_span/src/hygiene.rs

+41-5
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ impl ExpnId {
310310
}
311311

312312
#[derive(Debug)]
313-
pub(crate) struct HygieneData {
313+
pub struct HygieneData {
314314
/// Each expansion should have an associated expansion data, but sometimes there's a delay
315315
/// between creation of an expansion ID and obtaining its data (e.g. macros are collected
316316
/// first and then resolved later), so we use an `Option` here.
@@ -377,7 +377,7 @@ impl HygieneData {
377377
self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
378378
}
379379

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

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

@@ -443,15 +443,37 @@ impl HygieneData {
443443
}
444444

445445
fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
446+
let orig_span = span;
446447
debug!("walk_chain({:?}, {:?})", span, to);
447448
debug!("walk_chain: span ctxt = {:?}", span.ctxt());
448-
while span.from_expansion() && span.ctxt() != to {
449+
while span.ctxt() != to && span.from_expansion() {
449450
let outer_expn = self.outer_expn(span.ctxt());
450451
debug!("walk_chain({:?}): outer_expn={:?}", span, outer_expn);
451452
let expn_data = self.expn_data(outer_expn);
452453
debug!("walk_chain({:?}): expn_data={:?}", span, expn_data);
453454
span = expn_data.call_site;
454455
}
456+
debug!("walk_chain: for span {:?} >>> return span = {:?}", orig_span, span);
457+
span
458+
}
459+
460+
fn walk_chain_collapsed<F: Fn(&HygieneData, Span) -> bool>(
461+
&self,
462+
mut span: Span,
463+
to: SyntaxContext,
464+
should_collapse: F,
465+
) -> Span {
466+
let orig_span = span;
467+
debug!("walk_chain_collapsed({:?}, {:?})", span, to);
468+
debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt());
469+
while span.ctxt() != to && should_collapse(&self, span) {
470+
let outer_expn = self.outer_expn(span.ctxt());
471+
debug!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn);
472+
let expn_data = self.expn_data(outer_expn);
473+
debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data);
474+
span = expn_data.call_site;
475+
}
476+
debug!("walk_chain_collapsed: for span {:?} >>> return span = {:?}", orig_span, span);
455477
span
456478
}
457479

@@ -571,6 +593,20 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
571593
HygieneData::with(|data| data.walk_chain(span, to))
572594
}
573595

596+
pub fn walk_chain_collapsed<F: Fn(&HygieneData, Span) -> bool>(
597+
span: Span,
598+
to: SyntaxContext,
599+
should_collapse: F,
600+
) -> Span {
601+
HygieneData::with(|hdata| {
602+
if should_collapse(hdata, span) {
603+
hdata.walk_chain_collapsed(span, to, should_collapse)
604+
} else {
605+
span
606+
}
607+
})
608+
}
609+
574610
pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
575611
// The new contexts that need updating are at the end of the list and have `$crate` as a name.
576612
let (len, to_update) = HygieneData::with(|data| {
@@ -938,7 +974,7 @@ pub struct ExpnData {
938974
pub local_inner_macros: bool,
939975
/// Should debuginfo for the macro be collapsed to the outermost expansion site (in other
940976
/// words, was the macro definition annotated with `#[collapse_debuginfo]`)?
941-
pub(crate) collapse_debuginfo: bool,
977+
pub collapse_debuginfo: bool,
942978
}
943979

944980
impl !PartialEq for ExpnData {}

compiler/rustc_span/src/lib.rs

-7
Original file line numberDiff line numberDiff line change
@@ -568,13 +568,6 @@ impl Span {
568568
self.ctxt() != SyntaxContext::root()
569569
}
570570

571-
/// Returns `true` if `span` originates in a macro's expansion where debuginfo should be
572-
/// collapsed.
573-
pub fn in_macro_expansion_with_collapse_debuginfo(self) -> bool {
574-
let outer_expn = self.ctxt().outer_expn_data();
575-
matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo
576-
}
577-
578571
/// Returns `true` if `span` originates in a derive-macro's expansion.
579572
pub fn in_derive_expansion(self) -> bool {
580573
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// ignore-lldb
2+
#![feature(collapse_debuginfo)]
3+
4+
// Test that statement, skipped by macros, is correctly processed in debuginfo
5+
6+
// compile-flags:-g
7+
8+
// === GDB TESTS ===================================================================================
9+
10+
// gdb-command:run
11+
// gdb-command:next
12+
// gdb-check:[...]#loc2[...]
13+
// gdb-command:step
14+
// gdb-command:frame
15+
// gdb-check:[...]#loc_call1_pre[...]
16+
// gdb-command:next
17+
// gdb-command:frame
18+
// gdb-check:[...]#loc_in_proxy[...]
19+
// gdb-command:finish
20+
// gdb-check:[...]#loc4[...]
21+
// gdb-command:next
22+
// gdb-command:frame
23+
// gdb-check:[...]#loc5[...]
24+
// gdb-command:continue
25+
26+
27+
macro_rules! proxy_println {
28+
($($arg:tt)*) => {{
29+
println!($($arg)*); // #loc_in_proxy
30+
}};
31+
}
32+
33+
// Macro accepts 3 statements and removes the 2nd statement
34+
macro_rules! remove_second_statement {
35+
($s1:stmt; $s2:stmt; $s3:stmt;) => { $s1 $s3 }
36+
}
37+
38+
fn call1() {
39+
let rv = 0; // #loc_call1_pre
40+
proxy_println!("one"); // #loc_call1
41+
}
42+
43+
fn call2() {
44+
proxy_println!("two"); // #loc_call2
45+
}
46+
47+
fn call3() {
48+
proxy_println!("three"); // #loc_call3
49+
}
50+
51+
fn main() {
52+
let ret = 0; // #break, step should go to call1
53+
remove_second_statement! { // #loc1
54+
call1(); // #loc2, breakpoint should set to call1, step should go call3
55+
call2(); // #loc3, breakpoint should set to call3
56+
call3(); // #loc4, breakpoint should set to call3, step should go closing brace
57+
}
58+
std::process::exit(ret); // #loc5
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// ignore-lldb
2+
#![feature(collapse_debuginfo)]
3+
4+
// Test that statement, skipped by macros, is correctly processed in debuginfo
5+
6+
// compile-flags:-g
7+
8+
// === GDB TESTS ===================================================================================
9+
10+
// gdb-command:run
11+
// gdb-command:next
12+
// gdb-command:frame
13+
// gdb-check:[...]#loc2[...]
14+
// gdb-command:step
15+
// gdb-command:frame
16+
// gdb-command:step
17+
// gdb-command:frame
18+
// gdb-check:[...]#loc_call1_println[...]
19+
// gdb-command:finish
20+
// gdb-command:finish
21+
// gdb-check:[...]#loc4[...]
22+
// gdb-command:next
23+
// gdb-command:frame
24+
// gdb-check:[...]#loc5[...]
25+
// gdb-command:continue
26+
27+
// Macro accepts 3 statements and removes the 2nd statement
28+
macro_rules! remove_second_statement {
29+
($s1:stmt; $s2:stmt; $s3:stmt;) => { $s1 $s3 }
30+
}
31+
32+
fn call1() {
33+
(||{
34+
println!("one") // #loc_call1_println
35+
})(); // #loc_call1
36+
}
37+
38+
fn call2() {
39+
println!("two"); // #loc_call2
40+
}
41+
42+
fn call3() {
43+
println!("three"); // #loc_call3
44+
}
45+
46+
fn main() {
47+
let ret = 0; // #break, step should go to call1
48+
remove_second_statement! { // #loc1
49+
call1(); // #loc2, breakpoint should set to call1, step should go call3
50+
call2(); // #loc3, breakpoint should set to call3
51+
call3(); // #loc4, breakpoint should set to call3, step should go closing brace
52+
}
53+
std::process::exit(ret); // #loc5
54+
}
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// ignore-lldb
2+
//#![feature(collapse_debuginfo)]
3+
4+
// Test that statement, skipped by macros, is correctly processed in debuginfo
5+
6+
// compile-flags:-g
7+
8+
// === GDB TESTS ===================================================================================
9+
10+
// gdb-command:run
11+
// gdb-command:next
12+
// gdb-command:frame
13+
// gdb-check:[...]#loc2[...]
14+
// gdb-command:next
15+
// gdb-command:frame
16+
// gdb-check:[...]#loc4[...]
17+
// gdb-command:next
18+
// gdb-command:frame
19+
// gdb-check:[...]#loc5[...]
20+
// gdb-command:continue
21+
22+
23+
// Macro accepts 3 statements and removes the 2nd statement
24+
macro_rules! remove_second_statement {
25+
($s1:stmt; $s2:stmt; $s3:stmt;) => { $s1 $s3 }
26+
}
27+
28+
fn call1() {
29+
println!("one"); // #loc_call1
30+
}
31+
32+
fn call2() {
33+
println!("two"); // #loc_call2
34+
}
35+
36+
fn call3() {
37+
println!("three"); // #loc_call3
38+
}
39+
40+
fn main() {
41+
let ret = 0; // #break, step should go to call1
42+
remove_second_statement! { // #loc1
43+
call1(); // #loc2, breakpoint should set to call1, step should go call3
44+
call2(); // #loc3, breakpoint should set to call3
45+
call3(); // #loc4, breakpoint should set to call3, step should go closing brace
46+
}
47+
std::process::exit(ret); // #loc5
48+
}

0 commit comments

Comments
 (0)