Skip to content

Commit 0df1ddc

Browse files
committed
Auto merge of #99556 - davidtwco:collapse-debuginfo, r=wesleywiser
ssa: implement `#[collapse_debuginfo]` cc #39153 rust-lang/compiler-team#386 Debuginfo line information for macro invocations are collapsed by default - line information are replaced by the line of the outermost expansion site. Using `-Zdebug-macros` disables this behaviour. When the `collapse_debuginfo` feature is enabled, the default behaviour is reversed so that debuginfo is not collapsed by default. In addition, the `#[collapse_debuginfo]` attribute is available and can be applied to macro definitions which will then have their line information collapsed. r? rust-lang/wg-debugging
2 parents 089584d + 38958aa commit 0df1ddc

File tree

21 files changed

+700
-36
lines changed

21 files changed

+700
-36
lines changed

compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ impl DebugContext {
6868
) -> (Lrc<SourceFile>, u64, u64) {
6969
// Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131
7070
// In order to have a good line stepping behavior in debugger, we overwrite debug
71-
// locations of macro expansions with that of the outermost expansion site
72-
// (unless the crate is being compiled with `-Z debug-macros`).
73-
let span = if !span.from_expansion() || tcx.sess.opts.unstable_opts.debug_macros {
71+
// locations of macro expansions with that of the outermost expansion site (when the macro is
72+
// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided).
73+
let span = if tcx.should_collapse_debuginfo(span) {
7474
span
7575
} else {
7676
// Walk up the macro expansion chain until we reach a non-expanded span.

compiler/rustc_codegen_ssa/src/mir/debuginfo.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc_index::vec::IndexVec;
33
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
44
use rustc_middle::mir;
55
use rustc_middle::ty;
6-
use rustc_middle::ty::layout::LayoutOf;
6+
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
77
use rustc_session::config::DebugInfo;
88
use rustc_span::symbol::{kw, Symbol};
99
use rustc_span::{BytePos, Span};
@@ -93,15 +93,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
9393
}
9494

9595
/// In order to have a good line stepping behavior in debugger, we overwrite debug
96-
/// locations of macro expansions with that of the outermost expansion site
97-
/// (unless the crate is being compiled with `-Z debug-macros`).
96+
/// locations of macro expansions with that of the outermost expansion site (when the macro is
97+
/// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided).
9898
fn adjust_span_for_debugging(&self, mut span: Span) -> Span {
9999
// Bail out if debug info emission is not enabled.
100100
if self.debug_context.is_none() {
101101
return span;
102102
}
103103

104-
if span.from_expansion() && !self.cx.sess().opts.unstable_opts.debug_macros {
104+
if self.cx.tcx().should_collapse_debuginfo(span) {
105105
// Walk up the macro expansion chain until we reach a non-expanded span.
106106
// We also stop at the function body level because no line stepping can occur
107107
// at the level above that.

compiler/rustc_error_messages/locales/en-US/passes.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,6 @@ passes_rustc_lint_opt_deny_field_access = `#[rustc_lint_opt_deny_field_access]`
265265
266266
passes_link_ordinal = attribute should be applied to a foreign function or static
267267
.label = not a foreign function or static
268+
269+
passes_collapse_debuginfo = `collapse_debuginfo` attribute should be applied to macro definitions
270+
.label = not a macro definition

compiler/rustc_expand/src/base.rs

+23-16
Original file line numberDiff line numberDiff line change
@@ -693,10 +693,6 @@ pub struct SyntaxExtension {
693693
pub span: Span,
694694
/// List of unstable features that are treated as stable inside this macro.
695695
pub allow_internal_unstable: Option<Lrc<[Symbol]>>,
696-
/// Suppresses the `unsafe_code` lint for code produced by this macro.
697-
pub allow_internal_unsafe: bool,
698-
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
699-
pub local_inner_macros: bool,
700696
/// The macro's stability info.
701697
pub stability: Option<Stability>,
702698
/// The macro's deprecation info.
@@ -708,6 +704,13 @@ pub struct SyntaxExtension {
708704
/// Built-in macros have a couple of special properties like availability
709705
/// in `#[no_implicit_prelude]` modules, so we have to keep this flag.
710706
pub builtin_name: Option<Symbol>,
707+
/// Suppresses the `unsafe_code` lint for code produced by this macro.
708+
pub allow_internal_unsafe: bool,
709+
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
710+
pub local_inner_macros: bool,
711+
/// Should debuginfo for the macro be collapsed to the outermost expansion site (in other
712+
/// words, was the macro definition annotated with `#[collapse_debuginfo]`)?
713+
pub collapse_debuginfo: bool,
711714
}
712715

713716
impl SyntaxExtension {
@@ -729,14 +732,15 @@ impl SyntaxExtension {
729732
SyntaxExtension {
730733
span: DUMMY_SP,
731734
allow_internal_unstable: None,
732-
allow_internal_unsafe: false,
733-
local_inner_macros: false,
734735
stability: None,
735736
deprecation: None,
736737
helper_attrs: Vec::new(),
737738
edition,
738739
builtin_name: None,
739740
kind,
741+
allow_internal_unsafe: false,
742+
local_inner_macros: false,
743+
collapse_debuginfo: false,
740744
}
741745
}
742746

@@ -754,12 +758,13 @@ impl SyntaxExtension {
754758
let allow_internal_unstable =
755759
attr::allow_internal_unstable(sess, &attrs).collect::<Vec<Symbol>>();
756760

757-
let mut local_inner_macros = false;
758-
if let Some(macro_export) = sess.find_by_name(attrs, sym::macro_export) {
759-
if let Some(l) = macro_export.meta_item_list() {
760-
local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros);
761-
}
762-
}
761+
let allow_internal_unsafe = sess.contains_name(attrs, sym::allow_internal_unsafe);
762+
let local_inner_macros = sess
763+
.find_by_name(attrs, sym::macro_export)
764+
.and_then(|macro_export| macro_export.meta_item_list())
765+
.map_or(false, |l| attr::list_contains_name(&l, sym::local_inner_macros));
766+
let collapse_debuginfo = sess.contains_name(attrs, sym::collapse_debuginfo);
767+
tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
763768

764769
let (builtin_name, helper_attrs) = sess
765770
.find_by_name(attrs, sym::rustc_builtin_macro)
@@ -801,13 +806,14 @@ impl SyntaxExtension {
801806
span,
802807
allow_internal_unstable: (!allow_internal_unstable.is_empty())
803808
.then(|| allow_internal_unstable.into()),
804-
allow_internal_unsafe: sess.contains_name(attrs, sym::allow_internal_unsafe),
805-
local_inner_macros,
806809
stability: stability.map(|(s, _)| s),
807810
deprecation: attr::find_deprecation(&sess, attrs).map(|(d, _)| d),
808811
helper_attrs,
809812
edition,
810813
builtin_name,
814+
allow_internal_unsafe,
815+
local_inner_macros,
816+
collapse_debuginfo,
811817
}
812818
}
813819

@@ -852,11 +858,12 @@ impl SyntaxExtension {
852858
call_site,
853859
self.span,
854860
self.allow_internal_unstable.clone(),
855-
self.allow_internal_unsafe,
856-
self.local_inner_macros,
857861
self.edition,
858862
macro_def_id,
859863
parent_module,
864+
self.allow_internal_unsafe,
865+
self.local_inner_macros,
866+
self.collapse_debuginfo,
860867
)
861868
}
862869
}

compiler/rustc_feature/src/active.rs

+2
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,8 @@ declare_features! (
338338
(active, closure_track_caller, "1.57.0", Some(87417), None),
339339
/// Allows to use the `#[cmse_nonsecure_entry]` attribute.
340340
(active, cmse_nonsecure_entry, "1.48.0", Some(75835), None),
341+
/// Allows use of the `#[collapse_debuginfo]` attribute.
342+
(active, collapse_debuginfo, "CURRENT_RUSTC_VERSION", Some(100758), None),
341343
/// Allows `async {}` expressions in const contexts.
342344
(active, const_async_blocks, "1.53.0", Some(85368), None),
343345
// Allows limiting the evaluation steps of const expressions

compiler/rustc_feature/src/builtin_attrs.rs

+6
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
478478
experimental!(deprecated_safe),
479479
),
480480

481+
// `#[collapse_debuginfo]`
482+
gated!(
483+
collapse_debuginfo, Normal, template!(Word), WarnFollowing,
484+
experimental!(collapse_debuginfo)
485+
),
486+
481487
// ==========================================================================
482488
// Internal attributes: Stability, deprecation, and unsafe:
483489
// ==========================================================================

compiler/rustc_middle/src/ty/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1590,7 +1590,7 @@ impl<'tcx> TyCtxt<'tcx> {
15901590
})
15911591
}
15921592

1593-
// Returns the `DefId` and the `BoundRegionKind` corresponding to the given region.
1593+
/// Returns the `DefId` and the `BoundRegionKind` corresponding to the given region.
15941594
pub fn is_suitable_region(self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
15951595
let (suitable_region_binding_scope, bound_region) = match *region {
15961596
ty::ReFree(ref free_region) => {

compiler/rustc_middle/src/ty/mod.rs

+17
Original file line numberDiff line numberDiff line change
@@ -2470,6 +2470,23 @@ impl<'tcx> TyCtxt<'tcx> {
24702470
(ident, scope)
24712471
}
24722472

2473+
/// Returns `true` if the debuginfo for `span` should be collapsed to the outermost expansion
2474+
/// site. Only applies when `Span` is the result of macro expansion.
2475+
///
2476+
/// - If the `collapse_debuginfo` feature is enabled then debuginfo is not collapsed by default
2477+
/// and only when a macro definition is annotated with `#[collapse_debuginfo]`.
2478+
/// - If `collapse_debuginfo` is not enabled, then debuginfo is collapsed by default.
2479+
///
2480+
/// When `-Zdebug-macros` is provided then debuginfo will never be collapsed.
2481+
pub fn should_collapse_debuginfo(self, span: Span) -> bool {
2482+
!self.sess.opts.unstable_opts.debug_macros
2483+
&& if self.features().collapse_debuginfo {
2484+
span.in_macro_expansion_with_collapse_debuginfo()
2485+
} else {
2486+
span.from_expansion()
2487+
}
2488+
}
2489+
24732490
pub fn is_object_safe(self, key: DefId) -> bool {
24742491
self.object_safety_violations(key).is_empty()
24752492
}

compiler/rustc_passes/src/check_attr.rs

+14
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ impl CheckAttrVisitor<'_> {
131131
| sym::rustc_if_this_changed
132132
| sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr),
133133
sym::cmse_nonsecure_entry => self.check_cmse_nonsecure_entry(attr, span, target),
134+
sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target),
134135
sym::const_trait => self.check_const_trait(attr, span, target),
135136
sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
136137
sym::must_use => self.check_must_use(hir_id, &attr, span, target),
@@ -431,6 +432,19 @@ impl CheckAttrVisitor<'_> {
431432
}
432433
}
433434

435+
/// Checks if `#[collapse_debuginfo]` is applied to a macro.
436+
fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) -> bool {
437+
match target {
438+
Target::MacroDef => true,
439+
_ => {
440+
self.tcx
441+
.sess
442+
.emit_err(errors::CollapseDebuginfo { attr_span: attr.span, defn_span: span });
443+
false
444+
}
445+
}
446+
}
447+
434448
/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
435449
fn check_track_caller(
436450
&self,

compiler/rustc_passes/src/errors.rs

+9
Original file line numberDiff line numberDiff line change
@@ -649,3 +649,12 @@ pub struct RustcLintOptDenyFieldAccess {
649649
#[label]
650650
pub span: Span,
651651
}
652+
653+
#[derive(SessionDiagnostic)]
654+
#[diag(passes::collapse_debuginfo)]
655+
pub struct CollapseDebuginfo {
656+
#[primary_span]
657+
pub attr_span: Span,
658+
#[label]
659+
pub defn_span: Span,
660+
}

compiler/rustc_span/src/hygiene.rs

+16-12
Original file line numberDiff line numberDiff line change
@@ -944,19 +944,20 @@ pub struct ExpnData {
944944
/// internally without forcing the whole crate to opt-in
945945
/// to them.
946946
pub allow_internal_unstable: Option<Lrc<[Symbol]>>,
947-
/// Whether the macro is allowed to use `unsafe` internally
948-
/// even if the user crate has `#![forbid(unsafe_code)]`.
949-
pub allow_internal_unsafe: bool,
950-
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`)
951-
/// for a given macro.
952-
pub local_inner_macros: bool,
953947
/// Edition of the crate in which the macro is defined.
954948
pub edition: Edition,
955949
/// The `DefId` of the macro being invoked,
956950
/// if this `ExpnData` corresponds to a macro invocation
957951
pub macro_def_id: Option<DefId>,
958952
/// The normal module (`mod`) in which the expanded macro was defined.
959953
pub parent_module: Option<DefId>,
954+
/// Suppresses the `unsafe_code` lint for code produced by this macro.
955+
pub allow_internal_unsafe: bool,
956+
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
957+
pub local_inner_macros: bool,
958+
/// Should debuginfo for the macro be collapsed to the outermost expansion site (in other
959+
/// words, was the macro definition annotated with `#[collapse_debuginfo]`)?
960+
pub collapse_debuginfo: bool,
960961
}
961962

962963
impl !PartialEq for ExpnData {}
@@ -969,24 +970,26 @@ impl ExpnData {
969970
call_site: Span,
970971
def_site: Span,
971972
allow_internal_unstable: Option<Lrc<[Symbol]>>,
972-
allow_internal_unsafe: bool,
973-
local_inner_macros: bool,
974973
edition: Edition,
975974
macro_def_id: Option<DefId>,
976975
parent_module: Option<DefId>,
976+
allow_internal_unsafe: bool,
977+
local_inner_macros: bool,
978+
collapse_debuginfo: bool,
977979
) -> ExpnData {
978980
ExpnData {
979981
kind,
980982
parent,
981983
call_site,
982984
def_site,
983985
allow_internal_unstable,
984-
allow_internal_unsafe,
985-
local_inner_macros,
986986
edition,
987987
macro_def_id,
988988
parent_module,
989989
disambiguator: 0,
990+
allow_internal_unsafe,
991+
local_inner_macros,
992+
collapse_debuginfo,
990993
}
991994
}
992995

@@ -1004,12 +1007,13 @@ impl ExpnData {
10041007
call_site,
10051008
def_site: DUMMY_SP,
10061009
allow_internal_unstable: None,
1007-
allow_internal_unsafe: false,
1008-
local_inner_macros: false,
10091010
edition,
10101011
macro_def_id,
10111012
parent_module,
10121013
disambiguator: 0,
1014+
allow_internal_unsafe: false,
1015+
local_inner_macros: false,
1016+
collapse_debuginfo: false,
10131017
}
10141018
}
10151019

