mod.rs 22.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use libc::c_uint;
M
Mark-Simulacrum 已提交
12
use llvm::{self, ValueRef, BasicBlockRef};
M
Mark-Simulacrum 已提交
13
use llvm::debuginfo::DIScope;
M
Mark-Simulacrum 已提交
14
use rustc::ty;
M
Mark-Simulacrum 已提交
15
use rustc::mir::{self, Mir};
16
use rustc::mir::tcx::LvalueTy;
17 18 19
use rustc::ty::subst::Substs;
use rustc::infer::TransNormalize;
use rustc::ty::TypeFoldable;
20
use session::config::FullDebugInfo;
21
use base;
M
Mark-Simulacrum 已提交
22
use common::{self, BlockAndBuilder, CrateContext, FunctionContext, C_null, Funclet};
M
Mark-Simulacrum 已提交
23
use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
24
use monomorphize::{self, Instance};
M
Mark-Simulacrum 已提交
25
use machine;
26 27
use type_of;

M
Mark-Simulacrum 已提交
28
use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span};
29
use syntax::symbol::keywords;
30
use syntax::abi::Abi;
31

32
use std::iter;
33

34
use rustc_data_structures::bitvec::BitVector;
35
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
36

37 38
pub use self::constant::trans_static_initializer;

M
Mark Simulacrum 已提交
39
use self::analyze::CleanupKind;
40
use self::lvalue::{LvalueRef};
41
use rustc::mir::traversal;
42

43
use self::operand::{OperandRef, OperandValue};
44 45

/// Master context for translating MIR.
M
Mark Simulacrum 已提交
46
pub struct MirContext<'a, 'tcx:'a> {
47
    mir: &'a mir::Mir<'tcx>,
48

49
    debug_context: debuginfo::FunctionDebugContext,
50

51
    /// Function context
M
Mark Simulacrum 已提交
52
    fcx: &'a common::FunctionContext<'a, 'tcx>,
53

54 55 56 57 58 59 60 61 62 63
    /// When unwinding is initiated, we have to store this personality
    /// value somewhere so that we can load it and re-use it in the
    /// resume instruction. The personality is (afaik) some kind of
    /// value used for C++ unwinding, which must filter by type: we
    /// don't really care about it very much. Anyway, this value
    /// contains an alloca into which the personality is stored and
    /// then later loaded when generating the DIVERGE_BLOCK.
    llpersonalityslot: Option<ValueRef>,

    /// A `Block` for each MIR `BasicBlock`
M
Mark-Simulacrum 已提交
64
    blocks: IndexVec<mir::BasicBlock, BasicBlockRef>,
65

66
    /// The funclet status of each basic block
67
    cleanup_kinds: IndexVec<mir::BasicBlock, analyze::CleanupKind>,
68 69 70

    /// This stores the landing-pad block for a given BB, computed lazily on GNU
    /// and eagerly on MSVC.
M
Mark-Simulacrum 已提交
71
    landing_pads: IndexVec<mir::BasicBlock, Option<BasicBlockRef>>,
72

73
    /// Cached unreachable block
M
Mark-Simulacrum 已提交
74
    unreachable_block: Option<BasicBlockRef>,
75

76
    /// The location where each MIR arg/var/tmp/ret is stored. This is
77 78 79 80 81
    /// usually an `LvalueRef` representing an alloca, but not always:
    /// sometimes we can skip the alloca and just store the value
    /// directly using an `OperandRef`, which makes for tighter LLVM
    /// IR. The conditions for using an `OperandRef` are as follows:
    ///
82
    /// - the type of the local must be judged "immediate" by `type_is_immediate`
83 84 85 86 87
    /// - the operand must never be referenced indirectly
    ///     - we should not take its address using the `&` operator
    ///     - nor should it appear in an lvalue path like `tmp.a`
    /// - the operand must be defined by an rvalue that can generate immediate
    ///   values
N
Niko Matsakis 已提交
88 89 90
    ///
    /// Avoiding allocs can also be important for certain intrinsics,
    /// notably `expect`.
91
    locals: IndexVec<mir::Local, LocalRef<'tcx>>,
92 93

    /// Debug information for MIR scopes.
94
    scopes: IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
