Skip to content

debuginfo: Stabilize -Z debug-macros, -Z collapse-macro-debuginfo and #[collapse_debuginfo] #120845

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

Merged
merged 2 commits into from
Apr 26, 2024
Merged
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
9 changes: 3 additions & 6 deletions compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ use cranelift_codegen::binemit::CodeOffset;
use cranelift_codegen::MachSrcLoc;
use gimli::write::{AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable};
use rustc_span::{
FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm,
hygiene, FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm,
};

use crate::debuginfo::emit::address_for_func;
@@ -63,11 +63,8 @@ impl DebugContext {
function_span: Span,
span: Span,
) -> (FileId, 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 (when the macro is
// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided).
let span = tcx.collapsed_debuginfo(span, function_span);
// Match behavior of `FunctionCx::adjusted_span_and_dbg_scope`.
let span = hygiene::walk_chain_collapsed(span, function_span);
match tcx.sess.source_map().lookup_line(span.lo()) {
Ok(SourceFileAndLine { sf: file, line }) => {
let file_id = self.add_source_file(&file);
22 changes: 3 additions & 19 deletions compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
Original file line number Diff line number Diff line change
@@ -4,13 +4,12 @@ use rustc_index::IndexVec;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir;
use rustc_middle::ty;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::Instance;
use rustc_middle::ty::Ty;
use rustc_session::config::DebugInfo;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{BytePos, Span};
use rustc_span::{hygiene, BytePos, Span};
use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx};

use super::operand::{OperandRef, OperandValue};
@@ -220,26 +219,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
&self,
source_info: mir::SourceInfo,
) -> Option<(Bx::DIScope, Option<Bx::DILocation>, Span)> {
let span = self.adjust_span_for_debugging(source_info.span);
let scope = &self.debug_context.as_ref()?.scopes[source_info.scope];
let span = hygiene::walk_chain_collapsed(source_info.span, self.mir.span);
Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span))
}

/// 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, span: Span) -> Span {
// Bail out if debug info emission is not enabled.
if self.debug_context.is_none() {
return 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(
operand: OperandRef<'tcx, Bx::Value>,
name: Option<String>,
75 changes: 35 additions & 40 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
@@ -789,55 +789,50 @@ impl SyntaxExtension {
}
}

fn collapse_debuginfo_by_name(sess: &Session, attr: &Attribute) -> CollapseMacroDebuginfo {
use crate::errors::CollapseMacroDebuginfoIllegal;
// #[collapse_debuginfo] without enum value (#[collapse_debuginfo(no/external/yes)])
// considered as `yes`
attr.meta_item_list().map_or(CollapseMacroDebuginfo::Yes, |l| {
let [NestedMetaItem::MetaItem(item)] = &l[..] else {
sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: attr.span });
return CollapseMacroDebuginfo::Unspecified;
};
if !item.is_word() {
sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: item.span });
CollapseMacroDebuginfo::Unspecified
} else {
match item.name_or_empty() {
sym::no => CollapseMacroDebuginfo::No,
sym::external => CollapseMacroDebuginfo::External,
sym::yes => CollapseMacroDebuginfo::Yes,
_ => {
sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: item.span });
CollapseMacroDebuginfo::Unspecified
}
}
}
})
fn collapse_debuginfo_by_name(attr: &Attribute) -> Result<CollapseMacroDebuginfo, Span> {
let list = attr.meta_item_list();
let Some([NestedMetaItem::MetaItem(item)]) = list.as_deref() else {
return Err(attr.span);
};
if !item.is_word() {
return Err(item.span);
}

match item.name_or_empty() {
sym::no => Ok(CollapseMacroDebuginfo::No),
sym::external => Ok(CollapseMacroDebuginfo::External),
sym::yes => Ok(CollapseMacroDebuginfo::Yes),
_ => Err(item.path.span),
}
}