compiler/rustc_span/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,13 @@ impl Span {
564564
self.ctxt() != SyntaxContext::root()
565565
}
566566

567+
/// Returns `true` if `span` originates in a macro's expansion where debuginfo should be
568+
/// collapsed.
569+
pub fn in_macro_expansion_with_collapse_debuginfo(self) -> bool {
570+
let outer_expn = self.ctxt().outer_expn_data();
571+
matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo
572+
}
573+
567574
/// Returns `true` if `span` originates in a derive-macro's expansion.
568575
pub fn in_derive_expansion(self) -> bool {
569576
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ symbols! {
487487
cmse_nonsecure_entry,
488488
coerce_unsized,
489489
cold,
490+
collapse_debuginfo,
490491
column,
491492
column_macro,
492493
compare_and_swap,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// ignore-lldb
2+
#![feature(collapse_debuginfo)]
3+
4+
// Test that line numbers are not replaced with those of the outermost expansion site when the
5+
// `collapse_debuginfo` is active, `-Zdebug-macros` is provided and `#[collapse_debuginfo]` not
6+
// being used.
7+
8+
// compile-flags:-g -Zdebug-macros
9+
10+
// === GDB TESTS ===================================================================================
11+
12+
// gdb-command:run
13+
// gdb-command:next
14+
// gdb-command:frame
15+
// gdb-check:[...]#loc1[...]
16+
// gdb-command:next
17+
// gdb-command:frame
18+
// gdb-check:[...]#loc2[...]
19+
// gdb-command:next
20+
// gdb-command:frame
21+
// gdb-check:[...]#loc3[...]
22+
// gdb-command:next
23+
// gdb-command:frame
24+
// gdb-check:[...]#loc4[...]
25+
// gdb-command:continue
26+
27+
fn one() {
28+
println!("one");
29+
}
30+
fn two() {
31+
println!("two");
32+
}
33+
fn three() {
34+
println!("three");
35+
}
36+
fn four() {
37+
println!("four");
38+
}
39+
40+
macro_rules! outer {
41+
($b:block) => {
42+
one(); // #loc1
43+
inner!();
44+
$b
45+
};
46+
}
47+
48+
macro_rules! inner {
49+
() => {
50+
two(); // #loc2
51+
};
52+
}
53+
54+
fn main() {
55+
let ret = 0; // #break
56+
outer!({
57+
three(); // #loc3
58+
four(); // #loc4
59+
});
60+
std::process::exit(ret);
61+
}

0 commit comments

Comments
 (0)