95 96 97

    /// If this function is being monomorphized, this contains the type substitutions used.
    param_substs: &'tcx Substs<'tcx>,
98 99
}

M
Mark Simulacrum 已提交
100
impl<'a, 'tcx> MirContext<'a, 'tcx> {
101 102 103 104 105
    pub fn monomorphize<T>(&self, value: &T) -> T
        where T: TransNormalize<'tcx> {
        monomorphize::apply_param_substs(self.fcx.ccx.shared(), self.param_substs, value)
    }

106 107 108 109 110
    pub fn set_debug_loc(&mut self, bcx: &BlockAndBuilder, source_info: mir::SourceInfo) {
        let (scope, span) = self.debug_loc(source_info);
        debuginfo::set_source_location(&self.debug_context, bcx, scope, span);
    }

M
Mark-Simulacrum 已提交
111
    pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> (DIScope, Span) {
112
        // Bail out if debug info emission is not enabled.
113
        match self.debug_context {
114 115
            FunctionDebugContext::DebugInfoDisabled |
            FunctionDebugContext::FunctionWithoutDebugInfo => {
M
Mark-Simulacrum 已提交
116
                return (self.scopes[source_info.scope].scope_metadata, source_info.span);
117 118 119 120 121 122 123 124 125 126 127
            }
            FunctionDebugContext::RegularContext(_) =>{}
        }

        // In order to have a good line stepping behavior in debugger, we overwrite debug
        // locations of macro expansions with that of the outermost expansion site
        // (unless the crate is being compiled with `-Z debug-macros`).
        if source_info.span.expn_id == NO_EXPANSION ||
            source_info.span.expn_id == COMMAND_LINE_EXPN ||
            self.fcx.ccx.sess().opts.debugging_opts.debug_macros {

128 129
            let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo);
            (scope, source_info.span)
130 131 132 133 134 135 136 137 138 139 140 141
        } else {
            let cm = self.fcx.ccx.sess().codemap();
            // Walk up the macro expansion chain until we reach a non-expanded span.
            let mut span = source_info.span;
            while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN {
                if let Some(callsite_span) = cm.with_expn_info(span.expn_id,
                                                    |ei| ei.map(|ei| ei.call_site.clone())) {
                    span = callsite_span;
                } else {
                    break;
                }
            }
142
            let scope = self.scope_metadata_for_loc(source_info.scope, span.lo);
143
            // Use span of the outermost call site, while keeping the original lexical scope
144
            (scope, span)
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
        }
    }

    // DILocations inherit source file name from the parent DIScope.  Due to macro expansions
    // it may so happen that the current span belongs to a different file than the DIScope
    // corresponding to span's containing visibility scope.  If so, we need to create a DIScope
    // "extension" into that file.
    fn scope_metadata_for_loc(&self, scope_id: mir::VisibilityScope, pos: BytePos)
                               -> llvm::debuginfo::DIScope {
        let scope_metadata = self.scopes[scope_id].scope_metadata;
        if pos < self.scopes[scope_id].file_start_pos ||
           pos >= self.scopes[scope_id].file_end_pos {
            let cm = self.fcx.ccx.sess().codemap();
            debuginfo::extend_scope_to_file(self.fcx.ccx,
                                            scope_metadata,
                                            &cm.lookup_char_pos(pos).file)
        } else {
            scope_metadata
        }
164 165 166
    }
}