/// if-ext - if macro from different crate (related to callsite code)
/// | cmd \ attr | no | (unspecified) | external | yes |
/// | no | no | no | no | no |
/// | (unspecified) | no | no | if-ext | yes |
/// | (unspecified) | no | if-ext | if-ext | yes |
/// | external | no | if-ext | if-ext | yes |
/// | yes | yes | yes | yes | yes |
fn get_collapse_debuginfo(sess: &Session, attrs: &[ast::Attribute], is_local: bool) -> bool {
let mut collapse_debuginfo_attr = attr::find_by_name(attrs, sym::collapse_debuginfo)
.map(|v| Self::collapse_debuginfo_by_name(sess, v))
.unwrap_or(CollapseMacroDebuginfo::Unspecified);
if collapse_debuginfo_attr == CollapseMacroDebuginfo::Unspecified
&& attr::contains_name(attrs, sym::rustc_builtin_macro)
{
collapse_debuginfo_attr = CollapseMacroDebuginfo::Yes;
}

let flag = sess.opts.unstable_opts.collapse_macro_debuginfo;
let attr = collapse_debuginfo_attr;
let ext = !is_local;
fn get_collapse_debuginfo(sess: &Session, attrs: &[ast::Attribute], ext: bool) -> bool {
let flag = sess.opts.cg.collapse_macro_debuginfo;
let attr = attr::find_by_name(attrs, sym::collapse_debuginfo)
.and_then(|attr| {
Self::collapse_debuginfo_by_name(attr)
.map_err(|span| {
sess.dcx().emit_err(errors::CollapseMacroDebuginfoIllegal { span })
})
.ok()
})
.unwrap_or_else(|| {
if attr::contains_name(attrs, sym::rustc_builtin_macro) {
CollapseMacroDebuginfo::Yes
} else {
CollapseMacroDebuginfo::Unspecified
}
});
#[rustfmt::skip]
let collapse_table = [
[false, false, false, false],
[false, false, ext, true],
[false, ext, ext, true],
[false, ext, ext, true],
[true, true, true, true],
];
@@ -864,7 +859,7 @@ impl SyntaxExtension {
let local_inner_macros = attr::find_by_name(attrs, sym::macro_export)
.and_then(|macro_export| macro_export.meta_item_list())
.is_some_and(|l| attr::list_contains_name(&l, sym::local_inner_macros));
let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, is_local);
let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, !is_local);
tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);

let (builtin_name, helper_attrs) = attr::find_by_name(attrs, sym::rustc_builtin_macro)
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
@@ -98,6 +98,8 @@ declare_features! (
(accepted, closure_to_fn_coercion, "1.19.0", Some(39817)),
/// Allows using the CMPXCHG16B target feature.
(accepted, cmpxchg16b_target_feature, "1.69.0", Some(44839)),
/// Allows use of the `#[collapse_debuginfo]` attribute.
(accepted, collapse_debuginfo, "CURRENT_RUSTC_VERSION", Some(100758)),
/// Allows usage of the `compile_error!` macro.
(accepted, compile_error, "1.20.0", Some(40872)),
/// Allows `impl Trait` in function return types.
9 changes: 3 additions & 6 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
@@ -450,6 +450,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
template!(List: r#"natvis_file = "...", gdb_script_file = "...""#),
DuplicatesOk, EncodeCrossCrate::No
),
ungated!(collapse_debuginfo, Normal, template!(List: "no|external|yes"), ErrorFollowing,
EncodeCrossCrate::Yes
),

// ==========================================================================
// Unstable attributes:
@@ -516,12 +519,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
EncodeCrossCrate::Yes, experimental!(deprecated_safe),
),

// `#[collapse_debuginfo]`
gated!(
collapse_debuginfo, Normal, template!(Word, List: "no|external|yes"), ErrorFollowing,
EncodeCrossCrate::No, experimental!(collapse_debuginfo)
),

// RFC 2397
gated!(
do_not_recommend, Normal, template!(Word), WarnFollowing,
2 changes: 0 additions & 2 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
@@ -395,8 +395,6 @@ declare_features! (
(unstable, closure_track_caller, "1.57.0", Some(87417)),
/// Allows to use the `#[cmse_nonsecure_entry]` attribute.
(unstable, cmse_nonsecure_entry, "1.48.0", Some(75835)),
/// Allows use of the `#[collapse_debuginfo]` attribute.
(unstable, collapse_debuginfo, "1.65.0", Some(100758)),
/// Allows `async {}` expressions in const contexts.
(unstable, const_async_blocks, "1.53.0", Some(85368)),
/// Allows `const || {}` closures in const contexts.
3 changes: 1 addition & 2 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
@@ -600,6 +600,7 @@ fn test_codegen_options_tracking_hash() {
// Make sure that changing a [TRACKED] option changes the hash.
// tidy-alphabetical-start
tracked!(code_model, Some(CodeModel::Large));
tracked!(collapse_macro_debuginfo, CollapseMacroDebuginfo::Yes);
tracked!(control_flow_guard, CFGuard::Checks);
tracked!(debug_assertions, Some(true));
tracked!(debuginfo, DebugInfo::Limited);
@@ -760,12 +761,10 @@ fn test_unstable_options_tracking_hash() {
})
);
tracked!(codegen_backend, Some("abc".to_string()));
tracked!(collapse_macro_debuginfo, CollapseMacroDebuginfo::Yes);
tracked!(coverage_options, CoverageOptions { branch: true, mcdc: true });
tracked!(crate_attr, vec!["abc".to_string()]);
tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
tracked!(debug_info_for_profiling, true);
tracked!(debug_macros, true);
tracked!(default_hidden_visibility, Some(true));
tracked!(dep_info_omit_d_target, true);
tracked!(direct_access_external_data, Some(true));
18 changes: 1 addition & 17 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -54,7 +54,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::{hygiene, ExpnId, ExpnKind, Span};
use rustc_span::{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};
@@ -2013,22 +2013,6 @@ impl<'tcx> TyCtxt<'tcx> {
(ident, scope)
}

/// 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 (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.
pub fn collapsed_debuginfo(self, span: Span, upto: Span) -> Span {
if self.sess.opts.unstable_opts.debug_macros || !span.from_expansion() {
return span;
}
hygiene::walk_chain_collapsed(span, upto, self.features().collapse_debuginfo)
}

#[inline]
pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
matches!(
22 changes: 15 additions & 7 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
@@ -1358,10 +1358,20 @@ mod parse {
slot: &mut CollapseMacroDebuginfo,
v: Option<&str>,
) -> bool {
if v.is_some() {
let mut bool_arg = None;
if parse_opt_bool(&mut bool_arg, v) {
*slot = if bool_arg.unwrap() {
CollapseMacroDebuginfo::Yes
} else {
CollapseMacroDebuginfo::No
};
return true;
}
}

*slot = match v {
Some("no") => CollapseMacroDebuginfo::No,
Some("external") => CollapseMacroDebuginfo::External,
Some("yes") => CollapseMacroDebuginfo::Yes,
_ => return false,
};
true
@@ -1460,6 +1470,9 @@ options! {
"choose the code model to use (`rustc --print code-models` for details)"),
codegen_units: Option<usize> = (None, parse_opt_number, [UNTRACKED],
"divide crate into N units to optimize in parallel"),
collapse_macro_debuginfo: CollapseMacroDebuginfo = (CollapseMacroDebuginfo::Unspecified,
parse_collapse_macro_debuginfo, [TRACKED],
"set option to collapse debuginfo for macros"),
control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED],
"use Windows Control Flow Guard (default: no)"),
debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
@@ -1607,9 +1620,6 @@ options! {
"show all expected values in check-cfg diagnostics (default: no)"),
codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
"the backend to use"),
collapse_macro_debuginfo: CollapseMacroDebuginfo = (CollapseMacroDebuginfo::Unspecified,
parse_collapse_macro_debuginfo, [TRACKED],
"set option to collapse debuginfo for macros"),
combine_cgu: bool = (false, parse_bool, [TRACKED],
"combine CGUs into a single one"),
coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED],
@@ -1620,8 +1630,6 @@ options! {
"threshold to allow cross crate inlining of functions"),
debug_info_for_profiling: bool = (false, parse_bool, [TRACKED],
"emit discriminators and other data necessary for AutoFDO"),
debug_macros: bool = (false, parse_bool, [TRACKED],
"emit line numbers debug info inside macros (default: no)"),
debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED],
"compress debug info sections (none, zlib, zstd, default: none)"),
deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED],
38 changes: 15 additions & 23 deletions compiler/rustc_span/src/hygiene.rs
Original file line number Diff line number Diff line change
@@ -459,28 +459,21 @@ impl HygieneData {
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_feature_enabled: bool,
) -> Span {
fn walk_chain_collapsed(&self, mut span: Span, to: Span) -> Span {
let orig_span = span;
let mut ret_span = span;

debug!(
"walk_chain_collapsed({:?}, {:?}), feature_enable={}",
span, to, collapse_debuginfo_feature_enabled,
);
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());
while let ctxt = span.ctxt()
&& !ctxt.is_root()
&& ctxt != to.ctxt()
{
let outer_expn = self.outer_expn(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_feature_enabled || expn_data.collapse_debuginfo {
if expn_data.collapse_debuginfo {
ret_span = span;
}
}
@@ -604,14 +597,13 @@ 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_feature_enabled: bool,
) -> Span {
HygieneData::with(|hdata| {
hdata.walk_chain_collapsed(span, to, collapse_debuginfo_feature_enabled)
})
/// In order to have good line stepping behavior in debugger, for the given span we return its
/// outermost macro call site that still has a `#[collapse_debuginfo(yes)]` property on it.
/// We also stop walking call sites at the function body level because no line stepping can occur
/// at the level above that.
/// The returned span can then be used in emitted debuginfo.
pub fn walk_chain_collapsed(span: Span, to: Span) -> Span {
HygieneData::with(|data| data.walk_chain_collapsed(span, to))
}

pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
12 changes: 12 additions & 0 deletions src/doc/rustc/src/codegen-options/index.md
Original file line number Diff line number Diff line change
@@ -42,6 +42,18 @@ generated code, but may be slower to compile.
The default value, if not specified, is 16 for non-incremental builds. For
incremental builds the default is 256 which allows caching to be more granular.

## collapse-macro-debuginfo

This flag controls whether code locations from a macro definition are collapsed into a single
location associated with that macro's call site, when generating debuginfo for this crate.

This option, if passed, overrides both default collapsing behavior and `#[collapse_debuginfo]`
attributes in code.

* `y`, `yes`, `on`, `true`: collapse code locations in debuginfo.
* `n`, `no`, `off` or `false`: do not collapse code locations in debuginfo.
* `external`: collapse code locations in debuginfo only if the macro comes from a different crate.

## control-flow-guard

This flag controls whether LLVM enables the Windows [Control Flow
Loading