about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAndrew Zhogin <andrew.zhogin@gmail.com>2024-01-11 01:36:05 +0700
committerAndrew Zhogin <andrew.zhogin@gmail.com>2024-01-17 23:18:14 +0700
commit8507f5105bb5294d802c38918b0b21916b376c16 (patch)
treee8237b1fce01892985eb6418b9d9d766de765984
parentbf2637f4e89aab364d7ab28deb09820363bef86d (diff)
downloadrust-8507f5105bb5294d802c38918b0b21916b376c16.tar.gz
rust-8507f5105bb5294d802c38918b0b21916b376c16.zip
Improved collapse_debuginfo attribute, added command-line flag (no|external|yes)
-rw-r--r--compiler/rustc_expand/messages.ftl3
-rw-r--r--compiler/rustc_expand/src/base.rs56
-rw-r--r--compiler/rustc_expand/src/errors.rs7
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs1
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_interface/src/tests.rs9
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs1
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs3
-rw-r--r--compiler/rustc_session/src/config.rs32
-rw-r--r--compiler/rustc_session/src/options.rs17
-rw-r--r--compiler/rustc_span/src/hygiene.rs19
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--tests/debuginfo/collapse-debuginfo-external-attr.rs31
-rw-r--r--tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs34
-rw-r--r--tests/debuginfo/collapse-debuginfo-external-flag.rs26
-rw-r--r--tests/debuginfo/collapse-debuginfo-no-attr.rs2
-rw-r--r--tests/debuginfo/collapse-debuginfo-with-yes-flag.rs57
17 files changed, 281 insertions, 21 deletions
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 475dd348e7b..3e3b4814300 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -16,6 +16,9 @@ expand_attributes_wrong_form =
 expand_cannot_be_name_of_macro =
     `{$trait_ident}` cannot be a name of {$macro_type} macro
 
+expand_collapse_debuginfo_illegal =
+    illegal value for attribute #[collapse_debuginfo(no|external|yes)]
+
 expand_count_repetition_misplaced =
     `count` can not be placed inside the inner-most repetition
 
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 0a1c4430397..edc9c5a9130 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1,5 +1,6 @@
 #![deny(rustc::untranslatable_diagnostic)]
 
+use crate::base::ast::NestedMetaItem;
 use crate::errors;
 use crate::expand::{self, AstFragment, Invocation};
 use crate::module::DirOwnership;
@@ -19,6 +20,7 @@ use rustc_feature::Features;
 use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, RegisteredTools};
 use rustc_parse::{parser, MACRO_ARGUMENTS};
+use rustc_session::config::CollapseMacroDebuginfo;
 use rustc_session::errors::report_lit_error;
 use rustc_session::{parse::ParseSess, Limit, Session};
 use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