167
enum LocalRef<'tcx> {
168 169 170 171
    Lvalue(LvalueRef<'tcx>),
    Operand(Option<OperandRef<'tcx>>),
}

172
impl<'tcx> LocalRef<'tcx> {
M
Mark Simulacrum 已提交
173
    fn new_operand<'a>(ccx: &CrateContext<'a, 'tcx>,
174
                         ty: ty::Ty<'tcx>) -> LocalRef<'tcx> {
175 176 177 178
        if common::type_is_zero_size(ccx, ty) {
            // Zero-size temporaries aren't always initialized, which
            // doesn't matter because they don't contain data, but
            // we need something in the operand.
179
            let llty = type_of::type_of(ccx, ty);
180
            let val = if common::type_is_imm_pair(ccx, ty) {
181 182
                let fields = llty.field_types();
                OperandValue::Pair(C_null(fields[0]), C_null(fields[1]))
183
            } else {
184
                OperandValue::Immediate(C_null(llty))
185
            };
186 187 188 189
            let op = OperandRef {
                val: val,
                ty: ty
            };
190
            LocalRef::Operand(Some(op))
191
        } else {
192
            LocalRef::Operand(None)
193
        }
J
James Miller 已提交
194 195 196
    }
}

197 198
///////////////////////////////////////////////////////////////////////////

199 200 201 202 203 204 205
pub fn trans_mir<'a, 'tcx: 'a>(
    fcx: &'a FunctionContext<'a, 'tcx>,
    mir: &'a Mir<'tcx>,
    instance: Instance<'tcx>,
    sig: &ty::FnSig<'tcx>,
    abi: Abi,
) {
206 207
    let debug_context =
        debuginfo::create_function_debug_context(fcx.ccx, instance, sig, abi, fcx.llfn, mir);
208
    let bcx = fcx.get_entry_block();
209

M
Mark-Simulacrum 已提交
210
    let cleanup_kinds = analyze::cleanup_kinds(&mir);
211

212
    // Allocate a `Block` for every basic block
M
Mark-Simulacrum 已提交
213
    let block_bcxs: IndexVec<mir::BasicBlock, BasicBlockRef> =
214 215 216 217 218 219 220 221
        mir.basic_blocks().indices().map(|bb| {
            if bb == mir::START_BLOCK {
                fcx.new_block("start")
            } else {
                fcx.new_block(&format!("{:?}", bb))
            }
        }).collect();

222
    // Compute debuginfo scopes from MIR scopes.
223
    let scopes = debuginfo::create_mir_scopes(fcx, mir, &debug_context);
224

225
    let mut mircx = MirContext {
226
        mir: mir,
227 228 229 230 231 232 233 234
        fcx: fcx,
        llpersonalityslot: None,
        blocks: block_bcxs,
        unreachable_block: None,
        cleanup_kinds: cleanup_kinds,
        landing_pads: IndexVec::from_elem(None, mir.basic_blocks()),
        scopes: scopes,
        locals: IndexVec::new(),
235
        debug_context: debug_context,
236 237 238 239
        param_substs: {
            assert!(!instance.substs.needs_infer());
            instance.substs
        },
240 241
    };

242
    let lvalue_locals = analyze::lvalue_locals(&mircx);
243

244
    // Allocate variable and temp allocas
245
    mircx.locals = {
246
        let args = arg_local_refs(&bcx, &mircx, &mircx.scopes, &lvalue_locals);
247 248 249

        let mut allocate_local = |local| {
            let decl = &mir.local_decls[local];
250
            let ty = mircx.monomorphize(&decl.ty);
251

252 253 254 255 256
            if let Some(name) = decl.name {
                // User variable
                let source_info = decl.source_info.unwrap();
                let debug_scope = mircx.scopes[source_info.scope];
                let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo;
257

258 259
                if !lvalue_locals.contains(local.index()) && !dbg {
                    debug!("alloc: {:?} ({}) -> operand", local, name);
M
Mark Simulacrum 已提交
260
                    return LocalRef::new_operand(bcx.ccx, ty);
261
                }
262 263 264 265

                debug!("alloc: {:?} ({}) -> lvalue", local, name);
                let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str());
                if dbg {
M
Mark-Simulacrum 已提交
266
                    let (scope, span) = mircx.debug_loc(source_info);
267
                    declare_local(&bcx, &mircx.debug_context, name, ty, scope,
M
Mark-Simulacrum 已提交
268 269
                        VariableAccess::DirectVariable { alloca: lvalue.llval },
                        VariableKind::LocalVariable, span);
270 271
                }
                LocalRef::Lvalue(lvalue)
272
            } else {
273 274 275 276 277 278 279 280 281 282 283 284 285
                // Temporary or return pointer
                if local == mir::RETURN_POINTER && fcx.fn_ty.ret.is_indirect() {
                    debug!("alloc: {:?} (return pointer) -> lvalue", local);
                    let llretptr = llvm::get_param(fcx.llfn, 0);
                    LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty)))
                } else if lvalue_locals.contains(local.index()) {
                    debug!("alloc: {:?} -> lvalue", local);
                    LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty, &format!("{:?}", local)))
                } else {
                    // If this is an immediate local, we do not create an
                    // alloca in advance. Instead we wait until we see the
                    // definition and update the operand there.
                    debug!("alloc: {:?} -> operand", local);
M
Mark Simulacrum 已提交
286
                    LocalRef::new_operand(bcx.ccx, ty)
287
                }
