Skip to content

Commit 374c882

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

File tree

13 files changed

+396
-43
lines changed

13 files changed

+396
-43
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

+47-11
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,18 +443,38 @@ impl HygieneData {
443443
}
444444

445445
fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
446-
debug!("walk_chain({:?}, {:?})", span, to);
447-
debug!("walk_chain: span ctxt = {:?}", span.ctxt());
448-
while span.from_expansion() && span.ctxt() != to {
446+
trace!("walk_chain({:?}, {:?})", span, to);
447+
trace!("walk_chain: span ctxt = {:?}", span.ctxt());
448+
while span.ctxt() != to && span.from_expansion() {
449449
let outer_expn = self.outer_expn(span.ctxt());
450-
debug!("walk_chain({:?}): outer_expn={:?}", span, outer_expn);
450+
trace!("walk_chain({:?}): outer_expn={:?}", span, outer_expn);
451451
let expn_data = self.expn_data(outer_expn);
452-
debug!("walk_chain({:?}): expn_data={:?}", span, expn_data);
452+
trace!("walk_chain({:?}): expn_data={:?}", span, expn_data);
453453
span = expn_data.call_site;
454454
}
455455
span
456456
}
457457

458+
fn walk_chain_collapsed<F: Fn(&HygieneData, Span) -> bool>(
459+
&self,
460+
mut span: Span,
461+
to: SyntaxContext,
462+
should_collapse: F,
463+
) -> Span {
464+
let orig_span = span;
465+
trace!("walk_chain_collapsed({:?}, {:?})", span, to);
466+
trace!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt());
467+
while span.ctxt() != to && should_collapse(&self, span) {
468+
let outer_expn = self.outer_expn(span.ctxt());
469+
trace!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn);
470+
let expn_data = self.expn_data(outer_expn);
471+
trace!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data);
472+
span = expn_data.call_site;
473+
}
474+
trace!("walk_chain_collapsed: for span {:?} >>> return span = {:?}", orig_span, span);
475+
span
476+
}
477+
458478
fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option<ExpnId> {
459479
let mut scope = None;
460480
while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) {
@@ -568,9 +588,25 @@ impl HygieneData {
568588
}
569589

570590
pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
591+
debug!("walk_chain call({:?}, {:?})", span, to);
571592
HygieneData::with(|data| data.walk_chain(span, to))
572593
}
573594

595+
pub fn walk_chain_collapsed<F: Fn(&HygieneData, Span) -> bool>(
596+
span: Span,
597+
to: SyntaxContext,
598+
should_collapse: F,
599+
) -> Span {
600+
debug!("walk_chain_collapsed call({:?}, {:?})", span, to);
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 {}
@@ -1279,7 +1315,7 @@ pub fn decode_expn_id(
12791315
decode_data: impl FnOnce(ExpnId) -> (ExpnData, ExpnHash),
12801316
) -> ExpnId {
12811317
if index == 0 {
1282-
trace!("decode_expn_id: deserialized root");
1318+
//trace!("decode_expn_id: deserialized root");
12831319
return ExpnId::root();
12841320
}
12851321

@@ -1312,7 +1348,7 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
13121348
) -> SyntaxContext {
13131349
let raw_id: u32 = Decodable::decode(d);
13141350
if raw_id == 0 {
1315-
trace!("decode_syntax_context: deserialized root");
1351+
//trace!("decode_syntax_context: deserialized root");
13161352
// The root is special
13171353
return SyntaxContext::root();
13181354
}

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, _))

library/std/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@
272272
#![feature(c_unwind)]
273273
#![feature(cfg_target_thread_local)]
274274
#![feature(cfi_encoding)]
275+
#![feature(collapse_debuginfo)]
275276
#![feature(concat_idents)]
276277
#![feature(const_mut_refs)]
277278
#![feature(const_trait_impl)]
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+
}

0 commit comments

Comments
 (0)