-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Code in block passed to macro has line number of macro invocation #39153
Comments
@hsivonen: you can use |
This helps thank you. It surprises me that the other issue isn't a solved problem on the gdb/DWARF level, considering that C macros allow adjacent statements to be sourced from different places, too. |
The rust compiler can emit DWARF saying where each line comes from and gdb should do the right thing when stepping. The keyword to look for in the DWARF standard is |
@tromey: We wanted to be able to step over macros like println!(), which are far more common in Rust than they are in C/C++. I found two ways of achieving that:
|
This is the part I don't think is desirable. Inlining implies that there is a new function scope, which isn't necessarily the case in reality. It seems like this could make debugging weird unless you take extra effort to inject variables from the function into this new scope. I tend to think this is another area where some Rust DWARF extension would be preferable; though maybe there are other halfway solutions, like a different heuristic for what locations to emit (e.g., if the macro invocation contains significant amounts of user code, emit locations for that code from the expansion, so that stepping "works"). |
Yeah, that's basically the reason we didn't pursue this route. I hope my PR #39678 will sufficiently address the issue with |
This is also a problem when profiling Rust code, at least with the |
@vadimcn Didn't you add a command line flag to control how macro source locations are handled? |
@michaelwoerister yes, -Zdebug-macros does fix it. It would be nicer if this |
@julian-seward1: You scenario is exactly why I added that flag. However, I fail to see why would we want to make it the default. The change was made for the sake of sane debugging experience. Very few people want to land in the middle of a macro definition in libstd (for which we don't even emit line numbers), when trying to step over a |
I, too, think that |
@hsivonen: I can understand that this may be annoying when debugging macro-heavy code (I am guessing you are referring to this?), but you've gotta agree that such code is pretty uncommon.
But non-macro cases never were a problem - step-over works just fine for plain functions.
That would be debugger-dependent and everybody would have to take adjust their config to set up such exclusions. I am not even sure it would work. Debuggers typically allow one to exclude functions from being stepped in, however in this case, all code belongs to the function where the macro was expanded. All things considered, I believe that the current default is correct. That's not to say we should not try to improve. Can we identify more cases when we can be certain that stepping-in is the desired behavior, like this one? Perhaps an attribute can be added that allows to opt out of debug location override? I'll be happy to hear about any ideas that do not involve flipping the global default. PS: Or, maybe, someone wants to design a better debug info support for macros and pitch it to the DWARF Standards Committee? |
Yes. I filed a bug to get
Would giving the current default treatment only to macros from the standard library meet your goals? |
There's one option I don't see anyone explore in this thread. Namely, why not just fix LLVM? LLVM Debug info is unstable enough to make this change at this point. |
It seems that |
Per f2f discussion with @michaelwoerister last week, I propose this be fixed like I suggested on the internals forum:
Use cases:
|
How do the @rust-lang/lang and @rust-lang/compiler teams feel about @hsivonen's proposal? I imagine it to looks something like: #[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[collapse_debuginfo] // <- this is new
macro_rules! assert {
($cond:expr) => ( /* ... */ );
($cond:expr, $($arg:tt)+) => ( /* ... */ );
} Would we need an RFC for this? It wouldn't have to be stabilized immediately, since the most important macros in questions are all in the standard library. |
I think we should. Would be nice to also have an implementation too, so we could compare debugging experience with and without it. |
I'll write an RFC. |
Visited during wg-debugging triage. We don't have any concrete next steps at this time but an idea was floated during the meeting that inferring which kind of line annotation a macro should use might be possible based on the kinds of tokens the macro captures. For example, macros that only capture idents/literals would have the current behavior and macros that capture token trees would use the proposed behavior by default. We need to survey macro uses in the ecosystem to see if this (or something like it) might make sense. |
Relatedly, whether to treat the macro as opaque has come up in: (And macros like I don't have a strong opinion, but I agree it's an issue and it would be good to have a common solution. |
I did a little survey of the macros provided by the standard library/compiler to check @wesleywiser's hypothesis that we could do something intelligent here based on what token kinds are used by a macro:
Overwhelmingly, these macros benefit from debuginfo being collapsed. However, it's clear that std's macros aren't entirely representative of I think the original suggestion from this issue, a |
Do we have any debuginfo attributes at all today? I'm worried about the ad-hoc nature of As per #39153 (comment), I'm wondering if tackling this from the At the very least, I don't think it would be a good idea to consider stabilizing something here (whatever the timeline for that may be, but still) without being certain whether desired behaviors for There's also the matter of always having full debugger awareness of macro expansion layers (like Since I mentioned |
Technically this is possible, but hard to accomplish in practice. One would need to:
(2.1) and (3) might get pushback without (1.1) IMO, a more practical approach would be emitting debug information that is equivalent to an inlined lambda function that captures all variables in the surrounding scope. Might need to extend LLVM's DIBuilder API to support this scenario, but otherwise should be feasible to do. |
…ywiser ssa: implement `#[collapse_debuginfo]` cc rust-lang#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
…ywiser ssa: implement `#[collapse_debuginfo]` cc rust-lang#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
debuginfo: Stabilize `-Z debug-macros`, `-Z collapse-macro-debuginfo` and `#[collapse_debuginfo]` `-Z debug-macros` is "stabilized" by enabling it by default and removing. `-Z collapse-macro-debuginfo` is stabilized as `-C collapse-macro-debuginfo`. It now supports all typical boolean values (`parse_opt_bool`) in addition to just yes/no. Default value of `collapse_debuginfo` was changed from `false` to `external` (i.e. collapsed if external, not collapsed if local) - rust-lang#100758 (comment) describes some debugging scenarios that motivate this default as reasonable. `#[collapse_debuginfo]` attribute without a value is no longer supported to avoid guessing the default. Closes rust-lang#100758 Closes rust-lang#41743 Closes rust-lang#39153 TODO: Stabilization report
debuginfo: Stabilize `-Z debug-macros`, `-Z collapse-macro-debuginfo` and `#[collapse_debuginfo]` `-Z debug-macros` is "stabilized" by enabling it by default and removing. `-Z collapse-macro-debuginfo` is stabilized as `-C collapse-macro-debuginfo`. It now supports all typical boolean values (`parse_opt_bool`) in addition to just yes/no. Default value of `collapse_debuginfo` was changed from `false` to `external` (i.e. collapsed if external, not collapsed if local) - rust-lang#100758 (comment) describes some debugging scenarios that motivate this default as reasonable. `#[collapse_debuginfo]` attribute without a value is no longer supported to avoid guessing the default. Stabilization report: rust-lang#120845 (comment) Closes rust-lang#100758 Closes rust-lang#41743 Closes rust-lang#39153
debuginfo: Stabilize `-Z debug-macros`, `-Z collapse-macro-debuginfo` and `#[collapse_debuginfo]` `-Z debug-macros` is "stabilized" by enabling it by default and removing. `-Z collapse-macro-debuginfo` is stabilized as `-C collapse-macro-debuginfo`. It now supports all typical boolean values (`parse_opt_bool`) in addition to just yes/no. Default value of `collapse_debuginfo` was changed from `false` to `external` (i.e. collapsed if external, not collapsed if local) - rust-lang/rust#100758 (comment) describes some debugging scenarios that motivate this default as reasonable. `#[collapse_debuginfo]` attribute without a value is no longer supported to avoid guessing the default. Stabilization report: rust-lang/rust#120845 (comment) Closes rust-lang/rust#100758 Closes rust-lang/rust#41743 Closes rust-lang/rust#39153
It appears that (at least on Linux) if you pass a block of code to a macro, the line numbers for code in the block become the line of the start of the macro invocation rather than the actual lines within the block. This makes debugging hard.
Consider:
Line reported for
one()
,two()
andthree()
is the line thatcall_macro_defined_somewhere!({
is on. Expected line number forone()
to be the line number forcall_macro_defined_somewhere!({
plus one, etc.The text was updated successfully, but these errors were encountered: