mod.rs 25.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// 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.

11
use common::{C_i32, C_null};
12
use libc::c_uint;
M
Mark-Simulacrum 已提交
13
use llvm::{self, ValueRef, BasicBlockRef};
M
Mark-Simulacrum 已提交
14
use llvm::debuginfo::DIScope;
15
use rustc::ty::{self, Ty, TypeFoldable};
16
use rustc::ty::layout::{LayoutOf, TyLayout};
M
Mark-Simulacrum 已提交
17
use rustc::mir::{self, Mir};
18
use rustc::ty::subst::Substs;
19
use rustc::session::config::FullDebugInfo;
20
use base;
21
use builder::Builder;
22
use common::{CodegenCx, Funclet};
M
Mark-Simulacrum 已提交
23
use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
24
use monomorphize::Instance;
25
use abi::{ArgAttribute, ArgTypeExt, FnType, FnTypeExt, PassMode};
26
use type_::Type;
27

28
use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span};
29
use syntax::symbol::keywords;
30

31
use std::iter;
32

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

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

M
Mark Simulacrum 已提交
38
use self::analyze::CleanupKind;
39
use self::place::PlaceRef;
40
use rustc::mir::traversal;
41

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

/// Master context for translating MIR.
45
pub struct FunctionCx<'a, 'tcx:'a> {
O
Oliver Schneider 已提交
46 47
    instance: Instance<'tcx>,

48
    mir: &'a mir::Mir<'tcx>,
49

50
    debug_context: debuginfo::FunctionDebugContext,
51

M
Mark Simulacrum 已提交
52
    llfn: ValueRef,
53

54
    cx: &'a CodegenCx<'a, 'tcx>,
M
Mark Simulacrum 已提交
55

56
    fn_ty: FnType<'tcx, Ty<'tcx>>,
57

58 59 60 61 62 63 64
    /// 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.
65
    personality_slot: Option<PlaceRef<'tcx>>,
66 67

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

70
    /// The funclet status of each basic block
71
    cleanup_kinds: IndexVec<mir::BasicBlock, analyze::CleanupKind>,
72

73 74 75 76
    /// When targeting MSVC, this stores the cleanup info for each funclet
    /// BB. This is initialized as we compute the funclets' head block in RPO.
    funclets: &'a IndexVec<mir::BasicBlock, Option<Funclet>>,

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

81
    /// Cached unreachable block
M
Mark-Simulacrum 已提交
82
    unreachable_block: Option<BasicBlockRef>,
83

84
    /// The location where each MIR arg/var/tmp/ret is stored. This is
85
    /// usually an `PlaceRef` representing an alloca, but not always:
86 87 88 89
    /// 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:
    ///
90
    /// - the type of the local must be judged "immediate" by `is_llvm_immediate`
91 92
    /// - the operand must never be referenced indirectly
    ///     - we should not take its address using the `&` operator
93
    ///     - nor should it appear in a place path like `tmp.a`
94 95
    /// - the operand must be defined by an rvalue that can generate immediate
    ///   values
N
Niko Matsakis 已提交
96 97 98
    ///
    /// Avoiding allocs can also be important for certain intrinsics,
    /// notably `expect`.
99
    locals: IndexVec<mir::Local, LocalRef<'tcx>>,
100 101

    /// Debug information for MIR scopes.
102
    scopes: IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
103 104 105

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

108
impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
109
    pub fn monomorphize<T>(&self, value: &T) -> T
110
        where T: TypeFoldable<'tcx>
111
    {
112 113 114 115 116
        self.cx.tcx.subst_and_normalize_erasing_regions(
            self.param_substs,
            ty::ParamEnv::reveal_all(),
            value,
        )
117 118
    }

119
    pub fn set_debug_loc(&mut self, bx: &Builder, source_info: mir::SourceInfo) {
120
        let (scope, span) = self.debug_loc(source_info);
121
        debuginfo::set_source_location(&self.debug_context, bx, scope, span);
122 123
    }

