Closed
Description
When generating a variable debuginfo, rustc emits an expression describing the address of a source variable. Since #83941, rustc also evaluates this expression.
The expression can contain indirections, and it is not always valid to evaluate it. Consider a source variable that is described indirectly in terms of a base LocalRef::Place
local. The source variable will be introduced at the beginning of a function, but at this point the base local might be uninitialized. For example:
#![feature(stmt_expr_attributes)]
pub struct S([usize; 8]);
#[no_mangle]
pub fn f(x: S, y: S) -> usize {
(#[inline(always)]|| {
let _z = x;
y.0[0]
})()
}
$ rustc --crate-type=lib c.rs -O -Cdebuginfo=2 -Cno-prepopulate-passes -Zunpretty=mir
...
fn f(_1: S, _2: S) -> usize {
debug x => _1; // in scope 0 at c.rs:5:10: 5:11
debug y => _2; // in scope 0 at c.rs:5:16: 5:17
let mut _0: usize; // return place in scope 0 at c.rs:5:25: 5:30
let mut _3: [closure@c.rs:6:23: 6:25]; // in scope 0 at c.rs:6:5: 9:7
let mut _4: &S; // in scope 0 at c.rs:6:5: 9:7
scope 1 (inlined f::{closure#0}) { // at c.rs:6:5: 9:9
debug x => (_3.0: S); // in scope 1 at c.rs:5:10: 5:11
debug y => (*(_3.1: &S)); // in scope 1 at c.rs:5:16: 5:17
...
$ rustc --crate-type=lib c.rs -O -Cdebuginfo=2 -Cno-prepopulate-passes --emit llvm-ir
...
%S = type { [8 x i64] }
%"[closure@c.rs:6:23: 6:25]" = type { %S, ptr }
; Function Attrs: nonlazybind uwtable
define i64 @f(ptr noalias nocapture noundef readonly dereferenceable(64) %x, ptr noalias nocapture noundef readonly dereferenceable(64) %y) unnamed_addr #0 !dbg !6 {
start:
%_z = alloca %S, align 8
%_3 = alloca %"[closure@c.rs:6:23: 6:25]", align 8
call void @llvm.dbg.declare(metadata ptr %x, metadata !21, metadata !DIExpression()), !dbg !23
call void @llvm.dbg.declare(metadata ptr %y, metadata !22, metadata !DIExpression()), !dbg !24
call void @llvm.dbg.declare(metadata ptr %_3, metadata !25, metadata !DIExpression()), !dbg !39
%0 = getelementptr inbounds %"[closure@c.rs:6:23: 6:25]", ptr %_3, i32 0, i32 1
%1 = load ptr, ptr %0, align 8, !nonnull !19, !align !41, !noundef !19
call void @llvm.dbg.declare(metadata ptr %_3, metadata !36, metadata !DIExpression(DW_OP_plus_uconst, 64, DW_OP_deref)), !dbg !42
call void @llvm.dbg.declare(metadata ptr %_z, metadata !37, metadata !DIExpression()), !dbg !43
call void @llvm.lifetime.start.p0(i64 72, ptr %_3), !dbg !40
Note that %1 = load
has !nonnull
and !noundef
metadata but loaded value is uninitialized.
(This leads to end-to-end miscompilation with -Cdebuginfo=2).