Keep track of how scopes and locals are duplicated during inlining so that they can be correctly de-duplicated when emitting debug info #115455
Labels
A-debuginfo
Area: Debugging information in compiled programs (DWARF, PDB, etc.)
C-bug
Category: This is a bug.
T-compiler
Relevant to the compiler team, which will review and decide on the PR/issue.
WG-debugging
Working group: Bad Rust debugging experiences
Background
Original issue
The call to
panic
within a function likeOption::unwrap
is translated to LLVM as atail call
(as it will never return), when multiple calls to the same function like this are inlined LLVM will notice the commontail call
block (i.e., loading the same panic string + location info and then callingpanic
) and merge them together.When merging these instructions together, LLVM will also attempt to merge the debug locations as well, but this fails (i.e., debug info is dropped) as Rust emits a new
DISubprogram
at each inline site thus LLVM doesn't recognize that these are actually the same function and so thinks that there isn't a common debug location.As an example of this, consider the following program:
When building for x86_64 Windows using 1.72 it generates (note the lack of
.cv_loc
before the call topanic
, thus it will be attributed to the same line at theaddq
instruction):Ideally, we would generate debug information that would allow LLVM to (partially) merge the locations together and thus maintain the correct inlining information and partial line info (since the inlined function was de-duplicated, we can't give the exact line number as that is ambiguous between the two inline sites, but we also shouldn't show an incorrect line number).
For example, we could generate something like below (which shows the
panic!
was inlined fromunwrap
inoption.rs
at line 935 into the current function inlib.rs
at line 0):New issue
I attempted to fix this by deduplicating sub-program, lexical block and variable debug info in #114643 however this resulted in asserts in LLVM when attempting to build for Linux (see #115156).
The root cause of those asserts is that Rust was generating overlapping
DW_OP_LLVM_fragment
info for the same local variable in two different@llvm.dbg.declare
calls (i.e., that two different stack allocations represented the same part ("fragment") of the same local variable).My current plan (#115417) is to work around this by not deduplicating lexical scopes and variables, but instead create a new lexical scope every time that a function is inlined so that subsequent lexical scopes and variables do not appear to be duplicates (from LLVM's perspective).
Long-term fix
Given that LLVM relies on exact matching to merge together debug locations, and that Clang appears to do this deduplicating in its debug information, it seems that the correct long-term fix is for Rust to also do this deduplicating.
However, to do this Rust needs to keep careful track of how locals and scopes are duplicated while inlining - either to avoid the duplication at the point of inlining or to be able to deduplicate them when emitting debug information.
The text was updated successfully, but these errors were encountered: