Skip to content

Commit

Permalink
Auto merge of #99556 - davidtwco:collapse-debuginfo, r=wesleywiser
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Sep 13, 2022
2 parents 089584d + 38958aa commit 0df1ddc
Show file tree
Hide file tree
Showing 21 changed files with 700 additions and 36 deletions.
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ impl DebugContext {
) -> (Lrc<SourceFile>, u64, u64) {
// Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131
// 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
// (unless the crate is being compiled with `-Z debug-macros`).
let span = if !span.from_expansion() || tcx.sess.opts.unstable_opts.debug_macros {
// 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.
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rustc_index::vec::IndexVec;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir;
use rustc_middle::ty;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_session::config::DebugInfo;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{BytePos, Span};
Expand Down Expand Up @@ -93,15 +93,15 @@ 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
/// (unless the crate is being compiled with `-Z debug-macros`).
/// 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 {
// Bail out if debug info emission is not enabled.
if self.debug_context.is_none() {
return span;
}

if span.from_expansion() && !self.cx.sess().opts.unstable_opts.debug_macros {
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.
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/passes.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,6 @@ passes_rustc_lint_opt_deny_field_access = `#[rustc_lint_opt_deny_field_access]`
passes_link_ordinal = attribute should be applied to a foreign function or static
.label = not a foreign function or static
passes_collapse_debuginfo = `collapse_debuginfo` attribute should be applied to macro definitions
.label = not a macro definition
39 changes: 23 additions & 16 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,10 +693,6 @@ pub struct SyntaxExtension {
pub span: Span,
/// List of unstable features that are treated as stable inside this macro.
pub allow_internal_unstable: Option<Lrc<[Symbol]>>,
/// Suppresses the `unsafe_code` lint for code produced by this macro.
pub allow_internal_unsafe: bool,
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
pub local_inner_macros: bool,
/// The macro's stability info.
pub stability: Option<Stability>,
/// The macro's deprecation info.
Expand All @@ -708,6 +704,13 @@ pub struct SyntaxExtension {
/// Built-in macros have a couple of special properties like availability
/// in `#[no_implicit_prelude]` modules, so we have to keep this flag.
pub builtin_name: Option<Symbol>,
/// Suppresses the `unsafe_code` lint for code produced by this macro.
pub allow_internal_unsafe: bool,
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
pub local_inner_macros: bool,
/// Should debuginfo for the macro be collapsed to the outermost expansion site (in other
/// words, was the macro definition annotated with `#[collapse_debuginfo]`)?
pub collapse_debuginfo: bool,
}

impl SyntaxExtension {
Expand All @@ -729,14 +732,15 @@ impl SyntaxExtension {
SyntaxExtension {
span: DUMMY_SP,
allow_internal_unstable: None,
allow_internal_unsafe: false,
local_inner_macros: false,
stability: None,
deprecation: None,
helper_attrs: Vec::new(),
edition,
builtin_name: None,
kind,
allow_internal_unsafe: false,
local_inner_macros: false,
collapse_debuginfo: false,
}
}

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

let mut local_inner_macros = false;
if let Some(macro_export) = sess.find_by_name(attrs, sym::macro_export) {
if let Some(l) = macro_export.meta_item_list() {
local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros);
}
}
let allow_internal_unsafe = sess.contains_name(attrs, sym::allow_internal_unsafe);
let local_inner_macros = sess
.find_by_name(attrs, sym::macro_export)
.and_then(|macro_export| macro_export.meta_item_list())
.map_or(false, |l| attr::list_contains_name(&l, sym::local_inner_macros));
let collapse_debuginfo = sess.contains_name(attrs, sym::collapse_debuginfo);
tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);

let (builtin_name, helper_attrs) = sess
.find_by_name(attrs, sym::rustc_builtin_macro)
Expand Down Expand Up @@ -801,13 +806,14 @@ impl SyntaxExtension {
span,
allow_internal_unstable: (!allow_internal_unstable.is_empty())
.then(|| allow_internal_unstable.into()),
allow_internal_unsafe: sess.contains_name(attrs, sym::allow_internal_unsafe),
local_inner_macros,
stability: stability.map(|(s, _)| s),
deprecation: attr::find_deprecation(&sess, attrs).map(|(d, _)| d),
helper_attrs,
edition,
builtin_name,
allow_internal_unsafe,
local_inner_macros,
collapse_debuginfo,
}
}

Expand Down Expand Up @@ -852,11 +858,12 @@ impl SyntaxExtension {
call_site,
self.span,
self.allow_internal_unstable.clone(),
self.allow_internal_unsafe,
self.local_inner_macros,
self.edition,
macro_def_id,
parent_module,
self.allow_internal_unsafe,
self.local_inner_macros,
self.collapse_debuginfo,
)
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ declare_features! (
(active, closure_track_caller, "1.57.0", Some(87417), None),
/// Allows to use the `#[cmse_nonsecure_entry]` attribute.
(active, cmse_nonsecure_entry, "1.48.0", Some(75835), None),
/// Allows use of the `#[collapse_debuginfo]` attribute.
(active, collapse_debuginfo, "CURRENT_RUSTC_VERSION", Some(100758), None),
/// Allows `async {}` expressions in const contexts.
(active, const_async_blocks, "1.53.0", Some(85368), None),
// Allows limiting the evaluation steps of const expressions
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
experimental!(deprecated_safe),
),

// `#[collapse_debuginfo]`
gated!(
collapse_debuginfo, Normal, template!(Word), WarnFollowing,
experimental!(collapse_debuginfo)
),

// ==========================================================================
// Internal attributes: Stability, deprecation, and unsafe:
// ==========================================================================
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1590,7 +1590,7 @@ impl<'tcx> TyCtxt<'tcx> {
})
}

// Returns the `DefId` and the `BoundRegionKind` corresponding to the given region.
/// Returns the `DefId` and the `BoundRegionKind` corresponding to the given region.
pub fn is_suitable_region(self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
let (suitable_region_binding_scope, bound_region) = match *region {
ty::ReFree(ref free_region) => {
Expand Down
17 changes: 17 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2470,6 +2470,23 @@ 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 is_object_safe(self, key: DefId) -> bool {
self.object_safety_violations(key).is_empty()
}
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ impl CheckAttrVisitor<'_> {
| sym::rustc_if_this_changed
| sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr),
sym::cmse_nonsecure_entry => self.check_cmse_nonsecure_entry(attr, span, target),
sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target),
sym::const_trait => self.check_const_trait(attr, span, target),
sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
sym::must_use => self.check_must_use(hir_id, &attr, span, target),
Expand Down Expand Up @@ -431,6 +432,19 @@ impl CheckAttrVisitor<'_> {
}
}

/// Checks if `#[collapse_debuginfo]` is applied to a macro.
fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) -> bool {
match target {
Target::MacroDef => true,
_ => {
self.tcx
.sess
.emit_err(errors::CollapseDebuginfo { attr_span: attr.span, defn_span: span });
false
}
}
}

/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
fn check_track_caller(
&self,
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -649,3 +649,12 @@ pub struct RustcLintOptDenyFieldAccess {
#[label]
pub span: Span,
}

#[derive(SessionDiagnostic)]
#[diag(passes::collapse_debuginfo)]
pub struct CollapseDebuginfo {
#[primary_span]
pub attr_span: Span,
#[label]
pub defn_span: Span,
}
28 changes: 16 additions & 12 deletions compiler/rustc_span/src/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -944,19 +944,20 @@ pub struct ExpnData {
/// internally without forcing the whole crate to opt-in
/// to them.
pub allow_internal_unstable: Option<Lrc<[Symbol]>>,
/// Whether the macro is allowed to use `unsafe` internally
/// even if the user crate has `#![forbid(unsafe_code)]`.
pub allow_internal_unsafe: bool,
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`)
/// for a given macro.
pub local_inner_macros: bool,
/// Edition of the crate in which the macro is defined.
pub edition: Edition,
/// The `DefId` of the macro being invoked,
/// if this `ExpnData` corresponds to a macro invocation
pub macro_def_id: Option<DefId>,
/// The normal module (`mod`) in which the expanded macro was defined.
pub parent_module: Option<DefId>,
/// Suppresses the `unsafe_code` lint for code produced by this macro.
pub allow_internal_unsafe: bool,
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
pub local_inner_macros: bool,
/// Should debuginfo for the macro be collapsed to the outermost expansion site (in other
/// words, was the macro definition annotated with `#[collapse_debuginfo]`)?
pub collapse_debuginfo: bool,
}

impl !PartialEq for ExpnData {}
Expand All @@ -969,24 +970,26 @@ impl ExpnData {
call_site: Span,
def_site: Span,
allow_internal_unstable: Option<Lrc<[Symbol]>>,
allow_internal_unsafe: bool,
local_inner_macros: bool,
edition: Edition,
macro_def_id: Option<DefId>,
parent_module: Option<DefId>,
allow_internal_unsafe: bool,
local_inner_macros: bool,
collapse_debuginfo: bool,
) -> ExpnData {
ExpnData {
kind,
parent,
call_site,
def_site,
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
edition,
macro_def_id,
parent_module,
disambiguator: 0,
allow_internal_unsafe,
local_inner_macros,
collapse_debuginfo,
}
}

Expand All @@ -1004,12 +1007,13 @@ impl ExpnData {
call_site,
def_site: DUMMY_SP,
allow_internal_unstable: None,
allow_internal_unsafe: false,
local_inner_macros: false,
edition,
macro_def_id,
parent_module,
disambiguator: 0,
allow_internal_unsafe: false,
local_inner_macros: false,
collapse_debuginfo: false,
}
}

Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,13 @@ 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
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ symbols! {
cmse_nonsecure_entry,
coerce_unsized,
cold,
collapse_debuginfo,
column,
column_macro,
compare_and_swap,
Expand Down
61 changes: 61 additions & 0 deletions src/test/debuginfo/collapse-debuginfo-no-attr-flag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// ignore-lldb
#![feature(collapse_debuginfo)]

// Test that line numbers are not replaced with those of the outermost expansion site when the
// `collapse_debuginfo` is active, `-Zdebug-macros` is provided and `#[collapse_debuginfo]` not
// being used.

// compile-flags:-g -Zdebug-macros

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

// gdb-command:run
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc1[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc2[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc3[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc4[...]
// gdb-command:continue

fn one() {
println!("one");
}
fn two() {
println!("two");
}
fn three() {
println!("three");
}
fn four() {
println!("four");
}

macro_rules! outer {
($b:block) => {
one(); // #loc1
inner!();
$b
};
}

macro_rules! inner {
() => {
two(); // #loc2
};
}

fn main() {
let ret = 0; // #break
outer!({
three(); // #loc3
four(); // #loc4
});
std::process::exit(ret);
}
Loading

0 comments on commit 0df1ddc

Please sign in to comment.