M
Mark-Simulacrum 已提交
124
    pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> (DIScope, Span) {
125
        // Bail out if debug info emission is not enabled.
126
        match self.debug_context {
127 128
            FunctionDebugContext::DebugInfoDisabled |
            FunctionDebugContext::FunctionWithoutDebugInfo => {
M
Mark-Simulacrum 已提交
129
                return (self.scopes[source_info.scope].scope_metadata, source_info.span);
130 131 132 133 134 135 136
            }
            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`).
137
        if source_info.span.ctxt() == NO_EXPANSION ||
138
           self.cx.sess().opts.debugging_opts.debug_macros {
139
            let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo());
140
            (scope, source_info.span)
141 142
        } else {
            // Walk up the macro expansion chain until we reach a non-expanded span.
B
Bastien Orivel 已提交
143
            // We also stop at the function body level because no line stepping can occur
V
Vadim Chugunov 已提交
144
            // at the level above that.
145
            let mut span = source_info.span;
146 147
            while span.ctxt() != NO_EXPANSION && span.ctxt() != self.mir.span.ctxt() {
                if let Some(info) = span.ctxt().outer().expn_info() {
148
                    span = info.call_site;
149 150 151 152
                } else {
                    break;
                }
            }
153
            let scope = self.scope_metadata_for_loc(source_info.scope, span.lo());
154
            // Use span of the outermost expansion site, while keeping the original lexical scope.
155
            (scope, span)
156 157 158 159 160 161 162 163 164 165 166 167
        }
    }

    // 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 {
168
            let cm = self.cx.sess().codemap();
169
            let defining_crate = self.debug_context.get_ref(DUMMY_SP).defining_crate;
170
            debuginfo::extend_scope_to_file(self.cx,
171 172 173
                                            scope_metadata,
                                            &cm.lookup_char_pos(pos).file,
                                            defining_crate)
174 175 176
        } else {
            scope_metadata
        }
177 178 179
    }
}

180
enum LocalRef<'tcx> {
181
    Place(PlaceRef<'tcx>),
182 183 184
    Operand(Option<OperandRef<'tcx>>),
}

185
impl<'a, 'tcx> LocalRef<'tcx> {
186
    fn new_operand(cx: &CodegenCx<'a, 'tcx>, layout: TyLayout<'tcx>) -> LocalRef<'tcx> {
187
        if layout.is_zst() {
188 189 190
            // Zero-size temporaries aren't always initialized, which
            // doesn't matter because they don't contain data, but
            // we need something in the operand.
191
            LocalRef::Operand(Some(OperandRef::new_zst(cx, layout)))
192
        } else {
193
            LocalRef::Operand(None)
194
        }
J
James Miller 已提交
195 196 197
    }
}

198 199
///////////////////////////////////////////////////////////////////////////

200
pub fn trans_mir<'a, 'tcx: 'a>(
201
    cx: &'a CodegenCx<'a, 'tcx>,
M
Mark Simulacrum 已提交
202
    llfn: ValueRef,
203 204
    mir: &'a Mir<'tcx>,
    instance: Instance<'tcx>,
205
    sig: ty::FnSig<'tcx>,
206
) {
207
    let fn_ty = FnType::new(cx, sig, &[]);
208
    debug!("fn_ty: {:?}", fn_ty);
209
    let debug_context =
210
        debuginfo::create_function_debug_context(cx, instance, sig, llfn, mir);
211
    let bx = Builder::new_block(cx, llfn, "start");
212

213
    if mir.basic_blocks().iter().any(|bb| bb.is_cleanup) {
214
        bx.set_personality_fn(cx.eh_personality());
215
    }
216

217
    let cleanup_kinds = analyze::cleanup_kinds(&mir);
218 219 220
    // Allocate a `Block` for every basic block, except
    // the start block, if nothing loops back to it.
    let reentrant_start_block = !mir.predecessors_for(mir::START_BLOCK).is_empty();
221
    let block_bxs: IndexVec<mir::BasicBlock, BasicBlockRef> =
222
        mir.basic_blocks().indices().map(|bb| {
223
            if bb == mir::START_BLOCK && !reentrant_start_block {
224
                bx.llbb()
225
            } else {
226
                bx.build_sibling_block(&format!("{:?}", bb)).llbb()
227 228 229
            }
        }).collect();

230
    // Compute debuginfo scopes from MIR scopes.
231
    let scopes = debuginfo::create_mir_scopes(cx, mir, &debug_context);
232
    let (landing_pads, funclets) = create_funclets(mir, &bx, &cleanup_kinds, &block_bxs);
233

234
    let mut fx = FunctionCx {
O
Oliver Schneider 已提交
235
        instance,
236 237 238
        mir,
        llfn,
        fn_ty,
239
        cx,
240
        personality_slot: None,
241
        blocks: block_bxs,
242
        unreachable_block: None,
243 244
        cleanup_kinds,
        landing_pads,
245
        funclets: &funclets,
246
        scopes,
247
        locals: IndexVec::new(),
248
        debug_context,
249 250 251 252
        param_substs: {
            assert!(!instance.substs.needs_infer());
            instance.substs
        },
253 254
    };

255
    let memory_locals = analyze::non_ssa_locals(&fx);
256

257
    // Allocate variable and temp allocas
258 259
    fx.locals = {
        let args = arg_local_refs(&bx, &fx, &fx.scopes, &memory_locals);
260 261 262

        let mut allocate_local = |local| {
            let decl = &mir.local_decls[local];
263
            let layout = bx.cx.layout_of(fx.monomorphize(&decl.ty));
264
            assert!(!layout.ty.has_erasable_regions());
265

266 267
            if let Some(name) = decl.name {
                // User variable
268
                let debug_scope = fx.scopes[decl.source_info.scope];
269
                let dbg = debug_scope.is_valid() && bx.sess().opts.debuginfo == FullDebugInfo;
270

271
                if !memory_locals.contains(local.index()) && !dbg {
272
                    debug!("alloc: {:?} ({}) -> operand", local, name);
273
                    return LocalRef::new_operand(bx.cx, layout);
274
                }
275

276
                debug!("alloc: {:?} ({}) -> place", local, name);
277
                let place = PlaceRef::alloca(&bx, layout, &name.as_str());
278
                if dbg {
279 280
                    let (scope, span) = fx.debug_loc(decl.source_info);
                    declare_local(&bx, &fx.debug_context, name, layout.ty, scope,
281
                        VariableAccess::DirectVariable { alloca: place.llval },
M
Mark-Simulacrum 已提交
282
                        VariableKind::LocalVariable, span);
283
                }
284
                LocalRef::Place(place)
285
            } else {
286
                // Temporary or return place
287
                if local == mir::RETURN_PLACE && fx.fn_ty.ret.is_indirect() {
288
                    debug!("alloc: {:?} (return place) -> place", local);
M
Mark Simulacrum 已提交
289
                    let llretptr = llvm::get_param(llfn, 0);
290
                    LocalRef::Place(PlaceRef::new_sized(llretptr, layout, layout.align))
291 292
                } else if memory_locals.contains(local.index()) {
                    debug!("alloc: {:?} -> place", local);
293
                    LocalRef::Place(PlaceRef::alloca(&bx, layout, &format!("{:?}", local)))
294 295 296 297 298
                } 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);
299
                    LocalRef::new_operand(bx.cx, layout)
300
                }
301
            }
302 303
        };

304
        let retptr = allocate_local(mir::RETURN_PLACE);
305 306
        iter::once(retptr)
            .chain(args.into_iter())
307
            .chain(mir.vars_and_temps_iter().map(allocate_local))
308
            .collect()
309
    };
310

311 312
    // Branch to the START block, if it's not the entry block.
    if reentrant_start_block {
313
        bx.br(fx.blocks[mir::START_BLOCK]);
314
    }
315

316 317 318
    // 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.
319
    debuginfo::start_emitting_source_locations(&fx.debug_context);
320

M
Mark Simulacrum 已提交
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());
327
        fx.trans_block(bb);
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
            unsafe {
337
                llvm::LLVMDeleteBasicBlock(fx.blocks[bb]);
338
            }
339 340
        }
    }
341 342
}

343
fn create_funclets<'a, 'tcx>(
344
    mir: &'a Mir<'tcx>,
345
    bx: &Builder<'a, 'tcx>,
346
    cleanup_kinds: &IndexVec<mir::BasicBlock, CleanupKind>,
347
    block_bxs: &IndexVec<mir::BasicBlock, BasicBlockRef>)
348 349 350
    -> (IndexVec<mir::BasicBlock, Option<BasicBlockRef>>,
        IndexVec<mir::BasicBlock, Option<Funclet>>)
{
351
    block_bxs.iter_enumerated().zip(cleanup_kinds).map(|((bb, &llbb), cleanup_kind)| {
352
        match *cleanup_kind {
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
            CleanupKind::Funclet if base::wants_msvc_seh(bx.sess()) => {}
            _ => return (None, None)
        }

        let cleanup;
        let ret_llbb;
        match mir[bb].terminator.as_ref().map(|t| &t.kind) {
            // This is a basic block that we're aborting the program for,
            // notably in an `extern` function. These basic blocks are inserted
            // so that we assert that `extern` functions do indeed not panic,
            // and if they do we abort the process.
            //
            // On MSVC these are tricky though (where we're doing funclets). If
            // we were to do a cleanuppad (like below) the normal functions like
            // `longjmp` would trigger the abort logic, terminating the
            // program. Instead we insert the equivalent of `catch(...)` for C++
            // which magically doesn't trigger when `longjmp` files over this
            // frame.
            //
            // Lots more discussion can be found on #48251 but this codegen is
            // modeled after clang's for:
            //
            //      try {
            //          foo();
            //      } catch (...) {
            //          bar();
            //      }
            Some(&mir::TerminatorKind::Abort) => {
                let cs_bx = bx.build_sibling_block(&format!("cs_funclet{:?}", bb));
                let cp_bx = bx.build_sibling_block(&format!("cp_funclet{:?}", bb));
                ret_llbb = cs_bx.llbb();

                let cs = cs_bx.catch_switch(None, None, 1);
                cs_bx.add_handler(cs, cp_bx.llbb());

                // The "null" here is actually a RTTI type descriptor for the
                // C++ personality function, but `catch (...)` has no type so
                // it's null. The 64 here is actually a bitfield which
                // represents that this is a catch-all block.
                let null = C_null(Type::i8p(bx.cx));
                let sixty_four = C_i32(bx.cx, 64);
                cleanup = cp_bx.catch_pad(cs, &[null, sixty_four, null]);
                cp_bx.br(llbb);
            }
            _ => {
398
                let cleanup_bx = bx.build_sibling_block(&format!("funclet_{:?}", bb));
399 400
                ret_llbb = cleanup_bx.llbb();
                cleanup = cleanup_bx.cleanup_pad(None, &[]);
401
                cleanup_bx.br(llbb);
402
            }
403 404 405
        };

        (Some(ret_llbb), Some(Funclet::new(cleanup)))
406 407 408
    }).unzip()
}

409
/// Produce, for each argument, a `ValueRef` pointing at the
410
/// argument's value. As arguments are places, these are always
411
/// indirect.
412
fn arg_local_refs<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
413
                            fx: &FunctionCx<'a, 'tcx>,
M
Mark Simulacrum 已提交
414
                            scopes: &IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
415
                            memory_locals: &BitVector)
M
Mark Simulacrum 已提交
416
                            -> Vec<LocalRef<'tcx>> {
417
    let mir = fx.mir;
418
    let tcx = bx.tcx();
419
    let mut idx = 0;
420
    let mut llarg_idx = fx.fn_ty.ret.is_indirect() as usize;
421

422
    // Get the argument scope, if it exists and if we need it.
423
    let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE];
424
    let arg_scope = if arg_scope.is_valid() && bx.sess().opts.debuginfo == FullDebugInfo {
425
        Some(arg_scope.scope_metadata)
426 427 428
    } else {
        None
    };
429

430 431 432 433
    let deref_op = unsafe {
        [llvm::LLVMRustDIBuilderCreateOpDeref()]
    };

434
    mir.args_iter().enumerate().map(|(arg_index, local)| {
435
        let arg_decl = &mir.local_decls[local];
436

437 438 439 440 441 442
        let name = if let Some(name) = arg_decl.name {
            name.as_str().to_string()
        } else {
            format!("arg{}", arg_index)
        };

J
Jonas Schievink 已提交
443 444 445 446 447 448
        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.

449
            let arg_ty = fx.monomorphize(&arg_decl.ty);
J
Jonas Schievink 已提交
450
            let tupled_arg_tys = match arg_ty.sty {
A
Andrew Cann 已提交
451
                ty::TyTuple(ref tys) => tys,
J
Jonas Schievink 已提交
452 453
                _ => bug!("spread argument isn't a tuple?!")
            };
454

455
            let place = PlaceRef::alloca(bx, bx.cx.layout_of(arg_ty), &name);
456
            for i in 0..tupled_arg_tys.len() {
457
                let arg = &fx.fn_ty.args[idx];
J
Jonas Schievink 已提交
458
                idx += 1;
459 460 461
                if arg.pad.is_some() {
                    llarg_idx += 1;
                }
462
                arg.store_fn_arg(bx, &mut llarg_idx, place.project_field(bx, i));
463
            }
464 465 466

            // Now that we have one alloca that contains the aggregate value,
            // we can create one debuginfo entry for the argument.
467
            arg_scope.map(|scope| {
468
                let variable_access = VariableAccess::DirectVariable {
469
                    alloca: place.llval
470
                };
471
                declare_local(
472
                    bx,
473
                    &fx.debug_context,
474 475 476 477 478 479
                    arg_decl.name.unwrap_or(keywords::Invalid.name()),
                    arg_ty, scope,
                    variable_access,
                    VariableKind::ArgumentVariable(arg_index + 1),
                    DUMMY_SP
                );
480
            });
481

482
            return LocalRef::Place(place);
483 484
        }

485
        let arg = &fx.fn_ty.args[idx];
486
        idx += 1;
487
        if arg.pad.is_some() {
488
            llarg_idx += 1;
489
        }
490

491
        if arg_scope.is_none() && !memory_locals.contains(local.index()) {
492 493 494
            // 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.
495 496 497
            let local = |op| LocalRef::Operand(Some(op));
            match arg.mode {
                PassMode::Ignore => {
498
                    return local(OperandRef::new_zst(bx.cx, arg.layout));
499 500
                }
                PassMode::Direct(_) => {
501 502
                    let llarg = llvm::get_param(bx.llfn(), llarg_idx as c_uint);
                    bx.set_value_name(llarg, &name);
503 504
                    llarg_idx += 1;
                    return local(
505
                        OperandRef::from_immediate_or_packed_pair(bx, llarg, arg.layout));
506 507
                }
                PassMode::Pair(..) => {
508 509
                    let a = llvm::get_param(bx.llfn(), llarg_idx as c_uint);
                    bx.set_value_name(a, &(name.clone() + ".0"));
510 511
                    llarg_idx += 1;

512 513
                    let b = llvm::get_param(bx.llfn(), llarg_idx as c_uint);
                    bx.set_value_name(b, &(name + ".1"));
514 515 516 517 518 519 520 521
                    llarg_idx += 1;

                    return local(OperandRef {
                        val: OperandValue::Pair(a, b),
                        layout: arg.layout
                    });
                }
                _ => {}
522
            }
523 524
        }

525
        let place = if arg.is_indirect() {
526 527 528
            // Don't copy an indirect argument to an alloca, the caller
            // already put it in a temporary alloca and gave it up.
            // FIXME: lifetimes
529 530
            let llarg = llvm::get_param(bx.llfn(), llarg_idx as c_uint);
            bx.set_value_name(llarg, &name);
531
            llarg_idx += 1;
532
            PlaceRef::new_sized(llarg, arg.layout, arg.layout.align)
533
        } else {
534 535
            let tmp = PlaceRef::alloca(bx, arg.layout, &name);
            arg.store_fn_arg(bx, &mut llarg_idx, tmp);
536
            tmp
537
        };
538
        arg_scope.map(|scope| {
539 540
            // Is this a regular argument?
            if arg_index > 0 || mir.upvar_decls.is_empty() {
541 542 543
                // The Rust ABI passes indirect variables using a pointer and a manual copy, so we
                // need to insert a deref here, but the C ABI uses a pointer and a copy using the
                // byval attribute, for which LLVM does the deref itself, so we must not add it.
544
                // Starting with D31439 in LLVM 5, it *always* does the deref itself.
545
                let mut variable_access = VariableAccess::DirectVariable {
546
                    alloca: place.llval
547
                };
548 549 550 551 552 553 554 555
                if unsafe { llvm::LLVMRustVersionMajor() < 5 } {
                    if let PassMode::Indirect(ref attrs) = arg.mode {
                        if !attrs.contains(ArgAttribute::ByVal) {
                            variable_access = VariableAccess::IndirectVariable {
                                alloca: place.llval,
                                address_operations: &deref_op,
                            };
                        }
556 557 558
                    }
                }

559
                declare_local(
560
                    bx,
561
                    &fx.debug_context,
562
                    arg_decl.name.unwrap_or(keywords::Invalid.name()),
563
                    arg.layout.ty,
564
                    scope,
565
                    variable_access,
566 567 568
                    VariableKind::ArgumentVariable(arg_index + 1),
                    DUMMY_SP
                );
569 570 571 572
                return;
            }

            // Or is it the closure environment?
573
            let (closure_layout, env_ref) = match arg.layout.ty.sty {
574
                ty::TyRef(_, mt) | ty::TyRawPtr(mt) => (bx.cx.layout_of(mt.ty), true),
575
                _ => (arg.layout, false)
576
            };
A
Alex Crichton 已提交
577

578
            let upvar_tys = match closure_layout.ty.sty {
J
John Kåre Alsaker 已提交
579 580
                ty::TyClosure(def_id, substs) |
                ty::TyGenerator(def_id, substs, _) => substs.upvar_tys(def_id, tcx),
581
                _ => bug!("upvar_decls with non-closure arg0 type `{}`", closure_layout.ty)
582 583 584 585 586 587 588 589 590 591
            };

            // 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 {
592 593
                let scratch = PlaceRef::alloca(bx,
                    bx.cx.layout_of(tcx.mk_mut_ptr(arg.layout.ty)),
594
                    "__debuginfo_env_ptr");
595
                bx.store(place.llval, scratch.llval, scratch.align);
596
                scratch.llval
597
            } else {
598
                place.llval
599 600 601
            };

            for (i, (decl, ty)) in mir.upvar_decls.iter().zip(upvar_tys).enumerate() {
602
                let byte_offset_of_var_in_env = closure_layout.fields.offset(i).bytes();
A
Austin Hicks 已提交
603

604
                let ops = unsafe {
605
                    [llvm::LLVMRustDIBuilderCreateOpDeref(),
606
                     llvm::LLVMRustDIBuilderCreateOpPlusUconst(),
607
                     byte_offset_of_var_in_env as i64,
608
                     llvm::LLVMRustDIBuilderCreateOpDeref()]
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
                };

                // 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
                };
628
                declare_local(
629
                    bx,
630
                    &fx.debug_context,
631 632 633 634 635 636 637
                    decl.debug_name,
                    ty,
                    scope,
                    variable_access,
                    VariableKind::CapturedVariable,
                    DUMMY_SP
                );
638
            }
639
        });
640
        LocalRef::Place(place)
641
    }).collect()
642 643
}

644
mod analyze;
645 646
mod block;
mod constant;
647
pub mod place;
648
pub mod operand;
649
mod rvalue;
650
mod statement;