Skip to content

Identifiers introduced via if let binding can't be debugged #97799

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

Closed
wesleywiser opened this issue Jun 6, 2022 · 4 comments · Fixed by #97931
Closed

Identifiers introduced via if let binding can't be debugged #97799

wesleywiser opened this issue Jun 6, 2022 · 4 comments · Fixed by #97931
Labels
A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) C-bug Category: This is a bug.

Comments

@wesleywiser
Copy link
Member

Identifiers introduced via an if let binding can't be inspected in the debugger. For instance:

pub fn do_it(o: Option<i32>) {
    if let Some(x) = o {
        zzz(x); // #break
    }
}

fn zzz(_: i32) { }

Stopping the debugger on line 3 shows no variables in scope other than the function argument o. I tested this in both gdb and WinDbg.

This appears to be because rustc generates incorrect scoping information for the call to zzz. Looking at the LLVM IR, I see

...
  %x = load i32, i32* %7, align 4, !dbg !36
  store i32 %x, i32* %x.dbg.spill, align 4, !dbg !36
  call void @llvm.dbg.declare(metadata i32* %x.dbg.spill, metadata !31, metadata !DIExpression()), !dbg !37
  call void @_ZN7example3zzz17h59648a546f323dcaE(i32 %x), !dbg !38
...
!5 = distinct !DISubprogram(name: "do_it", linkageName: "_ZN7example5do_it17h549531f5caefefa2E", scope: !7, file: !6, line: 1, type: !8, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !3, templateParams: !19, retainedNodes: !29)
!32 = distinct !DILexicalBlock(scope: !5, file: !6, line: 2, column: 12)
!37 = !DILocation(line: 2, column: 17, scope: !32)
!38 = !DILocation(line: 3, column: 9, scope: !5)

Which puts the call to the zzz in a different scope than the one x is in and thus it isn't visible.

This reproduces on all current versions of Rust:

$ rustc +stable --version
rustc 1.61.0 (fe5b13d68 2022-05-18)
$ rustc +beta --version
rustc 1.62.0-beta.3 (a5cf77ca6 2022-06-02)
$ rustc +nightly --version
rustc 1.63.0-nightly (fee3a459d 2022-06-05)
@wesleywiser wesleywiser added A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) C-bug Category: This is a bug. labels Jun 6, 2022
@xldenis
Copy link
Contributor

xldenis commented Jun 9, 2022

I think I'm encountering the same issue, I've noticed that the variables inside an if let block don't have nested scopes in their VarDebugInfo, that is:

if let Some(x /* has scope 1 */) = y /* has scope 0 */ {
   
   let z = expr; // has scope 2

}

has the following scope tree:

0 <---- 1
^
|
+----- 2

instead of

0 <---- 1 <----- 2

@wesleywiser
Copy link
Member Author

Yeah, that looks like the same issue. I hadn't dug in further to see how deep the problem ran. Based on what you're seeing, this might be happening during MIR building or perhaps even earlier in (T)HIR.

@xldenis
Copy link
Contributor

xldenis commented Jun 9, 2022

Based on my understanding of the compilation my initial suspect is THIR since by the time we get to MIR building the if let will have been replaced by a match

@xldenis
Copy link
Contributor

xldenis commented Jun 9, 2022

Ok, a little more digging has led to me confirming the proximal cause of this issue: if let statements turn their bindings into match guards rather than match patterns. My guess is that the scope rules are handled differently between those two cases.

This can be confirmed by replacing your example with the following:

#![feature(if_let_guard)]
...
match o {
  y if let Some(x) = y => { zzz(x) }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) C-bug Category: This is a bug.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants