about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-08-14 23:59:11 +0800
committerGitHub <noreply@github.com>2018-08-14 23:59:11 +0800
commit764755b0b0367fcd79133f783efaebd7bcfb82a0 (patch)
treea8eabadf27afbb822215238618fd30ad9381b986 /src
parent2ae5f64daff3f7d01ab5f6816deb899d3fd9845c (diff)
parent763e72110a913c7aab396a0f687e2ebd3c9e572a (diff)
downloadrust-764755b0b0367fcd79133f783efaebd7bcfb82a0.tar.gz
rust-764755b0b0367fcd79133f783efaebd7bcfb82a0.zip
Rollup merge of #53239 - cuviper:llvm5-closure-alloca, r=eddyb
rustc_codegen_llvm: Restore the closure env alloca hack for LLVM 5.

This hack was removed in #50949, but without it I found that building
`std` with full debuginfo would print many LLVM `DW_OP_LLVM_fragment`
errors, then die `LLVM ERROR: Failed to strip malformed debug info`.

It doesn't seem to be a problem for LLVM 6, so we can re-enable the hack
just for older LLVM.

This reverts commit da579ef75e4a8ca11fb98b24a0a3ea0c7ccffeeb.
Fixes #53204.
r? @eddyb
Diffstat (limited to 'src')
-rw-r--r--src/librustc_codegen_llvm/mir/mod.rs26
1 files changed, 24 insertions, 2 deletions
diff --git a/src/librustc_codegen_llvm/mir/mod.rs b/src/librustc_codegen_llvm/mir/mod.rs
index 8fdb67f5930..8bb049be305 100644
--- a/src/librustc_codegen_llvm/mir/mod.rs
+++ b/src/librustc_codegen_llvm/mir/mod.rs
@@ -574,6 +574,25 @@ fn arg_local_refs(
             };
             let upvar_tys = upvar_substs.upvar_tys(def_id, tcx);
 
+            // Store the pointer to closure data in an alloca for debuginfo
+            // because that's what the llvm.dbg.declare intrinsic expects.
+
+            // FIXME(eddyb) this shouldn't be necessary but SROA seems to
+            // mishandle DW_OP_plus not preceded by DW_OP_deref, i.e. it
+            // doesn't actually strip the offset when splitting the closure
+            // environment into its components so it ends up out of bounds.
+            // (cuviper) It seems to be fine without the alloca on LLVM 6 and later.
+            let env_alloca = !env_ref && unsafe { llvm::LLVMRustVersionMajor() < 6 };
+            let env_ptr = if env_alloca {
+                let scratch = PlaceRef::alloca(bx,
+                    bx.cx.layout_of(tcx.mk_mut_ptr(arg.layout.ty)),
+                    "__debuginfo_env_ptr");
+                bx.store(place.llval, scratch.llval, scratch.align);
+                scratch.llval
+            } else {
+                place.llval
+            };
+
             for (i, (decl, ty)) in mir.upvar_decls.iter().zip(upvar_tys).enumerate() {
                 let byte_offset_of_var_in_env = closure_layout.fields.offset(i).bytes();
 
@@ -585,7 +604,10 @@ fn arg_local_refs(
                 };
 
                 // The environment and the capture can each be indirect.
-                let mut ops = if env_ref { &ops[..] } else { &ops[1..] };
+
+                // FIXME(eddyb) see above why we sometimes have to keep
+                // a pointer in an alloca for debuginfo atm.
+                let mut ops = if env_ref || env_alloca { &ops[..] } else { &ops[1..] };
 
                 let ty = if let (true, &ty::TyRef(_, ty, _)) = (decl.by_ref, &ty.sty) {
                     ty
@@ -595,7 +617,7 @@ fn arg_local_refs(
                 };
 
                 let variable_access = VariableAccess::IndirectVariable {
-                    alloca: place.llval,
+                    alloca: env_ptr,
                     address_operations: &ops
                 };
                 declare_local(