@@ -761,6 +763,55 @@ 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
+                    }
+                }
+            }
+        })
+    }
+
+    /// 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 |
+    /// | 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 collapse_debuginfo_attr = attr::find_by_name(attrs, sym::collapse_debuginfo)
+            .map(|v| Self::collapse_debuginfo_by_name(sess, v))
+            .unwrap_or(CollapseMacroDebuginfo::Unspecified);
+        let flag = sess.opts.unstable_opts.collapse_macro_debuginfo;
+        let attr = collapse_debuginfo_attr;
+        let ext = !is_local;
+        #[rustfmt::skip]
+        let collapse_table = [
+            [false, false, false, false],
+            [false, false, ext,   true],
+            [false, ext,   ext,   true],
+            [true,  true,  true,  true],
+        ];
+        collapse_table[flag as usize][attr as usize]
+    }
+
     /// Constructs a syntax extension with the given properties
     /// and other properties converted from attributes.
     pub fn new(
@@ -772,6 +823,7 @@ impl SyntaxExtension {
         edition: Edition,
         name: Symbol,
         attrs: &[ast::Attribute],
+        is_local: bool,
     ) -> SyntaxExtension {
         let allow_internal_unstable =
             attr::allow_internal_unstable(sess, attrs).collect::<Vec<Symbol>>();
@@ -780,8 +832,8 @@ 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 = attr::contains_name(attrs, sym::collapse_debuginfo);
-        tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
+        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)
             .map(|attr| {
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 2b43fae6852..4a1c00f0104 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -59,6 +59,13 @@ pub(crate) struct ResolveRelativePath {
 }
 
 #[derive(Diagnostic)]
+#[diag(expand_collapse_debuginfo_illegal)]
+pub(crate) struct CollapseMacroDebuginfoIllegal {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(expand_macro_const_stability)]
 pub(crate) struct MacroConstStability {
     #[primary_span]
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 363b52aef8a..1a39708ed8e 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -367,6 +367,7 @@ pub fn compile_declarative_macro(
             edition,
             def.ident.name,
             &def.attrs,
+            def.id != DUMMY_NODE_ID,
         )
     };
     let dummy_syn_ext = || (mk_syn_ext(Box::new(macro_rules_dummy_expander)), Vec::new());
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 4442b67df6e..68b6f69854d 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -469,7 +469,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     // `#[collapse_debuginfo]`
     gated!(
-        collapse_debuginfo, Normal, template!(Word), WarnFollowing,
+        collapse_debuginfo, Normal, template!(Word, List: "no|external|yes"), ErrorFollowing,
         experimental!(collapse_debuginfo)
     ),
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 588139a303c..555c822ad6d 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -4,10 +4,10 @@ use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
 use rustc_session::config::{
     build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg,
-    DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs,
-    FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay,
-    LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy,
-    Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius,
+    CollapseMacroDebuginfo, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry,
+    ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, InstrumentCoverage,
+    InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig,
+    OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius,
     ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
 };
 use rustc_session::lint::Level;
@@ -742,6 +742,7 @@ fn test_unstable_options_tracking_hash() {
         })
     );
     tracked!(codegen_backend, Some("abc".to_string()));
+    tracked!(collapse_macro_debuginfo, CollapseMacroDebuginfo::Yes);
     tracked!(crate_attr, vec!["abc".to_string()]);
     tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
     tracked!(debug_info_for_profiling, true);
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 49e849964be..20e3ae3ba94 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1027,6 +1027,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             self.root.edition,
             Symbol::intern(name),
             &attrs,
+            false,
         )
     }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ad9296a4cc8..a5d9e0fcf44 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2535,8 +2535,7 @@ impl<'tcx> TyCtxt<'tcx> {
         if self.sess.opts.unstable_opts.debug_macros || !span.from_expansion() {
             return span;
         }
-        let collapse_debuginfo_enabled = self.features().collapse_debuginfo;
-        hygiene::walk_chain_collapsed(span, upto, collapse_debuginfo_enabled)
+        hygiene::walk_chain_collapsed(span, upto, self.features().collapse_debuginfo)
     }
 
     #[inline]
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index ac15c3b407b..e751ff13a34 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -3190,12 +3190,12 @@ pub enum WasiExecModel {
 /// how the hash should be calculated when adding a new command-line argument.
 pub(crate) mod dep_tracking {
     use super::{
-        BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression,
-        ErrorOutputType, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay,
-        LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, OptLevel,
-        OutFileName, OutputType, OutputTypes, Polonius, RemapPathScopeComponents, ResolveDocLinks,
-        SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
-        WasiExecModel,
+        BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CrateType, DebugInfo,
+        DebugInfoCompression, ErrorOutputType, FunctionReturn, InliningThreshold,
+        InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, LtoCli,
+        NextSolverConfig, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Polonius,
+        RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind,
+        SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
     };
     use crate::lint;
     use crate::utils::NativeLib;
@@ -3274,6 +3274,7 @@ pub(crate) mod dep_tracking {
         LtoCli,
         DebugInfo,
         DebugInfoCompression,
+        CollapseMacroDebuginfo,
         UnstableFeatures,
         NativeLib,
         SanitizerSet,
@@ -3437,6 +3438,25 @@ pub enum ProcMacroExecutionStrategy {
     CrossThread,
 }
 
+/// How to perform collapse macros debug info
+/// 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 |
+/// | external      | no  | if-ext        | if-ext   | yes |
+/// | yes           | yes | yes           | yes      | yes |
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum CollapseMacroDebuginfo {
+    /// Don't collapse debuginfo for the macro
+    No = 0,
+    /// Unspecified value
+    Unspecified = 1,
+    /// Collapse debuginfo if the macro comes from a different crate
+    External = 2,
+    /// Collapse debuginfo for the macro
+    Yes = 3,
+}
+
 /// Which format to use for `-Z dump-mono-stats`
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
 pub enum DumpMonoStatsFormat {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index f4bf79f93f2..6c91929fcbe 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -388,6 +388,7 @@ mod desc {
     pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
     pub const parse_debuginfo: &str = "either an integer (0, 1, 2), `none`, `line-directives-only`, `line-tables-only`, `limited`, or `full`";
     pub const parse_debuginfo_compression: &str = "one of `none`, `zlib`, or `zstd`";
+    pub const parse_collapse_macro_debuginfo: &str = "one of `no`, `external`, or `yes`";
     pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
     pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
     pub const parse_optimization_fuel: &str = "crate=integer";
@@ -1302,6 +1303,19 @@ mod parse {
         true
     }
 
+    pub(crate) fn parse_collapse_macro_debuginfo(
+        slot: &mut CollapseMacroDebuginfo,
+        v: Option<&str>,
+    ) -> bool {
+        *slot = match v {
+            Some("no") => CollapseMacroDebuginfo::No,
+            Some("external") => CollapseMacroDebuginfo::External,
+            Some("yes") => CollapseMacroDebuginfo::Yes,
+            _ => return false,
+        };
+        true
+    }
+
     pub(crate) fn parse_proc_macro_execution_strategy(
         slot: &mut ProcMacroExecutionStrategy,
         v: Option<&str>,
@@ -1534,6 +1548,9 @@ options! {
         "instrument control-flow architecture protection"),
     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"),
     crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index d03965b539c..21623fdc1d2 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -464,12 +464,15 @@ impl HygieneData {
         &self,
         mut span: Span,
         to: Span,
-        collapse_debuginfo_enabled: bool,
+        collapse_debuginfo_feature_enabled: bool,
     ) -> Span {
         let orig_span = span;
         let mut ret_span = span;
 
-        debug!("walk_chain_collapsed({:?}, {:?})", span, to);
+        debug!(
+            "walk_chain_collapsed({:?}, {:?}), feature_enable={}",
+            span, to, collapse_debuginfo_feature_enabled,
+        );
         debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt());
         while !span.eq_ctxt(to) && span.from_expansion() {
             let outer_expn = self.outer_expn(span.ctxt());
@@ -477,7 +480,7 @@ impl HygieneData {
             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_enabled || expn_data.collapse_debuginfo {
+            if !collapse_debuginfo_feature_enabled || expn_data.collapse_debuginfo {
                 ret_span = span;
             }
         }
@@ -601,8 +604,14 @@ 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_enabled: bool) -> Span {
-    HygieneData::with(|hdata| hdata.walk_chain_collapsed(span, to, collapse_debuginfo_enabled))
+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)
+    })
 }
 
 pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 72b62a795fc..44795022cba 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -749,6 +749,7 @@ symbols! {
         extern_in_paths,
         extern_prelude,
         extern_types,
+        external,
         external_doc,
         f,
         f16c_target_feature,
@@ -1811,6 +1812,7 @@ symbols! {
         xmm_reg,
         yeet_desugar_details,
         yeet_expr,
+        yes,
         yield_expr,
         ymm_reg,
         zmm_reg,
diff --git a/tests/debuginfo/collapse-debuginfo-external-attr.rs b/tests/debuginfo/collapse-debuginfo-external-attr.rs
new file mode 100644
index 00000000000..f36b0833ad5
--- /dev/null
+++ b/tests/debuginfo/collapse-debuginfo-external-attr.rs
@@ -0,0 +1,31 @@
+// ignore-lldb
+#![feature(collapse_debuginfo)]
+
+// Test that local macro debug info is not collapsed with #[collapse_debuginfo(external)]
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#one_callsite[...]
+// gdb-command:continue
+
+fn one() {
+    println!("one");
+}
+
+#[collapse_debuginfo(external)]
+macro_rules! outer {
+    () => {
+        one(); // #one_callsite
+    };
+}
+
+fn main() {
+    let ret = 0; // #break
+    outer!();
+    std::process::exit(ret);
+}
diff --git a/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs b/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs
new file mode 100644
index 00000000000..e5cbc1a685d
--- /dev/null
+++ b/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs
@@ -0,0 +1,34 @@
+// ignore-lldb
+#![feature(collapse_debuginfo)]
+
+// Test that macro attribute #[collapse_debuginfo(no)]
+// overrides "collapse_macro_debuginfo=external" flag
+
+// compile-flags:-g -Z collapse_macro_debuginfo=external
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#one_callsite[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-command:continue
+
+fn one() {
+    println!("one");
+}
+
+#[collapse_debuginfo(no)]
+macro_rules! outer {
+    () => {
+        one(); // #one_callsite
+    };
+}
+
+fn main() {
+    let ret = 0; // #break
+    outer!();
+    std::process::exit(ret);
+}
diff --git a/tests/debuginfo/collapse-debuginfo-external-flag.rs b/tests/debuginfo/collapse-debuginfo-external-flag.rs
new file mode 100644
index 00000000000..9a0aef38ea6
--- /dev/null
+++ b/tests/debuginfo/collapse-debuginfo-external-flag.rs
@@ -0,0 +1,26 @@
+// ignore-lldb
+#![feature(collapse_debuginfo)]
+
+// Test that println macro debug info is collapsed with "collapse_macro_debuginfo=external" flag
+
+// compile-flags:-g -Z collapse_macro_debuginfo=external
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#println_callsite[...]
+// gdb-command:continue
+
+macro_rules! outer {
+    () => {
+        println!("one"); // #println_callsite
+    };
+}
+
+fn main() {
+    let ret = 0; // #break
+    outer!();
+    std::process::exit(ret);
+}
diff --git a/tests/debuginfo/collapse-debuginfo-no-attr.rs b/tests/debuginfo/collapse-debuginfo-no-attr.rs
index 230c8795be3..d156c381a15 100644
--- a/tests/debuginfo/collapse-debuginfo-no-attr.rs
+++ b/tests/debuginfo/collapse-debuginfo-no-attr.rs
@@ -4,7 +4,7 @@
 // Test that line numbers are not replaced with those of the outermost expansion site when the
 // `collapse_debuginfo` feature is active and the attribute is not provided.
 
-// compile-flags:-g
+// compile-flags:-g -Z collapse_macro_debuginfo=no
 
 // === GDB TESTS ===================================================================================
 
diff --git a/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs b/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs
new file mode 100644
index 00000000000..76a97a325d7
--- /dev/null
+++ b/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs
@@ -0,0 +1,57 @@
+// ignore-lldb
+#![feature(collapse_debuginfo)]
+
+// Test that line numbers are replaced with those of the outermost expansion site when the
+// `collapse_debuginfo` feature is active and the command line flag is provided.
+
+// compile-flags:-g -Z collapse_macro_debuginfo=yes
+
+// === 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:continue
+
+fn one() {
+    println!("one");
+}
+fn two() {
+    println!("two");
+}
+fn three() {
+    println!("three");
+}
+fn four() {
+    println!("four");
+}
+
+macro_rules! outer {
+    ($b:block) => {
+        one();
+        inner!();
+        $b
+    };
+}
+
+macro_rules! inner {
+    () => {
+        two();
+    };
+}
+
+fn main() {
+    let ret = 0; // #break
+    outer!({ // #loc1
+        three(); // #loc2
+        four(); // #loc3
+    });
+    std::process::exit(ret);
+}