288
            }
289 290 291 292 293
        };

        let retptr = allocate_local(mir::RETURN_POINTER);
        iter::once(retptr)
            .chain(args.into_iter())
294
            .chain(mir.vars_and_temps_iter().map(allocate_local))
295
            .collect()
296
    };
297 298

    // Branch to the START block
299
    let start_bcx = mircx.blocks[mir::START_BLOCK];
M
Mark-Simulacrum 已提交
300
    bcx.br(start_bcx);
301

302 303 304
    // Up until here, IR instructions for this function have explicitly not been annotated with
    // source code location, so we don't step into call setup code. From here on, source location
    // emitting should be enabled.
305
    debuginfo::start_emitting_source_locations(&mircx.debug_context);
306

M
Mark Simulacrum 已提交
307
    // If false, all funclets should be None (which is the default)
M
Mark Simulacrum 已提交
308 309
    let funclets: IndexVec<mir::BasicBlock, Option<Funclet>> =
    mircx.cleanup_kinds.iter_enumerated().map(|(bb, cleanup_kind)| {
310 311 312 313 314
        if let CleanupKind::Funclet = *cleanup_kind {
            let bcx = mircx.build_block(bb);
            bcx.set_personality_fn(fcx.eh_personality());
            if base::wants_msvc_seh(fcx.ccx.sess()) {
                return Some(Funclet::new(bcx.cleanup_pad(None, &[])));
M
Mark Simulacrum 已提交
315 316
            }
        }
317 318

        None
M
Mark Simulacrum 已提交
319
    }).collect();
M
Mark Simulacrum 已提交
320 321 322

    let rpo = traversal::reverse_postorder(&mir);
    let mut visited = BitVector::new(mir.basic_blocks().len());
323

324 325
    // Translate the body of each block using reverse postorder
    for (bb, _) in rpo {
326
        visited.insert(bb.index());
M
Mark-Simulacrum 已提交
327
        mircx.trans_block(bb, &funclets);
328
    }
329

330 331
    // Remove blocks that haven't been visited, or have no
    // predecessors.
332
    for bb in mir.basic_blocks().indices() {
333
        // Unreachable block
334
        if !visited.contains(bb.index()) {
335
            debug!("trans_mir: block {:?} was not visited", bb);
336 337 338
            unsafe {
                llvm::LLVMDeleteBasicBlock(mircx.blocks[bb]);
            }
339 340
        }
    }
341 342 343 344 345
}

/// Produce, for each argument, a `ValueRef` pointing at the
/// argument's value. As arguments are lvalues, these are always
/// indirect.
M
Mark Simulacrum 已提交
346
fn arg_local_refs<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
347
                            mircx: &MirContext<'a, 'tcx>,
M
Mark Simulacrum 已提交
348 349 350
                            scopes: &IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
                            lvalue_locals: &BitVector)
                            -> Vec<LocalRef<'tcx>> {
351
    let mir = mircx.mir;
352
    let fcx = bcx.fcx();
353
    let tcx = bcx.tcx();
354 355
    let mut idx = 0;
    let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
356

357
    // Get the argument scope, if it exists and if we need it.
358
    let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE];
359 360
    let arg_scope = if arg_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo {
        Some(arg_scope.scope_metadata)
361 362 363
    } else {
        None
    };
364

365
    mir.args_iter().enumerate().map(|(arg_index, local)| {
366
        let arg_decl = &mir.local_decls[local];
367
        let arg_ty = mircx.monomorphize(&arg_decl.ty);
368

J
Jonas Schievink 已提交
369 370 371 372 373 374 375 376 377 378
        if Some(local) == mir.spread_arg {
            // This argument (e.g. the last argument in the "rust-call" ABI)
            // is a tuple that was spread at the ABI level and now we have
            // to reconstruct it into a tuple local variable, from multiple
            // individual LLVM function arguments.

            let tupled_arg_tys = match arg_ty.sty {
                ty::TyTuple(ref tys) => tys,
                _ => bug!("spread argument isn't a tuple?!")
            };
379

380
            let lltemp = base::alloc_ty(&bcx, arg_ty, &format!("arg{}", arg_index));
J
Jonas Schievink 已提交
381 382 383 384
            for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
                let dst = bcx.struct_gep(lltemp, i);
                let arg = &fcx.fn_ty.args[idx];
                idx += 1;
M
Mark Simulacrum 已提交
385
                if common::type_is_fat_ptr(bcx.ccx, tupled_arg_ty) {
J
Jonas Schievink 已提交
386 387 388 389
                    // We pass fat pointers as two words, but inside the tuple
                    // they are the two sub-fields of a single aggregate field.
                    let meta = &fcx.fn_ty.args[idx];
                    idx += 1;
M
Mark-Simulacrum 已提交
390 391
                    arg.store_fn_arg(bcx, &mut llarg_idx, base::get_dataptr(bcx, dst));
                    meta.store_fn_arg(bcx, &mut llarg_idx, base::get_meta(bcx, dst));
J
Jonas Schievink 已提交
392 393
                } else {
                    arg.store_fn_arg(bcx, &mut llarg_idx, dst);
394
                }
395
            }
396 397 398

            // Now that we have one alloca that contains the aggregate value,
            // we can create one debuginfo entry for the argument.
399
            arg_scope.map(|scope| {
400 401 402
                let variable_access = VariableAccess::DirectVariable {
                    alloca: lltemp
                };
403 404 405 406 407 408 409 410 411
                declare_local(
                    bcx,
                    &mircx.debug_context,
                    arg_decl.name.unwrap_or(keywords::Invalid.name()),
                    arg_ty, scope,
                    variable_access,
                    VariableKind::ArgumentVariable(arg_index + 1),
                    DUMMY_SP
                );
412
            });
413

J
Jonas Schievink 已提交
414
            return LocalRef::Lvalue(LvalueRef::new_sized(lltemp, LvalueTy::from_ty(arg_ty)));
415 416
        }

417 418
        let arg = &fcx.fn_ty.args[idx];
        idx += 1;
419
        let llval = if arg.is_indirect() && bcx.sess().opts.debuginfo != FullDebugInfo {
420 421 422
            // Don't copy an indirect argument to an alloca, the caller
            // already put it in a temporary alloca and gave it up, unless
            // we emit extra-debug-info, which requires local allocas :(.
423
            // FIXME: lifetimes
424 425 426
            if arg.pad.is_some() {
                llarg_idx += 1;
            }
427 428 429
            let llarg = llvm::get_param(fcx.llfn, llarg_idx as c_uint);
            llarg_idx += 1;
            llarg
430 431 432 433
        } else if !lvalue_locals.contains(local.index()) &&
                  !arg.is_indirect() && arg.cast.is_none() &&
                  arg_scope.is_none() {
            if arg.is_ignore() {
M
Mark Simulacrum 已提交
434
                return LocalRef::new_operand(bcx.ccx, arg_ty);
435 436 437 438 439 440 441 442 443 444
            }

            // We don't have to cast or keep the argument in the alloca.
            // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
            // of putting everything in allocas just so we can use llvm.dbg.declare.
            if arg.pad.is_some() {
                llarg_idx += 1;
            }
            let llarg = llvm::get_param(fcx.llfn, llarg_idx as c_uint);
            llarg_idx += 1;
M
Mark Simulacrum 已提交
445
            let val = if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
446 447 448 449 450 451 452 453 454 455 456 457 458 459
                let meta = &fcx.fn_ty.args[idx];
                idx += 1;
                assert_eq!((meta.cast, meta.pad), (None, None));
                let llmeta = llvm::get_param(fcx.llfn, llarg_idx as c_uint);
                llarg_idx += 1;
                OperandValue::Pair(llarg, llmeta)
            } else {
                OperandValue::Immediate(llarg)
            };
            let operand = OperandRef {
                val: val,
                ty: arg_ty
            };
            return LocalRef::Operand(Some(operand.unpack_if_pair(bcx)));
460
        } else {
461
            let lltemp = base::alloc_ty(&bcx, arg_ty, &format!("arg{}", arg_index));
M
Mark Simulacrum 已提交
462
            if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
463 464 465 466 467
                // we pass fat pointers as two words, but we want to
                // represent them internally as a pointer to two words,
                // so make an alloca to store them in.
                let meta = &fcx.fn_ty.args[idx];
                idx += 1;
M
Mark-Simulacrum 已提交
468 469
                arg.store_fn_arg(bcx, &mut llarg_idx, base::get_dataptr(bcx, lltemp));
                meta.store_fn_arg(bcx, &mut llarg_idx, base::get_meta(bcx, lltemp));
470
            } else  {
471 472
                // otherwise, arg is passed by value, so make a
                // temporary and store it there
473 474
                arg.store_fn_arg(bcx, &mut llarg_idx, lltemp);
            }
475
            lltemp
476
        };
477
        arg_scope.map(|scope| {
478 479
            // Is this a regular argument?
            if arg_index > 0 || mir.upvar_decls.is_empty() {
480 481 482 483 484 485 486 487 488 489
                declare_local(
                    bcx,
                    &mircx.debug_context,
                    arg_decl.name.unwrap_or(keywords::Invalid.name()),
                    arg_ty,
                    scope,
                    VariableAccess::DirectVariable { alloca: llval },
                    VariableKind::ArgumentVariable(arg_index + 1),
                    DUMMY_SP
                );
490 491 492 493 494 495 496 497 498
                return;
            }

            // Or is it the closure environment?
            let (closure_ty, env_ref) = if let ty::TyRef(_, mt) = arg_ty.sty {
                (mt.ty, true)
            } else {
                (arg_ty, false)
            };
499 500
            let upvar_tys = if let ty::TyClosure(def_id, substs) = closure_ty.sty {
                substs.upvar_tys(def_id, tcx)
501 502 503 504 505 506 507 508 509 510 511 512
            } else {
                bug!("upvar_decls with non-closure arg0 type `{}`", closure_ty);
            };

            // 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.
            let env_ptr = if !env_ref {
513
                let alloc = bcx.fcx().alloca(common::val_ty(llval), "__debuginfo_env_ptr");
514
                bcx.store(llval, alloc);
515 516 517 518 519
                alloc
            } else {
                llval
            };

M
Mark Simulacrum 已提交
520
            let layout = bcx.ccx.layout_of(closure_ty);
A
Austin Hicks 已提交
521 522 523 524 525
            let offsets = match *layout {
                layout::Univariant { ref variant, .. } => &variant.offsets[..],
                _ => bug!("Closures are only supposed to be Univariant")
            };

526
            for (i, (decl, ty)) in mir.upvar_decls.iter().zip(upvar_tys).enumerate() {
A
Austin Hicks 已提交
527 528
                let byte_offset_of_var_in_env = offsets[i].bytes();

529
                let ops = unsafe {
530 531
                    [llvm::LLVMRustDIBuilderCreateOpDeref(),
                     llvm::LLVMRustDIBuilderCreateOpPlus(),
532
                     byte_offset_of_var_in_env as i64,
533
                     llvm::LLVMRustDIBuilderCreateOpDeref()]
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
                };

                // The environment and the capture can each be indirect.

                // FIXME(eddyb) see above why we have to keep
                // a pointer in an alloca for debuginfo atm.
                let mut ops = if env_ref || true { &ops[..] } else { &ops[1..] };

                let ty = if let (true, &ty::TyRef(_, mt)) = (decl.by_ref, &ty.sty) {
                    mt.ty
                } else {
                    ops = &ops[..ops.len() - 1];
                    ty
                };

                let variable_access = VariableAccess::IndirectVariable {
                    alloca: env_ptr,
                    address_operations: &ops
                };
553 554 555 556 557 558 559 560 561 562
                declare_local(
                    bcx,
                    &mircx.debug_context,
                    decl.debug_name,
                    ty,
                    scope,
                    variable_access,
                    VariableKind::CapturedVariable,
                    DUMMY_SP
                );
563
            }
564
        });
565
        LocalRef::Lvalue(LvalueRef::new_sized(llval, LvalueTy::from_ty(arg_ty)))
566
    }).collect()
567 568
}

569
mod analyze;
570 571 572 573
mod block;
mod constant;
mod lvalue;
mod operand;
574
mod rvalue;
575
mod statement;