expr.rs 112.2 KB
Newer Older
1
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10
// 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.

S
Steve Klabnik 已提交
11 12
//! # Translation of Expressions
//!
S
Steve Klabnik 已提交
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
//! The expr module handles translation of expressions. The most general
//! translation routine is `trans()`, which will translate an expression
//! into a datum. `trans_into()` is also available, which will translate
//! an expression and write the result directly into memory, sometimes
//! avoiding the need for a temporary stack slot. Finally,
//! `trans_to_lvalue()` is available if you'd like to ensure that the
//! result has cleanup scheduled.
//!
//! Internally, each of these functions dispatches to various other
//! expression functions depending on the kind of expression. We divide
//! up expressions into:
//!
//! - **Datum expressions:** Those that most naturally yield values.
//!   Examples would be `22`, `box x`, or `a + b` (when not overloaded).
//! - **DPS expressions:** Those that most naturally write into a location
//!   in memory. Examples would be `foo()` or `Point { x: 3, y: 4 }`.
//! - **Statement expressions:** That that do not generate a meaningful
//!   result. Examples would be `while { ... }` or `return 44`.
//!
S
Steve Klabnik 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
//! Public entry points:
//!
//! - `trans_into(bcx, expr, dest) -> bcx`: evaluates an expression,
//!   storing the result into `dest`. This is the preferred form, if you
//!   can manage it.
//!
//! - `trans(bcx, expr) -> DatumBlock`: evaluates an expression, yielding
//!   `Datum` with the result. You can then store the datum, inspect
//!   the value, etc. This may introduce temporaries if the datum is a
//!   structural type.
//!
//! - `trans_to_lvalue(bcx, expr, "...") -> DatumBlock`: evaluates an
//!   expression and ensures that the result has a cleanup associated with it,
//!   creating a temporary stack slot if necessary.
//!
//! - `trans_local_var -> Datum`: looks up a local variable or upvar.
48

49
#![allow(non_camel_case_types)]
50

S
Steven Fackler 已提交
51 52 53
pub use self::Dest::*;
use self::lazy_binop_ty::*;

54
use back::abi;
55
use llvm::{self, ValueRef, TypeKind};
56
use middle::check_const;
57
use middle::def;
N
Nick Cameron 已提交
58
use middle::lang_items::CoerceUnsizedTraitLangItem;
N
Nick Cameron 已提交
59
use middle::subst::{Substs, VecPerParamSpace};
N
Nick Cameron 已提交
60
use middle::traits;
61
use trans::{_match, adt, asm, base, callee, closure, consts, controlflow};
62 63
use trans::base::*;
use trans::build::*;
64
use trans::cleanup::{self, CleanupMethods, DropHintMethods};
65 66
use trans::common::*;
use trans::datum::*;
67
use trans::debuginfo::{self, DebugLoc, ToDebugLoc};
68
use trans::declare;
69 70 71 72 73
use trans::glue;
use trans::machine;
use trans::meth;
use trans::tvec;
use trans::type_of;
74 75
use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
use middle::ty::adjustment::{AdjustUnsafeFnPointer, CustomCoerceUnsized};
76
use middle::ty::{self, Ty};
77
use middle::ty::MethodCall;
78
use middle::ty::cast::{CastKind, CastTy};
79
use util::common::indenter;
80 81
use trans::machine::{llsize_of, llsize_of_alloc};
use trans::type_::Type;
J
James Miller 已提交
82

83 84 85
use rustc_front;
use rustc_front::hir;

86
use syntax::{ast, ast_util, codemap};
87
use syntax::parse::token::InternedString;
88
use syntax::ptr::P;
N
Nick Cameron 已提交
89
use syntax::parse::token;
90
use std::mem;
91

92 93 94 95 96
// Destinations

// These are passed around by the code generating functions to track the
// destination of a computation's value.

N
Niko Matsakis 已提交
97
#[derive(Copy, Clone, PartialEq)]
98
pub enum Dest {
99 100 101 102
    SaveIn(ValueRef),
    Ignore,
}

103
impl Dest {
104
    pub fn to_string(&self, ccx: &CrateContext) -> String {
B
Ben Striegel 已提交
105
        match *self {
106
            SaveIn(v) => format!("SaveIn({})", ccx.tn().val_to_string(v)),
107
            Ignore => "Ignore".to_string()
108 109 110 111
        }
    }
}

S
Steve Klabnik 已提交
112 113
/// This function is equivalent to `trans(bcx, expr).store_to_dest(dest)` but it may generate
/// better optimized LLVM code.
114
pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
115
                              expr: &hir::Expr,
116 117
                              dest: Dest)
                              -> Block<'blk, 'tcx> {
118 119
    let mut bcx = bcx;

120 121
    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);

122
    if adjustment_required(bcx, expr) {
123 124 125
        // use trans, which may be less efficient but
        // which will perform the adjustments:
        let datum = unpack_datum!(bcx, trans(bcx, expr));
126 127 128
        return datum.store_to_dest(bcx, dest, expr.id);
    }

129
    let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
T
Fallout  
Tamir Duberstein 已提交
130 131 132 133 134
    if !qualif.intersects(
        check_const::ConstQualif::NOT_CONST |
        check_const::ConstQualif::NEEDS_DROP
    ) {
        if !qualif.intersects(check_const::ConstQualif::PREFER_IN_PLACE) {
135 136 137 138 139 140 141
            if let SaveIn(lldest) = dest {
                let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
                                                            bcx.fcx.param_substs);
                // Cast pointer to destination, because constants
                // have different types.
                let lldest = PointerCast(bcx, lldest, val_ty(global));
                memcpy_ty(bcx, lldest, global, expr_ty_adjusted(bcx, expr));
142
                return bcx;
143
            }
144 145 146 147
            // Even if we don't have a value to emit, and the expression
            // doesn't have any side-effects, we still have to translate the
            // body of any closures.
            // FIXME: Find a better way of handling this case.
148 149 150 151 152
        } else {
            // The only way we're going to see a `const` at this point is if
            // it prefers in-place instantiation, likely because it contains
            // `[x; N]` somewhere within.
            match expr.node {
153
                hir::ExprPath(..) => {
154 155
                    match bcx.def(expr.id) {
                        def::DefConst(did) => {
156
                            let const_expr = consts::get_const_expr(bcx.ccx(), did, expr);
157 158 159 160 161 162 163
                            // Temporarily get cleanup scopes out of the way,
                            // as they require sub-expressions to be contained
                            // inside the current AST scope.
                            // These should record no cleanups anyways, `const`
                            // can't have destructors.
                            let scopes = mem::replace(&mut *bcx.fcx.scopes.borrow_mut(),
                                                      vec![]);
164 165 166 167 168 169 170
                            // Lock emitted debug locations to the location of
                            // the constant reference expression.
                            debuginfo::with_source_location_override(bcx.fcx,
                                                                     expr.debug_loc(),
                                                                     || {
                                bcx = trans_into(bcx, const_expr, dest)
                            });
171 172 173 174 175 176 177 178 179 180 181
                            let scopes = mem::replace(&mut *bcx.fcx.scopes.borrow_mut(),
                                                      scopes);
                            assert!(scopes.is_empty());
                            return bcx;
                        }
                        _ => {}
                    }
                }
                _ => {}
            }
        }
182 183
    }

184
    debug!("trans_into() expr={:?}", expr);
185

186 187
    let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
                                                                          expr.id,
188 189 190
                                                                          expr.span,
                                                                          false);
    bcx.fcx.push_ast_cleanup_scope(cleanup_debug_loc);
191

A
Ariel Ben-Yehuda 已提交
192
    let kind = expr_kind(bcx.tcx(), expr);
193
    bcx = match kind {
A
Ariel Ben-Yehuda 已提交
194
        ExprKind::Lvalue | ExprKind::RvalueDatum => {
195 196
            trans_unadjusted(bcx, expr).store_to_dest(dest, expr.id)
        }
A
Ariel Ben-Yehuda 已提交
197
        ExprKind::RvalueDps => {
198 199
            trans_rvalue_dps_unadjusted(bcx, expr, dest)
        }
A
Ariel Ben-Yehuda 已提交
200
        ExprKind::RvalueStmt => {
201 202 203 204 205 206 207
            trans_rvalue_stmt_unadjusted(bcx, expr)
        }
    };

    bcx.fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id)
}

S
Steve Klabnik 已提交
208 209 210
/// Translates an expression, returning a datum (and new block) encapsulating the result. When
/// possible, it is preferred to use `trans_into`, as that may avoid creating a temporary on the
/// stack.
211
pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
212
                         expr: &hir::Expr)
213
                         -> DatumBlock<'blk, 'tcx, Expr> {
214
    debug!("trans(expr={:?})", expr);
N
Niko Matsakis 已提交
215

216
    let mut bcx = bcx;
217
    let fcx = bcx.fcx;
218
    let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
T
Fallout  
Tamir Duberstein 已提交
219 220 221 222 223
    let adjusted_global = !qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS);
    let global = if !qualif.intersects(
        check_const::ConstQualif::NOT_CONST |
        check_const::ConstQualif::NEEDS_DROP
    ) {
224 225 226
        let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
                                                      bcx.fcx.param_substs);

T
Fallout  
Tamir Duberstein 已提交
227
        if qualif.intersects(check_const::ConstQualif::HAS_STATIC_BORROWS) {
228 229 230 231 232 233
            // Is borrowed as 'static, must return lvalue.

            // Cast pointer to global, because constants have different types.
            let const_ty = expr_ty_adjusted(bcx, expr);
            let llty = type_of::type_of(bcx.ccx(), const_ty);
            let global = PointerCast(bcx, global, llty.ptr_to());
234
            let datum = Datum::new(global, const_ty, Lvalue::new("expr::trans"));
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
            return DatumBlock::new(bcx, datum.to_expr_datum());
        }

        // Otherwise, keep around and perform adjustments, if needed.
        let const_ty = if adjusted_global {
            expr_ty_adjusted(bcx, expr)
        } else {
            expr_ty(bcx, expr)
        };

        // This could use a better heuristic.
        Some(if type_is_immediate(bcx.ccx(), const_ty) {
            // Cast pointer to global, because constants have different types.
            let llty = type_of::type_of(bcx.ccx(), const_ty);
            let global = PointerCast(bcx, global, llty.ptr_to());
            // Maybe just get the value directly, instead of loading it?
            immediate_rvalue(load_ty(bcx, global, const_ty), const_ty)
        } else {
253
            let scratch = alloc_ty(bcx, const_ty, "const");
254
            call_lifetime_start(bcx, scratch);
255
            let lldest = if !const_ty.is_structural() {
256 257 258 259 260 261 262 263 264 265 266 267 268
                // Cast pointer to slot, because constants have different types.
                PointerCast(bcx, scratch, val_ty(global))
            } else {
                // In this case, memcpy_ty calls llvm.memcpy after casting both
                // source and destination to i8*, so we don't need any casts.
                scratch
            };
            memcpy_ty(bcx, lldest, global, const_ty);
            Datum::new(scratch, const_ty, Rvalue::new(ByRef))
        })
    } else {
        None
    };
269

270 271
    let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
                                                                          expr.id,
272 273 274
                                                                          expr.span,
                                                                          false);
    fcx.push_ast_cleanup_scope(cleanup_debug_loc);
275 276 277 278 279 280 281 282 283
    let datum = match global {
        Some(rvalue) => rvalue.to_expr_datum(),
        None => unpack_datum!(bcx, trans_unadjusted(bcx, expr))
    };
    let datum = if adjusted_global {
        datum // trans::consts already performed adjustments.
    } else {
        unpack_datum!(bcx, apply_adjustments(bcx, expr, datum))
    };
284
    bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id);
K
Kevin Butler 已提交
285
    return DatumBlock::new(bcx, datum);
286 287
}

288
pub fn get_meta(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
289
    StructGEP(bcx, fat_ptr, abi::FAT_PTR_EXTRA)
N
Nick Cameron 已提交
290 291
}

292
pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
293
    StructGEP(bcx, fat_ptr, abi::FAT_PTR_ADDR)
N
Nick Cameron 已提交
294 295
}

296 297
pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) {
    Store(bcx, Load(bcx, get_dataptr(bcx, src_ptr)), get_dataptr(bcx, dst_ptr));
298
    Store(bcx, Load(bcx, get_meta(bcx, src_ptr)), get_meta(bcx, dst_ptr));
299 300
}

301 302 303 304 305 306 307 308 309 310
/// Retrieve the information we are losing (making dynamic) in an unsizing
/// adjustment.
///
/// The `old_info` argument is a bit funny. It is intended for use
/// in an upcast, where the new vtable for an object will be drived
/// from the old one.
pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
                                source: Ty<'tcx>,
                                target: Ty<'tcx>,
                                old_info: Option<ValueRef>,
N
Nick Cameron 已提交
311
                                param_substs: &'tcx Substs<'tcx>)
312
                                -> ValueRef {
313
    let (source, target) = ccx.tcx().struct_lockstep_tails(source, target);
314
    match (&source.sty, &target.sty) {
315
        (&ty::TyArray(_, len), &ty::TySlice(_)) => C_uint(ccx, len),
316
        (&ty::TyTrait(_), &ty::TyTrait(_)) => {
317 318 319 320 321
            // For now, upcasts are limited to changes in marker
            // traits, and hence never actually require an actual
            // change to the vtable.
            old_info.expect("unsized_info: missing old info for trait upcast")
        }
322
        (_, &ty::TyTrait(box ty::TraitTy { ref principal, .. })) => {
323
            // Note that we preserve binding levels here:
324
            let substs = principal.0.substs.with_self_ty(source).erase_regions();
325
            let substs = ccx.tcx().mk_substs(substs);
326 327
            let trait_ref = ty::Binder(ty::TraitRef { def_id: principal.def_id(),
                                                      substs: substs });
328
            consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs),
329 330
                            Type::vtable_ptr(ccx))
        }
331 332 333
        _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {:?} -> {:?}",
                                     source,
                                     target))
334 335 336
    }
}

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                   expr: &hir::Expr) -> bool {
    let adjustment = match bcx.tcx().tables.borrow().adjustments.get(&expr.id).cloned() {
        None => { return false; }
        Some(adj) => adj
    };

    // Don't skip a conversion from Box<T> to &T, etc.
    if bcx.tcx().is_overloaded_autoderef(expr.id, 0) {
        return true;
    }

    match adjustment {
        AdjustReifyFnPointer => {
            // FIXME(#19925) once fn item types are
            // zero-sized, we'll need to return true here
            false
        }
        AdjustUnsafeFnPointer => {
            // purely a type-level thing
            false
        }
        AdjustDerefRef(ref adj) => {
            // We are a bit paranoid about adjustments and thus might have a re-
            // borrow here which merely derefs and then refs again (it might have
            // a different region or mutability, but we don't care here).
            !(adj.autoderefs == 1 && adj.autoref.is_some() && adj.unsize.is_none())
        }
    }
}

S
Steve Klabnik 已提交
368 369
/// Helper for trans that apply adjustments from `expr` to `datum`, which should be the unadjusted
/// translation of `expr`.
370
fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
371
                                 expr: &hir::Expr,
372
                                 datum: Datum<'tcx, Expr>)
373 374
                                 -> DatumBlock<'blk, 'tcx, Expr>
{
375 376
    let mut bcx = bcx;
    let mut datum = datum;
377
    let adjustment = match bcx.tcx().tables.borrow().adjustments.get(&expr.id).cloned() {
378
        None => {
K
Kevin Butler 已提交
379
            return DatumBlock::new(bcx, datum);
380
        }
381
        Some(adj) => { adj }
382
    };
383 384
    debug!("unadjusted datum for expr {:?}: {} adjustment={:?}",
           expr,
385
           datum.to_string(bcx.ccx()),
386
           adjustment);
387
    match adjustment {
388
        AdjustReifyFnPointer => {
389 390
            // FIXME(#19925) once fn item types are
            // zero-sized, we'll need to do something here
391
        }
392 393 394
        AdjustUnsafeFnPointer => {
            // purely a type-level thing
        }
395
        AdjustDerefRef(ref adj) => {
396
            let skip_reborrows = if adj.autoderefs == 1 && adj.autoref.is_some() {
397 398
                // We are a bit paranoid about adjustments and thus might have a re-
                // borrow here which merely derefs and then refs again (it might have
399 400 401
                // a different region or mutability, but we don't care here).
                match datum.ty.sty {
                    // Don't skip a conversion from Box<T> to &T, etc.
402
                    ty::TyRef(..) => {
403
                        if bcx.tcx().is_overloaded_autoderef(expr.id, 0) {
404 405 406 407
                            // Don't skip an overloaded deref.
                            0
                        } else {
                            1
408 409
                        }
                    }
410
                    _ => 0
411
                }
412 413
            } else {
                0
N
Nick Cameron 已提交
414 415
            };

416
            if adj.autoderefs > skip_reborrows {
417 418
                // Schedule cleanup.
                let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id));
419 420 421
                datum = unpack_datum!(bcx, deref_multiple(bcx, expr,
                                                          lval.to_expr_datum(),
                                                          adj.autoderefs - skip_reborrows));
422 423
            }

424
            // (You might think there is a more elegant way to do this than a
425 426
            // skip_reborrows bool, but then you remember that the borrow checker exists).
            if skip_reborrows == 0 && adj.autoref.is_some() {
427
                datum = unpack_datum!(bcx, auto_ref(bcx, datum, expr));
428 429 430
            }

            if let Some(target) = adj.unsize {
N
Nick Cameron 已提交
431 432 433 434 435 436 437 438 439 440
                // We do not arrange cleanup ourselves; if we already are an
                // L-value, then cleanup will have already been scheduled (and
                // the `datum.to_rvalue_datum` call below will emit code to zero
                // the drop flag when moving out of the L-value). If we are an
                // R-value, then we do not need to schedule cleanup.
                let source_datum = unpack_datum!(bcx,
                    datum.to_rvalue_datum(bcx, "__coerce_source"));

                let target = bcx.monomorphize(&target);

441
                let scratch = alloc_ty(bcx, target, "__coerce_target");
442
                call_lifetime_start(bcx, scratch);
N
Nick Cameron 已提交
443 444 445 446 447
                let target_datum = Datum::new(scratch, target,
                                              Rvalue::new(ByRef));
                bcx = coerce_unsized(bcx, expr.span, source_datum, target_datum);
                datum = Datum::new(scratch, target,
                                   RvalueExpr(Rvalue::new(ByRef)));
N
Nick Cameron 已提交
448
            }
449
        }
450
    }
451
    debug!("after adjustments, datum={}", datum.to_string(bcx.ccx()));
N
Nick Cameron 已提交
452 453
    DatumBlock::new(bcx, datum)
}
454

N
Nick Cameron 已提交
455 456 457 458 459 460 461 462 463 464 465
fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                              span: codemap::Span,
                              source: Datum<'tcx, Rvalue>,
                              target: Datum<'tcx, Rvalue>)
                              -> Block<'blk, 'tcx> {
    let mut bcx = bcx;
    debug!("coerce_unsized({} -> {})",
           source.to_string(bcx.ccx()),
           target.to_string(bcx.ccx()));

    match (&source.ty.sty, &target.ty.sty) {
466
        (&ty::TyBox(a), &ty::TyBox(b)) |
J
Jared Roesch 已提交
467 468 469 470 471 472
        (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }),
         &ty::TyRef(_, ty::TypeAndMut { ty: b, .. })) |
        (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }),
         &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) |
        (&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }),
         &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => {
N
Nick Cameron 已提交
473 474 475 476 477 478 479 480 481 482
            let (inner_source, inner_target) = (a, b);

            let (base, old_info) = if !type_is_sized(bcx.tcx(), inner_source) {
                // Normally, the source is a thin pointer and we are
                // adding extra info to make a fat pointer. The exception
                // is when we are upcasting an existing object fat pointer
                // to use a different vtable. In that case, we want to
                // load out the original data pointer so we can repackage
                // it.
                (Load(bcx, get_dataptr(bcx, source.val)),
483
                Some(Load(bcx, get_meta(bcx, source.val))))
N
Nick Cameron 已提交
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
            } else {
                let val = if source.kind.is_by_ref() {
                    load_ty(bcx, source.val, source.ty)
                } else {
                    source.val
                };
                (val, None)
            };

            let info = unsized_info(bcx.ccx(), inner_source, inner_target,
                                    old_info, bcx.fcx.param_substs);

            // Compute the base pointer. This doesn't change the pointer value,
            // but merely its type.
            let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), inner_target).ptr_to();
            let base = PointerCast(bcx, base, ptr_ty);

            Store(bcx, base, get_dataptr(bcx, target.val));
502
            Store(bcx, info, get_meta(bcx, target.val));
503
        }
N
Nick Cameron 已提交
504

N
Nick Cameron 已提交
505
        // This can be extended to enums and tuples in the future.
506 507
        // (&ty::TyEnum(def_id_a, _), &ty::TyEnum(def_id_b, _)) |
        (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => {
N
Nick Cameron 已提交
508
            assert_eq!(def_id_a, def_id_b);
509

N
Nick Cameron 已提交
510 511 512
            // The target is already by-ref because it's to be written to.
            let source = unpack_datum!(bcx, source.to_ref_datum(bcx));
            assert!(target.kind.is_by_ref());
513

N
Nick Cameron 已提交
514 515 516
            let trait_substs = Substs::erased(VecPerParamSpace::new(vec![target.ty],
                                                                    vec![source.ty],
                                                                    Vec::new()));
N
Nick Cameron 已提交
517
            let trait_ref = ty::Binder(ty::TraitRef {
N
Nick Cameron 已提交
518 519 520
                def_id: langcall(bcx, Some(span), "coercion",
                                 CoerceUnsizedTraitLangItem),
                substs: bcx.tcx().mk_substs(trait_substs)
N
Nick Cameron 已提交
521
            });
N
Nick Cameron 已提交
522

N
Nick Cameron 已提交
523 524
            let kind = match fulfill_obligation(bcx.ccx(), span, trait_ref) {
                traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
525
                    bcx.tcx().custom_coerce_unsized_kind(impl_def_id)
N
Nick Cameron 已提交
526 527
                }
                vtable => {
528 529
                    bcx.sess().span_bug(span, &format!("invalid CoerceUnsized vtable: {:?}",
                                                       vtable));
N
Nick Cameron 已提交
530 531
                }
            };
N
Nick Cameron 已提交
532

N
Nick Cameron 已提交
533
            let repr_source = adt::represent_type(bcx.ccx(), source.ty);
N
Nick Cameron 已提交
534 535 536 537 538 539
            let src_fields = match &*repr_source {
                &adt::Repr::Univariant(ref s, _) => &s.fields,
                _ => bcx.sess().span_bug(span,
                                         &format!("Non univariant struct? (repr_source: {:?})",
                                                  repr_source)),
            };
N
Nick Cameron 已提交
540
            let repr_target = adt::represent_type(bcx.ccx(), target.ty);
N
Nick Cameron 已提交
541 542 543 544 545 546
            let target_fields = match &*repr_target {
                &adt::Repr::Univariant(ref s, _) => &s.fields,
                _ => bcx.sess().span_bug(span,
                                         &format!("Non univariant struct? (repr_target: {:?})",
                                                  repr_target)),
            };
N
Nick Cameron 已提交
547 548

            let coerce_index = match kind {
549
                CustomCoerceUnsized::Struct(i) => i
N
Nick Cameron 已提交
550
            };
N
Nick Cameron 已提交
551
            assert!(coerce_index < src_fields.len() && src_fields.len() == target_fields.len());
N
Nick Cameron 已提交
552

553
            let iter = src_fields.iter().zip(target_fields).enumerate();
N
Nick Cameron 已提交
554
            for (i, (src_ty, target_ty)) in iter {
N
Nick Cameron 已提交
555 556 557 558 559 560
                let ll_source = adt::trans_field_ptr(bcx, &repr_source, source.val, 0, i);
                let ll_target = adt::trans_field_ptr(bcx, &repr_target, target.val, 0, i);

                // If this is the field we need to coerce, recurse on it.
                if i == coerce_index {
                    coerce_unsized(bcx, span,
N
Nick Cameron 已提交
561
                                   Datum::new(ll_source, src_ty,
N
Nick Cameron 已提交
562
                                              Rvalue::new(ByRef)),
N
Nick Cameron 已提交
563
                                   Datum::new(ll_target, target_ty,
N
Nick Cameron 已提交
564 565 566
                                              Rvalue::new(ByRef)));
                } else {
                    // Otherwise, simply copy the data from the source.
567
                    assert!(src_ty.is_phantom_data() || src_ty == target_ty);
N
Nick Cameron 已提交
568
                    memcpy_ty(bcx, ll_target, ll_source, src_ty);
N
Nick Cameron 已提交
569 570 571
                }
            }
        }
572 573 574
        _ => bcx.sess().bug(&format!("coerce_unsized: invalid coercion {:?} -> {:?}",
                                     source.ty,
                                     target.ty))
575
    }
N
Nick Cameron 已提交
576
    bcx
577 578
}

S
Steve Klabnik 已提交
579 580 581 582 583 584 585
/// Translates an expression in "lvalue" mode -- meaning that it returns a reference to the memory
/// that the expr represents.
///
/// If this expression is an rvalue, this implies introducing a temporary.  In other words,
/// something like `x().f` is translated into roughly the equivalent of
///
///   { tmp = x(); tmp.f }
586
pub fn trans_to_lvalue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
587
                                   expr: &hir::Expr,
588 589
                                   name: &str)
                                   -> DatumBlock<'blk, 'tcx, Lvalue> {
590 591 592
    let mut bcx = bcx;
    let datum = unpack_datum!(bcx, trans(bcx, expr));
    return datum.to_lvalue_datum(bcx, name, expr.id);
593 594
}

S
Steve Klabnik 已提交
595 596
/// A version of `trans` that ignores adjustments. You almost certainly do not want to call this
/// directly.
597
fn trans_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
598
                                expr: &hir::Expr)
599
                                -> DatumBlock<'blk, 'tcx, Expr> {
600 601
    let mut bcx = bcx;

602
    debug!("trans_unadjusted(expr={:?})", expr);
603 604
    let _indenter = indenter();

605
    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
606

A
Ariel Ben-Yehuda 已提交
607 608
    return match expr_kind(bcx.tcx(), expr) {
        ExprKind::Lvalue | ExprKind::RvalueDatum => {
609
            let datum = unpack_datum!(bcx, {
610
                trans_datum_unadjusted(bcx, expr)
611
            });
612 613

            DatumBlock {bcx: bcx, datum: datum}
614 615
        }

A
Ariel Ben-Yehuda 已提交
616
        ExprKind::RvalueStmt => {
617
            bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
618
            nil(bcx, expr_ty(bcx, expr))
619 620
        }

A
Ariel Ben-Yehuda 已提交
621
        ExprKind::RvalueDps => {
622
            let ty = expr_ty(bcx, expr);
623
            if type_is_zero_size(bcx.ccx(), ty) {
624
                bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
625
                nil(bcx, ty)
626
            } else {
627
                let scratch = rvalue_scratch_datum(bcx, ty, "");
628 629
                bcx = trans_rvalue_dps_unadjusted(
                    bcx, expr, SaveIn(scratch.val));
630 631 632 633 634 635 636 637 638 639

                // Note: this is not obviously a good idea.  It causes
                // immediate values to be loaded immediately after a
                // return from a call or other similar expression,
                // which in turn leads to alloca's having shorter
                // lifetimes and hence larger stack frames.  However,
                // in turn it can lead to more register pressure.
                // Still, in practice it seems to increase
                // performance, since we have fewer problems with
                // morestack churn.
640 641
                let scratch = unpack_datum!(
                    bcx, scratch.to_appropriate_datum(bcx));
642

K
Kevin Butler 已提交
643
                DatumBlock::new(bcx, scratch.to_expr_datum())
644 645
            }
        }
646
    };
647

648
    fn nil<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>)
649
                       -> DatumBlock<'blk, 'tcx, Expr> {
650 651
        let llval = C_undef(type_of::type_of(bcx.ccx(), ty));
        let datum = immediate_rvalue(llval, ty);
K
Kevin Butler 已提交
652
        DatumBlock::new(bcx, datum.to_expr_datum())
653 654 655
    }
}

656
fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
657
                                      expr: &hir::Expr)
658
                                      -> DatumBlock<'blk, 'tcx, Expr> {
659 660 661
    let mut bcx = bcx;
    let fcx = bcx.fcx;
    let _icx = push_ctxt("trans_datum_unadjusted");
662 663

    match expr.node {
664
        hir::ExprPath(..) => {
665 666
            trans_def(bcx, expr, bcx.def(expr.id))
        }
667 668
        hir::ExprField(ref base, name) => {
            trans_rec_field(bcx, &**base, name.node)
669
        }
670
        hir::ExprTupField(ref base, idx) => {
671 672
            trans_rec_tup_field(bcx, &**base, idx.node)
        }
673
        hir::ExprIndex(ref base, ref idx) => {
674
            trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
N
Nick Cameron 已提交
675
        }
676
        hir::ExprBox(ref contents) => {
E
Eduard Burtescu 已提交
677
            // Special case for `Box<T>`
678
            let box_ty = expr_ty(bcx, expr);
679
            let contents_ty = expr_ty(bcx, &**contents);
680
            match box_ty.sty {
681
                ty::TyBox(..) => {
682
                    trans_uniq_expr(bcx, expr, box_ty, &**contents, contents_ty)
683 684
                }
                _ => bcx.sess().span_bug(expr.span,
E
Eduard Burtescu 已提交
685
                                         "expected unique box")
686
            }
N
Nick Cameron 已提交
687

688
        }
689 690
        hir::ExprLit(ref lit) => trans_immediate_lit(bcx, expr, &**lit),
        hir::ExprBinary(op, ref lhs, ref rhs) => {
691
            trans_binary(bcx, expr, op, &**lhs, &**rhs)
692
        }
693
        hir::ExprUnary(op, ref x) => {
694
            trans_unary(bcx, expr, op, &**x)
695
        }
696
        hir::ExprAddrOf(_, ref x) => {
N
Nick Cameron 已提交
697
            match x.node {
698
                hir::ExprRepeat(..) | hir::ExprVec(..) => {
N
Nick Cameron 已提交
699
                    // Special case for slices.
700
                    let cleanup_debug_loc =
701 702 703 704
                        debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
                                                                      x.id,
                                                                      x.span,
                                                                      false);
705
                    fcx.push_ast_cleanup_scope(cleanup_debug_loc);
N
Nick Cameron 已提交
706 707 708 709 710 711 712 713 714
                    let datum = unpack_datum!(
                        bcx, tvec::trans_slice_vec(bcx, expr, &**x));
                    bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, x.id);
                    DatumBlock::new(bcx, datum)
                }
                _ => {
                    trans_addr_of(bcx, expr, &**x)
                }
            }
715
        }
716
        hir::ExprCast(ref val, _) => {
717
            // Datum output mode means this is a scalar cast:
718
            trans_imm_cast(bcx, &**val, expr.id)
719
        }
720 721 722
        _ => {
            bcx.tcx().sess.span_bug(
                expr.span,
J
Jorge Aparicio 已提交
723
                &format!("trans_rvalue_datum_unadjusted reached \
724
                         fall-through case: {:?}",
725
                        expr.node));
726 727 728 729
        }
    }
}

730
fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
731
                              base: &hir::Expr,
732 733
                              get_idx: F)
                              -> DatumBlock<'blk, 'tcx, Expr> where
734
    F: FnOnce(&'blk ty::ctxt<'tcx>, &VariantInfo<'tcx>) -> usize,
735
{
736 737 738 739
    let mut bcx = bcx;
    let _icx = push_ctxt("trans_rec_field");

    let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
740
    let bare_ty = base_datum.ty;
N
Nick Cameron 已提交
741
    let repr = adt::represent_type(bcx.ccx(), bare_ty);
742
    let vinfo = VariantInfo::from_ty(bcx.tcx(), bare_ty, None);
N
Nick Cameron 已提交
743

744 745 746 747 748
    let ix = get_idx(bcx.tcx(), &vinfo);
    let d = base_datum.get_element(
        bcx,
        vinfo.fields[ix].1,
        |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, vinfo.discr, ix));
749

750 751 752 753 754
    if type_is_sized(bcx.tcx(), d.ty) {
        DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
    } else {
        let scratch = rvalue_scratch_datum(bcx, d.ty, "");
        Store(bcx, d.val, get_dataptr(bcx, scratch.val));
755 756
        let info = Load(bcx, get_meta(bcx, base_datum.val));
        Store(bcx, info, get_meta(bcx, scratch.val));
757 758 759 760 761

        // Always generate an lvalue datum, because this pointer doesn't own
        // the data and cleanup is scheduled elsewhere.
        DatumBlock::new(bcx, Datum::new(scratch.val, scratch.ty, LvalueExpr(d.kind)))
    }
762 763 764 765
}

/// Translates `base.field`.
fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
766
                               base: &hir::Expr,
767
                               field: ast::Name)
768
                               -> DatumBlock<'blk, 'tcx, Expr> {
769
    trans_field(bcx, base, |_, vinfo| vinfo.field_index(field))
770 771 772 773
}

/// Translates `base.<idx>`.
fn trans_rec_tup_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
774
                                   base: &hir::Expr,
775
                                   idx: usize)
776 777
                                   -> DatumBlock<'blk, 'tcx, Expr> {
    trans_field(bcx, base, |_, _| idx)
778 779
}

780
fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
781 782 783
                           index_expr: &hir::Expr,
                           base: &hir::Expr,
                           idx: &hir::Expr,
784 785
                           method_call: MethodCall)
                           -> DatumBlock<'blk, 'tcx, Expr> {
786 787 788 789 790 791
    //! Translates `base[idx]`.

    let _icx = push_ctxt("trans_index");
    let ccx = bcx.ccx();
    let mut bcx = bcx;

792 793
    let index_expr_debug_loc = index_expr.debug_loc();

794
    // Check for overloaded index.
795
    let method_ty = ccx.tcx()
796
                       .tables
797
                       .borrow()
798
                       .method_map
799
                       .get(&method_call)
800 801 802
                       .map(|method| method.ty);
    let elt_datum = match method_ty {
        Some(method_ty) => {
803 804
            let method_ty = monomorphize_type(bcx, method_ty);

805
            let base_datum = unpack_datum!(bcx, trans(bcx, base));
806

807 808
            // Translate index expression.
            let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
809

810
            let ref_ty = // invoked methods have LB regions instantiated:
811
                bcx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
812
            let elt_ty = match ref_ty.builtin_deref(true, ty::NoPreference) {
813 814 815 816 817 818 819
                None => {
                    bcx.tcx().sess.span_bug(index_expr.span,
                                            "index method didn't return a \
                                             dereferenceable type?!")
                }
                Some(elt_tm) => elt_tm.ty,
            };
820 821 822 823 824 825 826 827 828 829 830

            // Overloaded. Evaluate `trans_overloaded_op`, which will
            // invoke the user's index() method, which basically yields
            // a `&T` pointer.  We can then proceed down the normal
            // path (below) to dereference that `&T`.
            let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_index_elt");
            unpack_result!(bcx,
                           trans_overloaded_op(bcx,
                                               index_expr,
                                               method_call,
                                               base_datum,
831
                                               Some((ix_datum, idx.id)),
832
                                               Some(SaveIn(scratch.val)),
833
                                               false));
834
            let datum = scratch.to_expr_datum();
835
            let lval = Lvalue::new("expr::trans_index overload");
836
            if type_is_sized(bcx.tcx(), elt_ty) {
837
                Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr(lval))
838
            } else {
839
                Datum::new(datum.val, elt_ty, LvalueExpr(lval))
840
            }
841 842 843 844 845 846 847 848 849 850 851 852 853
        }
        None => {
            let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx,
                                                                base,
                                                                "index"));

            // Translate index expression and cast to a suitable LLVM integer.
            // Rust is less strict than LLVM in this regard.
            let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
            let ix_val = ix_datum.to_llscalarish(bcx);
            let ix_size = machine::llbitsize_of_real(bcx.ccx(),
                                                     val_ty(ix_val));
            let int_size = machine::llbitsize_of_real(bcx.ccx(),
854
                                                      ccx.int_type());
855 856
            let ix_val = {
                if ix_size < int_size {
857
                    if expr_ty(bcx, idx).is_signed() {
858 859
                        SExt(bcx, ix_val, ccx.int_type())
                    } else { ZExt(bcx, ix_val, ccx.int_type()) }
860
                } else if ix_size > int_size {
861
                    Trunc(bcx, ix_val, ccx.int_type())
862 863 864 865
                } else {
                    ix_val
                }
            };
866

867
            let unit_ty = base_datum.ty.sequence_element_type(bcx.tcx());
868 869 870

            let (base, len) = base_datum.get_vec_base_and_len(bcx);

871 872
            debug!("trans_index: base {}", bcx.val_to_string(base));
            debug!("trans_index: len {}", bcx.val_to_string(len));
873

874 875 876 877 878
            let bounds_check = ICmp(bcx,
                                    llvm::IntUGE,
                                    ix_val,
                                    len,
                                    index_expr_debug_loc);
879 880 881
            let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
            let expected = Call(bcx,
                                expect,
N
Nick Cameron 已提交
882
                                &[bounds_check, C_bool(ccx, false)],
883
                                None,
884
                                index_expr_debug_loc);
885 886
            bcx = with_cond(bcx, expected, |bcx| {
                controlflow::trans_fail_bounds_check(bcx,
887
                                                     expr_info(index_expr),
888 889 890
                                                     ix_val,
                                                     len)
            });
N
Nick Cameron 已提交
891
            let elt = InBoundsGEP(bcx, base, &[ix_val]);
892
            let elt = PointerCast(bcx, elt, type_of::type_of(ccx, unit_ty).ptr_to());
893 894
            let lval = Lvalue::new("expr::trans_index fallback");
            Datum::new(elt, unit_ty, LvalueExpr(lval))
895 896
        }
    };
897

898
    DatumBlock::new(bcx, elt_datum)
899 900
}

901
fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
902
                         ref_expr: &hir::Expr,
903 904
                         def: def::Def)
                         -> DatumBlock<'blk, 'tcx, Expr> {
905 906 907 908
    //! Translates a reference to a path.

    let _icx = push_ctxt("trans_def_lvalue");
    match def {
909
        def::DefFn(..) | def::DefMethod(..) |
910
        def::DefStruct(_) | def::DefVariant(..) => {
911 912 913
            let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def,
                                                bcx.fcx.param_substs);
            DatumBlock::new(bcx, datum.to_expr_datum())
914
        }
915
        def::DefStatic(did, _) => {
916
            // There are two things that may happen here:
917 918 919
            //  1) If the static item is defined in this crate, it will be
            //     translated using `get_item_val`, and we return a pointer to
            //     the result.
920 921 922
            //  2) If the static item is defined in another crate then we add
            //     (or reuse) a declaration of an external global, and return a
            //     pointer to that.
923 924
            let const_ty = expr_ty(bcx, ref_expr);

925
            // For external constants, we don't inline.
926
            let val = if let Some(node_id) = bcx.tcx().map.as_local_node_id(did) {
927 928 929 930 931
                // Case 1.

                // The LLVM global has the type of its initializer,
                // which may not be equal to the enum's type for
                // non-C-like enums.
932
                let val = base::get_item_val(bcx.ccx(), node_id);
933 934 935 936 937 938
                let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
                PointerCast(bcx, val, pty)
            } else {
                // Case 2.
                base::get_extern_const(bcx.ccx(), did, const_ty)
            };
939 940
            let lval = Lvalue::new("expr::trans_def");
            DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr(lval)))
941
        }
942 943 944
        def::DefConst(_) => {
            bcx.sess().span_bug(ref_expr.span,
                "constant expression should not reach expr::trans_def")
945
        }
946
        _ => {
K
Kevin Butler 已提交
947
            DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
948 949 950 951
        }
    }
}

952
fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
953
                                            expr: &hir::Expr)
954
                                            -> Block<'blk, 'tcx> {
955
    let mut bcx = bcx;
956
    let _icx = push_ctxt("trans_rvalue_stmt");
957

958
    if bcx.unreachable.get() {
959 960 961
        return bcx;
    }

962 963
    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);

964
    match expr.node {
965
        hir::ExprBreak(label_opt) => {
966
            controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node.name))
967
        }
968
        hir::ExprAgain(label_opt) => {
969
            controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node.name))
970
        }
971
        hir::ExprRet(ref ex) => {
J
James Miller 已提交
972 973 974 975 976 977 978 979 980
            // Check to see if the return expression itself is reachable.
            // This can occur when the inner expression contains a return
            let reachable = if let Some(ref cfg) = bcx.fcx.cfg {
                cfg.node_is_reachable(expr.id)
            } else {
                true
            };

            if reachable {
981
                controlflow::trans_ret(bcx, expr, ex.as_ref().map(|e| &**e))
J
James Miller 已提交
982 983 984 985 986 987
            } else {
                // If it's not reachable, just translate the inner expression
                // directly. This avoids having to manage a return slot when
                // it won't actually be used anyway.
                if let &Some(ref x) = ex {
                    bcx = trans_into(bcx, &**x, Ignore);
J
James Miller 已提交
988
                }
989 990 991 992
                // Mark the end of the block as unreachable. Once we get to
                // a return expression, there's no more we should be doing
                // after this.
                Unreachable(bcx);
J
James Miller 已提交
993 994
                bcx
            }
995
        }
996
        hir::ExprWhile(ref cond, ref body, _) => {
997
            controlflow::trans_while(bcx, expr, &**cond, &**body)
998
        }
999
        hir::ExprLoop(ref body, _) => {
1000
            controlflow::trans_loop(bcx, expr, &**body)
1001
        }
1002
        hir::ExprAssign(ref dst, ref src) => {
1003
            let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
1004
            let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &**dst, "assign"));
1005

1006
            if bcx.fcx.type_needs_drop(dst_datum.ty) {
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
                // If there are destructors involved, make sure we
                // are copying from an rvalue, since that cannot possible
                // alias an lvalue. We are concerned about code like:
                //
                //   a = a
                //
                // but also
                //
                //   a = a.b
                //
                // where e.g. a : Option<Foo> and a.b :
                // Option<Foo>. In that case, freeing `a` before the
                // assignment may also free `a.b`!
                //
                // We could avoid this intermediary with some analysis
                // to determine whether `dst` may possibly own `src`.
1023
                debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
1024 1025
                let src_datum = unpack_datum!(
                    bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign"));
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
                let opt_hint_datum = dst_datum.kind.drop_flag_info.hint_datum(bcx);
                let opt_hint_val = opt_hint_datum.map(|d|d.to_value());

                // 1. Drop the data at the destination, passing the
                //    drop-hint in case the lvalue has already been
                //    dropped or moved.
                bcx = glue::drop_ty_core(bcx,
                                         dst_datum.val,
                                         dst_datum.ty,
                                         expr.debug_loc(),
                                         false,
                                         opt_hint_val);

                // 2. We are overwriting the destination; ensure that
                //    its drop-hint (if any) says "initialized."
                if let Some(hint_val) = opt_hint_val {
1042
                    let hint_llval = hint_val.value();
1043
                    let drop_needed = C_u8(bcx.fcx.ccx, adt::DTOR_NEEDED_HINT);
1044 1045
                    Store(bcx, drop_needed, hint_llval);
                }
1046 1047
                src_datum.store_to(bcx, dst_datum.val)
            } else {
1048
                src_datum.store_to(bcx, dst_datum.val)
1049
            }
1050
        }
1051
        hir::ExprAssignOp(op, ref dst, ref src) => {
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
            let has_method_map = bcx.tcx()
                                    .tables
                                    .borrow()
                                    .method_map
                                    .contains_key(&MethodCall::expr(expr.id));

            if has_method_map {
                let dst = unpack_datum!(bcx, trans(bcx, &**dst));
                let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
                trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), dst,
                                    Some((src_datum, src.id)), None, false).bcx
            } else {
                trans_assign_op(bcx, expr, op, &**dst, &**src)
            }
1066
        }
1067
        hir::ExprInlineAsm(ref a) => {
1068
            asm::trans_inline_asm(bcx, a)
1069
        }
1070 1071 1072
        _ => {
            bcx.tcx().sess.span_bug(
                expr.span,
J
Jorge Aparicio 已提交
1073
                &format!("trans_rvalue_stmt_unadjusted reached \
1074
                         fall-through case: {:?}",
1075
                        expr.node));
1076
        }
1077
    }
1078 1079
}

1080
fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1081
                                           expr: &hir::Expr,
1082 1083
                                           dest: Dest)
                                           -> Block<'blk, 'tcx> {
1084
    let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
1085
    let mut bcx = bcx;
1086 1087
    let tcx = bcx.tcx();

1088 1089
    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);

1090
    match expr.node {
1091
        hir::ExprPath(..) => {
1092
            trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
1093
        }
1094
        hir::ExprIf(ref cond, ref thn, ref els) => {
1095
            controlflow::trans_if(bcx, expr.id, &**cond, &**thn, els.as_ref().map(|e| &**e), dest)
1096
        }
1097
        hir::ExprMatch(ref discr, ref arms, _) => {
1098
            _match::trans_match(bcx, expr, &**discr, &arms[..], dest)
1099
        }
1100
        hir::ExprBlock(ref blk) => {
1101
            controlflow::trans_block(bcx, &**blk, dest)
1102
        }
1103
        hir::ExprStruct(_, ref fields, ref base) => {
1104
            trans_struct(bcx,
1105
                         &fields[..],
1106
                         base.as_ref().map(|e| &**e),
1107 1108
                         expr.span,
                         expr.id,
N
Nick Cameron 已提交
1109
                         node_id_type(bcx, expr.id),
1110
                         dest)
1111
        }
1112
        hir::ExprRange(ref start, ref end) => {
N
Nick Cameron 已提交
1113 1114
            // FIXME it is just not right that we are synthesising ast nodes in
            // trans. Shudder.
1115 1116
            fn make_field(field_name: &str, expr: P<hir::Expr>) -> hir::Field {
                hir::Field {
1117
                    name: codemap::dummy_spanned(token::intern(field_name)),
N
Nick Cameron 已提交
1118 1119 1120 1121 1122 1123
                    expr: expr,
                    span: codemap::DUMMY_SP,
                }
            }

            // A range just desugars into a struct.
1124 1125 1126 1127 1128
            // Note that the type of the start and end may not be the same, but
            // they should only differ in their lifetime, which should not matter
            // in trans.
            let (did, fields, ty_params) = match (start, end) {
                (&Some(ref start), &Some(ref end)) => {
N
Nick Cameron 已提交
1129
                    // Desugar to Range
N
Nick Cameron 已提交
1130 1131
                    let fields = vec![make_field("start", start.clone()),
                                      make_field("end", end.clone())];
1132
                    (tcx.lang_items.range_struct(), fields, vec![node_id_type(bcx, start.id)])
N
Nick Cameron 已提交
1133
                }
1134
                (&Some(ref start), &None) => {
N
Nick Cameron 已提交
1135
                    // Desugar to RangeFrom
N
Nick Cameron 已提交
1136
                    let fields = vec![make_field("start", start.clone())];
1137 1138 1139 1140
                    (tcx.lang_items.range_from_struct(), fields, vec![node_id_type(bcx, start.id)])
                }
                (&None, &Some(ref end)) => {
                    // Desugar to RangeTo
N
Nick Cameron 已提交
1141
                    let fields = vec![make_field("end", end.clone())];
1142 1143 1144
                    (tcx.lang_items.range_to_struct(), fields, vec![node_id_type(bcx, end.id)])
                }
                _ => {
N
Nick Cameron 已提交
1145 1146
                    // Desugar to RangeFull
                    (tcx.lang_items.range_full_struct(), vec![], vec![])
N
Nick Cameron 已提交
1147 1148 1149 1150
                }
            };

            if let Some(did) = did {
1151
                let substs = Substs::new_type(ty_params, vec![]);
N
Nick Cameron 已提交
1152
                trans_struct(bcx,
1153
                             &fields,
N
Nick Cameron 已提交
1154 1155 1156
                             None,
                             expr.span,
                             expr.id,
1157 1158
                             tcx.mk_struct(tcx.lookup_adt_def(did),
                                           tcx.mk_substs(substs)),
N
Nick Cameron 已提交
1159 1160 1161 1162 1163 1164
                             dest)
            } else {
                tcx.sess.span_bug(expr.span,
                                  "No lang item for ranges (how did we get this far?)")
            }
        }
1165 1166
        hir::ExprTup(ref args) => {
            let numbered_fields: Vec<(usize, &hir::Expr)> =
1167
                args.iter().enumerate().map(|(i, arg)| (i, &**arg)).collect();
1168 1169 1170
            trans_adt(bcx,
                      expr_ty(bcx, expr),
                      0,
1171
                      &numbered_fields[..],
1172 1173
                      None,
                      dest,
1174
                      expr.debug_loc())
1175
        }
1176
        hir::ExprLit(ref lit) => {
1177
            match lit.node {
1178
                ast::LitStr(ref s, _) => {
1179
                    tvec::trans_lit_str(bcx, expr, (*s).clone(), dest)
1180 1181 1182 1183 1184 1185 1186 1187 1188
                }
                _ => {
                    bcx.tcx()
                       .sess
                       .span_bug(expr.span,
                                 "trans_rvalue_dps_unadjusted shouldn't be \
                                  translating this type of literal")
                }
            }
1189
        }
1190
        hir::ExprVec(..) | hir::ExprRepeat(..) => {
N
Nick Cameron 已提交
1191
            tvec::trans_fixed_vstore(bcx, expr, dest)
1192
        }
1193
        hir::ExprClosure(_, ref decl, ref body) => {
1194 1195 1196 1197
            let dest = match dest {
                SaveIn(lldest) => closure::Dest::SaveIn(bcx, lldest),
                Ignore => closure::Dest::Ignore(bcx.ccx())
            };
1198 1199 1200 1201 1202 1203 1204 1205
            let substs = match expr_ty(bcx, expr).sty {
                ty::TyClosure(_, ref substs) => substs,
                ref t =>
                    bcx.tcx().sess.span_bug(
                        expr.span,
                        &format!("closure expr without closure type: {:?}", t)),
            };
            closure::trans_closure_expr(dest, decl, body, expr.id, substs).unwrap_or(bcx)
1206
        }
1207
        hir::ExprCall(ref f, ref args) => {
1208 1209 1210
            if bcx.tcx().is_method_call(expr.id) {
                trans_overloaded_call(bcx,
                                      expr,
1211
                                      &**f,
1212
                                      &args[..],
1213 1214 1215 1216
                                      Some(dest))
            } else {
                callee::trans_call(bcx,
                                   expr,
1217
                                   &**f,
1218
                                   callee::ArgExprs(&args[..]),
1219 1220
                                   dest)
            }
1221
        }
1222
        hir::ExprMethodCall(_, _, ref args) => {
1223 1224
            callee::trans_method_call(bcx,
                                      expr,
1225
                                      &*args[0],
1226
                                      callee::ArgExprs(&args[..]),
1227
                                      dest)
1228
        }
1229
        hir::ExprBinary(op, ref lhs, ref rhs) => {
1230
            // if not overloaded, would be RvalueDatumExpr
1231 1232
            let lhs = unpack_datum!(bcx, trans(bcx, &**lhs));
            let rhs_datum = unpack_datum!(bcx, trans(bcx, &**rhs));
1233
            trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs,
1234
                                Some((rhs_datum, rhs.id)), Some(dest),
1235
                                !rustc_front::util::is_by_value_binop(op.node)).bcx
1236
        }
1237
        hir::ExprUnary(op, ref subexpr) => {
1238
            // if not overloaded, would be RvalueDatumExpr
1239
            let arg = unpack_datum!(bcx, trans(bcx, &**subexpr));
1240
            trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
1241
                                arg, None, Some(dest), !rustc_front::util::is_by_value_unop(op)).bcx
1242
        }
1243
        hir::ExprIndex(ref base, ref idx) => {
1244
            // if not overloaded, would be RvalueDatumExpr
1245 1246
            let base = unpack_datum!(bcx, trans(bcx, &**base));
            let idx_datum = unpack_datum!(bcx, trans(bcx, &**idx));
1247
            trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
1248
                                Some((idx_datum, idx.id)), Some(dest), true).bcx
1249
        }
1250
        hir::ExprCast(..) => {
N
Nick Cameron 已提交
1251 1252
            // Trait casts used to come this way, now they should be coercions.
            bcx.tcx().sess.span_bug(expr.span, "DPS expr_cast (residual trait cast?)")
1253
        }
1254 1255 1256 1257 1258
        hir::ExprAssignOp(op, _, _) => {
            bcx.tcx().sess.span_bug(
                expr.span,
                &format!("augmented assignment `{}=` should always be a rvalue_stmt",
                         rustc_front::util::binop_to_string(op.node)))
1259 1260 1261 1262
        }
        _ => {
            bcx.tcx().sess.span_bug(
                expr.span,
J
Jorge Aparicio 已提交
1263
                &format!("trans_rvalue_dps_unadjusted reached fall-through \
1264
                         case: {:?}",
1265
                        expr.node));
1266 1267 1268 1269
        }
    }
}

1270
fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1271
                                        ref_expr: &hir::Expr,
1272 1273 1274
                                        def: def::Def,
                                        dest: Dest)
                                        -> Block<'blk, 'tcx> {
1275
    let _icx = push_ctxt("trans_def_dps_unadjusted");
1276 1277 1278 1279 1280 1281 1282

    let lldest = match dest {
        SaveIn(lldest) => lldest,
        Ignore => { return bcx; }
    };

    match def {
1283
        def::DefVariant(tid, vid, _) => {
1284 1285
            let variant = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
            if let ty::VariantKind::Tuple = variant.kind() {
1286
                // N-ary variant.
1287 1288 1289
                let llfn = callee::trans_fn_ref(bcx.ccx(), vid,
                                                ExprId(ref_expr.id),
                                                bcx.fcx.param_substs).val;
1290
                Store(bcx, llfn, lldest);
1291
                return bcx;
1292
            } else {
1293 1294
                // Nullary variant.
                let ty = expr_ty(bcx, ref_expr);
1295
                let repr = adt::represent_type(bcx.ccx(), ty);
1296
                adt::trans_set_discr(bcx, &*repr, lldest, variant.disr_val);
1297
                return bcx;
1298 1299
            }
        }
1300
        def::DefStruct(_) => {
1301
            let ty = expr_ty(bcx, ref_expr);
1302
            match ty.sty {
1303
                ty::TyStruct(def, _) if def.has_dtor() => {
1304
                    let repr = adt::represent_type(bcx.ccx(), ty);
1305
                    adt::trans_set_discr(bcx, &*repr, lldest, 0);
1306
                }
1307
                _ => {}
1308
            }
1309
            bcx
1310
        }
1311
        _ => {
J
Jorge Aparicio 已提交
1312
            bcx.tcx().sess.span_bug(ref_expr.span, &format!(
1313
                "Non-DPS def {:?} referened by {}",
1314
                def, bcx.node_id_to_string(ref_expr.id)));
1315 1316 1317 1318
        }
    }
}

1319
pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1320
                                         ref_expr: &hir::Expr,
1321
                                         def: def::Def,
N
Nick Cameron 已提交
1322
                                         param_substs: &'tcx Substs<'tcx>)
1323
                                         -> Datum<'tcx, Rvalue> {
1324
    let _icx = push_ctxt("trans_def_datum_unadjusted");
1325

1326
    match def {
1327
        def::DefFn(did, _) |
1328
        def::DefStruct(did) | def::DefVariant(_, did, _) => {
1329
            callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs)
1330
        }
1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
        def::DefMethod(method_did) => {
            match ccx.tcx().impl_or_trait_item(method_did).container() {
                ty::ImplContainer(_) => {
                    callee::trans_fn_ref(ccx, method_did,
                                         ExprId(ref_expr.id),
                                         param_substs)
                }
                ty::TraitContainer(trait_did) => {
                    meth::trans_static_method_callee(ccx, method_did,
                                                     trait_did, ref_expr.id,
                                                     param_substs)
                }
            }
1344 1345
        }
        _ => {
J
Jorge Aparicio 已提交
1346
            ccx.tcx().sess.span_bug(ref_expr.span, &format!(
1347
                    "trans_def_fn_unadjusted invoked on: {:?} for {:?}",
1348
                    def,
1349
                    ref_expr));
1350
        }
1351
    }
1352 1353
}

S
Steve Klabnik 已提交
1354
/// Translates a reference to a local variable or argument. This always results in an lvalue datum.
1355 1356
pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                   def: def::Def)
1357
                                   -> Datum<'tcx, Lvalue> {
1358
    let _icx = push_ctxt("trans_local_var");
1359

1360
    match def {
1361
        def::DefUpvar(_, nid, _, _) => {
1362
            // Can't move upvars, so this is never a ZeroMemLastUse.
1363
            let local_ty = node_id_type(bcx, nid);
1364 1365
            let lval = Lvalue::new_with_hint("expr::trans_local_var (upvar)",
                                             bcx, nid, HintKind::ZeroAndMaintain);
1366
            match bcx.fcx.llupvars.borrow().get(&nid) {
1367
                Some(&val) => Datum::new(val, local_ty, lval),
1368
                None => {
J
Jorge Aparicio 已提交
1369
                    bcx.sess().bug(&format!(
L
Luqman Aden 已提交
1370
                        "trans_local_var: no llval for upvar {} found",
1371
                        nid));
1372 1373 1374
                }
            }
        }
1375
        def::DefLocal(_, nid) => {
1376
            let datum = match bcx.fcx.lllocals.borrow().get(&nid) {
1377 1378
                Some(&v) => v,
                None => {
J
Jorge Aparicio 已提交
1379
                    bcx.sess().bug(&format!(
L
Luqman Aden 已提交
1380
                        "trans_local_var: no datum for local/arg {} found",
1381
                        nid));
1382 1383
                }
            };
L
Luqman Aden 已提交
1384
            debug!("take_local(nid={}, v={}, ty={})",
1385
                   nid, bcx.val_to_string(datum.val), datum.ty);
1386
            datum
1387 1388
        }
        _ => {
J
Jorge Aparicio 已提交
1389
            bcx.sess().unimpl(&format!(
1390
                "unsupported def type in trans_local_var: {:?}",
1391
                def));
1392 1393 1394 1395
        }
    }
}

1396
fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1397 1398
                            fields: &[hir::Field],
                            base: Option<&hir::Expr>,
1399
                            expr_span: codemap::Span,
1400
                            expr_id: ast::NodeId,
N
Nick Cameron 已提交
1401
                            ty: Ty<'tcx>,
1402
                            dest: Dest) -> Block<'blk, 'tcx> {
1403
    let _icx = push_ctxt("trans_rec");
1404 1405

    let tcx = bcx.tcx();
1406 1407 1408 1409 1410
    let vinfo = VariantInfo::of_node(tcx, ty, expr_id);

    let mut need_base = vec![true; vinfo.fields.len()];

    let numbered_fields = fields.iter().map(|field| {
1411
        let pos = vinfo.field_index(field.name.node);
1412 1413 1414 1415 1416 1417 1418 1419 1420 1421
        need_base[pos] = false;
        (pos, &*field.expr)
    }).collect::<Vec<_>>();

    let optbase = match base {
        Some(base_expr) => {
            let mut leftovers = Vec::new();
            for (i, b) in need_base.iter().enumerate() {
                if *b {
                    leftovers.push((i, vinfo.fields[i].1));
1422
                }
1423
            }
1424 1425 1426 1427 1428 1429
            Some(StructBaseInfo {expr: base_expr,
                                 fields: leftovers })
        }
        None => {
            if need_base.iter().any(|b| *b) {
                tcx.sess.span_bug(expr_span, "missing fields and no base expr")
1430
            }
1431 1432 1433
            None
        }
    };
1434

1435 1436 1437 1438 1439 1440 1441
    trans_adt(bcx,
              ty,
              vinfo.discr,
              &numbered_fields,
              optbase,
              dest,
              DebugLoc::At(expr_id, expr_span))
1442 1443
}

S
Steve Klabnik 已提交
1444 1445 1446 1447 1448 1449
/// Information that `trans_adt` needs in order to fill in the fields
/// of a struct copied from a base struct (e.g., from an expression
/// like `Foo { a: b, ..base }`.
///
/// Note that `fields` may be empty; the base expression must always be
/// evaluated for side-effects.
1450
pub struct StructBaseInfo<'a, 'tcx> {
1451
    /// The base expression; will be evaluated after all explicit fields.
1452
    expr: &'a hir::Expr,
1453
    /// The indices of fields to copy paired with their types.
1454
    fields: Vec<(usize, Ty<'tcx>)>
1455
}
1456

S
Steve Klabnik 已提交
1457 1458 1459 1460 1461 1462 1463 1464
/// Constructs an ADT instance:
///
/// - `fields` should be a list of field indices paired with the
/// expression to store into that field.  The initializers will be
/// evaluated in the order specified by `fields`.
///
/// - `optbase` contains information on the base struct (if any) from
/// which remaining fields are copied; see comments on `StructBaseInfo`.
1465 1466 1467
pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                 ty: Ty<'tcx>,
                                 discr: ty::Disr,
1468
                                 fields: &[(usize, &hir::Expr)],
1469 1470
                                 optbase: Option<StructBaseInfo<'a, 'tcx>>,
                                 dest: Dest,
1471
                                 debug_location: DebugLoc)
1472
                                 -> Block<'blk, 'tcx> {
1473
    let _icx = push_ctxt("trans_adt");
1474
    let fcx = bcx.fcx;
1475 1476
    let repr = adt::represent_type(bcx.ccx(), ty);

1477
    debug_location.apply(bcx.fcx);
1478

1479 1480
    // If we don't care about the result, just make a
    // temporary stack slot
1481
    let addr = match dest {
1482
        SaveIn(pos) => pos,
1483 1484 1485 1486 1487
        Ignore => {
            let llresult = alloc_ty(bcx, ty, "temp");
            call_lifetime_start(bcx, llresult);
            llresult
        }
1488
    };
1489 1490

    // This scope holds intermediates that must be cleaned should
S
Steve Klabnik 已提交
1491
    // panic occur before the ADT as a whole is ready.
1492 1493
    let custom_cleanup_scope = fcx.push_custom_cleanup_scope();

A
Ariel Ben-Yehuda 已提交
1494
    if ty.is_simd() {
1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532
        // Issue 23112: The original logic appeared vulnerable to same
        // order-of-eval bug. But, SIMD values are tuple-structs;
        // i.e. functional record update (FRU) syntax is unavailable.
        //
        // To be safe, double-check that we did not get here via FRU.
        assert!(optbase.is_none());

        // This is the constructor of a SIMD type, such types are
        // always primitive machine types and so do not have a
        // destructor or require any clean-up.
        let llty = type_of::type_of(bcx.ccx(), ty);

        // keep a vector as a register, and running through the field
        // `insertelement`ing them directly into that register
        // (i.e. avoid GEPi and `store`s to an alloca) .
        let mut vec_val = C_undef(llty);

        for &(i, ref e) in fields {
            let block_datum = trans(bcx, &**e);
            bcx = block_datum.bcx;
            let position = C_uint(bcx.ccx(), i);
            let value = block_datum.datum.to_llscalarish(bcx);
            vec_val = InsertElement(bcx, vec_val, value, position);
        }
        Store(bcx, vec_val, addr);
    } else if let Some(base) = optbase {
        // Issue 23112: If there is a base, then order-of-eval
        // requires field expressions eval'ed before base expression.

        // First, trans field expressions to temporary scratch values.
        let scratch_vals: Vec<_> = fields.iter().map(|&(i, ref e)| {
            let datum = unpack_datum!(bcx, trans(bcx, &**e));
            (i, datum)
        }).collect();

        debug_location.apply(bcx.fcx);

        // Second, trans the base to the dest.
1533 1534
        assert_eq!(discr, 0);

A
Ariel Ben-Yehuda 已提交
1535 1536
        match expr_kind(bcx.tcx(), &*base.expr) {
            ExprKind::RvalueDps | ExprKind::RvalueDatum if !bcx.fcx.type_needs_drop(ty) => {
1537 1538
                bcx = trans_into(bcx, &*base.expr, SaveIn(addr));
            },
A
Ariel Ben-Yehuda 已提交
1539 1540 1541
            ExprKind::RvalueStmt => {
                bcx.tcx().sess.bug("unexpected expr kind for struct base expr")
            }
1542
            _ => {
1543
                let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base"));
1544
                for &(i, t) in &base.fields {
1545
                    let datum = base_datum.get_element(
N
Nick Cameron 已提交
1546
                            bcx, t, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, i));
1547
                    assert!(type_is_sized(bcx.tcx(), datum.ty));
1548
                    let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
1549 1550
                    bcx = datum.store_to(bcx, dest);
                }
1551
            }
1552
        }
1553

1554
        // Finally, move scratch field values into actual field locations
1555
        for (i, datum) in scratch_vals {
1556 1557
            let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
            bcx = datum.store_to(bcx, dest);
1558 1559
        }
    } else {
1560
        // No base means we can write all fields directly in place.
1561
        for &(i, ref e) in fields {
1562 1563 1564 1565 1566
            let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
            let e_ty = expr_ty_adjusted(bcx, &**e);
            bcx = trans_into(bcx, &**e, SaveIn(dest));
            let scope = cleanup::CustomScope(custom_cleanup_scope);
            fcx.schedule_lifetime_end(scope, dest);
1567 1568
            // FIXME: nonzeroing move should generalize to fields
            fcx.schedule_drop_mem(scope, dest, e_ty, None);
1569
        }
1570
    }
1571

1572
    adt::trans_set_discr(bcx, &*repr, addr, discr);
1573

1574 1575
    fcx.pop_custom_cleanup_scope(custom_cleanup_scope);

1576 1577 1578 1579
    // If we don't care about the result drop the temporary we made
    match dest {
        SaveIn(_) => bcx,
        Ignore => {
1580
            bcx = glue::drop_ty(bcx, addr, ty, debug_location);
1581 1582 1583 1584
            base::call_lifetime_end(bcx, addr);
            bcx
        }
    }
1585 1586
}

1587

1588
fn trans_immediate_lit<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1589
                                   expr: &hir::Expr,
1590
                                   lit: &ast::Lit)
1591
                                   -> DatumBlock<'blk, 'tcx, Expr> {
1592
    // must not be a string constant, that is a RvalueDpsExpr
1593
    let _icx = push_ctxt("trans_immediate_lit");
1594
    let ty = expr_ty(bcx, expr);
1595 1596
    let v = consts::const_lit(bcx.ccx(), expr, lit);
    immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock()
1597 1598
}

1599
fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1600 1601 1602
                           expr: &hir::Expr,
                           op: hir::UnOp,
                           sub_expr: &hir::Expr)
1603
                           -> DatumBlock<'blk, 'tcx, Expr> {
1604
    let ccx = bcx.ccx();
1605
    let mut bcx = bcx;
1606
    let _icx = push_ctxt("trans_unary_datum");
1607

1608
    let method_call = MethodCall::expr(expr.id);
1609 1610 1611 1612

    // The only overloaded operator that is translated to a datum
    // is an overloaded deref, since it is always yields a `&T`.
    // Otherwise, we should be in the RvalueDpsExpr path.
1613
    assert!(op == hir::UnDeref || !ccx.tcx().is_method_call(expr.id));
1614

1615
    let un_ty = expr_ty(bcx, expr);
1616

1617 1618
    let debug_loc = expr.debug_loc();

1619
    match op {
1620
        hir::UnNot => {
1621
            let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1622
            let llresult = Not(bcx, datum.to_llscalarish(bcx), debug_loc);
1623
            immediate_rvalue_bcx(bcx, llresult, un_ty).to_expr_datumblock()
1624
        }
1625
        hir::UnNeg => {
1626 1627
            let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
            let val = datum.to_llscalarish(bcx);
1628
            let (bcx, llneg) = {
1629
                if un_ty.is_fp() {
1630 1631
                    let result = FNeg(bcx, val, debug_loc);
                    (bcx, result)
1632
                } else {
1633
                    let is_signed = un_ty.is_signed();
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647
                    let result = Neg(bcx, val, debug_loc);
                    let bcx = if bcx.ccx().check_overflow() && is_signed {
                        let (llty, min) = base::llty_and_min_for_signed_ty(bcx, un_ty);
                        let is_min = ICmp(bcx, llvm::IntEQ, val,
                                          C_integral(llty, min, true), debug_loc);
                        with_cond(bcx, is_min, |bcx| {
                            let msg = InternedString::new(
                                "attempted to negate with overflow");
                            controlflow::trans_fail(bcx, expr_info(expr), msg)
                        })
                    } else {
                        bcx
                    };
                    (bcx, result)
1648 1649
                }
            };
1650
            immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
1651
        }
1652
        hir::UnDeref => {
1653
            let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1654
            deref_once(bcx, expr, datum, method_call)
1655
        }
1656
    }
1657
}
1658

1659
fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1660
                               box_expr: &hir::Expr,
1661
                               box_ty: Ty<'tcx>,
1662
                               contents: &hir::Expr,
1663
                               contents_ty: Ty<'tcx>)
1664
                               -> DatumBlock<'blk, 'tcx, Expr> {
E
Eduard Burtescu 已提交
1665
    let _icx = push_ctxt("trans_uniq_expr");
1666
    let fcx = bcx.fcx;
1667
    assert!(type_is_sized(bcx.tcx(), contents_ty));
E
Eduard Burtescu 已提交
1668 1669
    let llty = type_of::type_of(bcx.ccx(), contents_ty);
    let size = llsize_of(bcx.ccx(), llty);
1670
    let align = C_uint(bcx.ccx(), type_of::align_of(bcx.ccx(), contents_ty));
N
Nick Cameron 已提交
1671
    let llty_ptr = llty.ptr_to();
1672 1673 1674 1675 1676 1677
    let Result { bcx, val } = malloc_raw_dyn(bcx,
                                             llty_ptr,
                                             box_ty,
                                             size,
                                             align,
                                             box_expr.debug_loc());
1678 1679 1680
    // Unique boxes do not allocate for zero-size types. The standard library
    // may assume that `free` is never called on the pointer returned for
    // `Box<ZeroSizeType>`.
E
Eduard Burtescu 已提交
1681 1682
    let bcx = if llsize_of_alloc(bcx.ccx(), llty) == 0 {
        trans_into(bcx, contents, SaveIn(val))
1683
    } else {
1684 1685
        let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
        fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
1686
                                val, cleanup::HeapExchange, contents_ty);
E
Eduard Burtescu 已提交
1687
        let bcx = trans_into(bcx, contents, SaveIn(val));
1688
        fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
E
Eduard Burtescu 已提交
1689 1690 1691 1692 1693
        bcx
    };
    immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
}

1694 1695 1696
fn ref_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                           lval: Datum<'tcx, Lvalue>)
                           -> DatumBlock<'blk, 'tcx, Expr> {
1697
    let dest_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic), lval.ty);
1698 1699 1700 1701 1702 1703
    let scratch = rvalue_scratch_datum(bcx, dest_ty, "__fat_ptr");
    memcpy_ty(bcx, scratch.val, lval.val, scratch.ty);

    DatumBlock::new(bcx, scratch.to_expr_datum())
}

1704
fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1705 1706
                             expr: &hir::Expr,
                             subexpr: &hir::Expr)
1707
                             -> DatumBlock<'blk, 'tcx, Expr> {
1708
    let _icx = push_ctxt("trans_addr_of");
1709
    let mut bcx = bcx;
1710
    let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
1711 1712 1713 1714 1715 1716 1717
    if !type_is_sized(bcx.tcx(), sub_datum.ty) {
        // DST lvalue, close to a fat pointer
        ref_fat_ptr(bcx, sub_datum)
    } else {
        // Sized value, ref to a thin pointer
        let ty = expr_ty(bcx, expr);
        immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock()
N
Nick Cameron 已提交
1718
    }
1719 1720
}

A
Ariel Ben-Yehuda 已提交
1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781
fn trans_fat_ptr_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                   binop_expr: &hir::Expr,
                                   binop_ty: Ty<'tcx>,
                                   op: hir::BinOp,
                                   lhs: Datum<'tcx, Rvalue>,
                                   rhs: Datum<'tcx, Rvalue>)
                                   -> DatumBlock<'blk, 'tcx, Expr>
{
    let debug_loc = binop_expr.debug_loc();

    let lhs_addr = Load(bcx, GEPi(bcx, lhs.val, &[0, abi::FAT_PTR_ADDR]));
    let lhs_extra = Load(bcx, GEPi(bcx, lhs.val, &[0, abi::FAT_PTR_EXTRA]));

    let rhs_addr = Load(bcx, GEPi(bcx, rhs.val, &[0, abi::FAT_PTR_ADDR]));
    let rhs_extra = Load(bcx, GEPi(bcx, rhs.val, &[0, abi::FAT_PTR_EXTRA]));

    let val = match op.node {
        hir::BiEq => {
            let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc);
            let extra_eq = ICmp(bcx, llvm::IntEQ, lhs_extra, rhs_extra, debug_loc);
            And(bcx, addr_eq, extra_eq, debug_loc)
        }
        hir::BiNe => {
            let addr_eq = ICmp(bcx, llvm::IntNE, lhs_addr, rhs_addr, debug_loc);
            let extra_eq = ICmp(bcx, llvm::IntNE, lhs_extra, rhs_extra, debug_loc);
            Or(bcx, addr_eq, extra_eq, debug_loc)
        }
        hir::BiLe | hir::BiLt | hir::BiGe | hir::BiGt => {
            // a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1)
            let (op, strict_op) = match op.node {
                hir::BiLt => (llvm::IntULT, llvm::IntULT),
                hir::BiLe => (llvm::IntULE, llvm::IntULT),
                hir::BiGt => (llvm::IntUGT, llvm::IntUGT),
                hir::BiGe => (llvm::IntUGE, llvm::IntUGT),
                _ => unreachable!()
            };

            let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc);
            let extra_op = ICmp(bcx, op, lhs_extra, rhs_extra, debug_loc);
            let addr_eq_extra_op = And(bcx, addr_eq, extra_op, debug_loc);

            let addr_strict = ICmp(bcx, strict_op, lhs_addr, rhs_addr, debug_loc);
            Or(bcx, addr_strict, addr_eq_extra_op, debug_loc)
        }
        _ => {
            bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
        }
    };

    immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
}

fn trans_scalar_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                  binop_expr: &hir::Expr,
                                  binop_ty: Ty<'tcx>,
                                  op: hir::BinOp,
                                  lhs: Datum<'tcx, Rvalue>,
                                  rhs: Datum<'tcx, Rvalue>)
                                  -> DatumBlock<'blk, 'tcx, Expr>
{
    let _icx = push_ctxt("trans_scalar_binop");
1782

1783
    let tcx = bcx.tcx();
A
Ariel Ben-Yehuda 已提交
1784
    let lhs_t = lhs.ty;
1785 1786 1787
    assert!(!lhs_t.is_simd());
    let is_float = lhs_t.is_fp();
    let is_signed = lhs_t.is_signed();
1788
    let info = expr_info(binop_expr);
1789

1790 1791
    let binop_debug_loc = binop_expr.debug_loc();

1792
    let mut bcx = bcx;
A
Ariel Ben-Yehuda 已提交
1793 1794
    let lhs = lhs.to_llscalarish(bcx);
    let rhs = rhs.to_llscalarish(bcx);
1795
    let val = match op.node {
1796
      hir::BiAdd => {
1797 1798 1799
        if is_float {
            FAdd(bcx, lhs, rhs, binop_debug_loc)
        } else {
1800 1801 1802 1803
            let (newbcx, res) = with_overflow_check(
                bcx, OverflowOp::Add, info, lhs_t, lhs, rhs, binop_debug_loc);
            bcx = newbcx;
            res
1804
        }
1805
      }
1806
      hir::BiSub => {
1807 1808 1809
        if is_float {
            FSub(bcx, lhs, rhs, binop_debug_loc)
        } else {
1810 1811 1812 1813
            let (newbcx, res) = with_overflow_check(
                bcx, OverflowOp::Sub, info, lhs_t, lhs, rhs, binop_debug_loc);
            bcx = newbcx;
            res
1814
        }
1815
      }
1816
      hir::BiMul => {
1817 1818 1819
        if is_float {
            FMul(bcx, lhs, rhs, binop_debug_loc)
        } else {
1820 1821 1822 1823
            let (newbcx, res) = with_overflow_check(
                bcx, OverflowOp::Mul, info, lhs_t, lhs, rhs, binop_debug_loc);
            bcx = newbcx;
            res
1824
        }
1825
      }
1826
      hir::BiDiv => {
1827
        if is_float {
1828
            FDiv(bcx, lhs, rhs, binop_debug_loc)
1829 1830
        } else {
            // Only zero-check integers; fp /0 is NaN
1831 1832 1833 1834 1835
            bcx = base::fail_if_zero_or_overflows(bcx,
                                                  expr_info(binop_expr),
                                                  op,
                                                  lhs,
                                                  rhs,
A
Ariel Ben-Yehuda 已提交
1836
                                                  lhs_t);
1837
            if is_signed {
1838
                SDiv(bcx, lhs, rhs, binop_debug_loc)
1839
            } else {
1840
                UDiv(bcx, lhs, rhs, binop_debug_loc)
1841 1842 1843
            }
        }
      }
1844
      hir::BiRem => {
1845
        if is_float {
1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882
            // LLVM currently always lowers the `frem` instructions appropriate
            // library calls typically found in libm. Notably f64 gets wired up
            // to `fmod` and f32 gets wired up to `fmodf`. Inconveniently for
            // us, 32-bit MSVC does not actually have a `fmodf` symbol, it's
            // instead just an inline function in a header that goes up to a
            // f64, uses `fmod`, and then comes back down to a f32.
            //
            // Although LLVM knows that `fmodf` doesn't exist on MSVC, it will
            // still unconditionally lower frem instructions over 32-bit floats
            // to a call to `fmodf`. To work around this we special case MSVC
            // 32-bit float rem instructions and instead do the call out to
            // `fmod` ourselves.
            //
            // Note that this is currently duplicated with src/libcore/ops.rs
            // which does the same thing, and it would be nice to perhaps unify
            // these two implementations on day! Also note that we call `fmod`
            // for both 32 and 64-bit floats because if we emit any FRem
            // instruction at all then LLVM is capable of optimizing it into a
            // 32-bit FRem (which we're trying to avoid).
            let use_fmod = tcx.sess.target.target.options.is_like_msvc &&
                           tcx.sess.target.target.arch == "x86";
            if use_fmod {
                let f64t = Type::f64(bcx.ccx());
                let fty = Type::func(&[f64t, f64t], &f64t);
                let llfn = declare::declare_cfn(bcx.ccx(), "fmod", fty,
                                                tcx.types.f64);
                if lhs_t == tcx.types.f32 {
                    let lhs = FPExt(bcx, lhs, f64t);
                    let rhs = FPExt(bcx, rhs, f64t);
                    let res = Call(bcx, llfn, &[lhs, rhs], None, binop_debug_loc);
                    FPTrunc(bcx, res, Type::f32(bcx.ccx()))
                } else {
                    Call(bcx, llfn, &[lhs, rhs], None, binop_debug_loc)
                }
            } else {
                FRem(bcx, lhs, rhs, binop_debug_loc)
            }
1883 1884
        } else {
            // Only zero-check integers; fp %0 is NaN
1885 1886
            bcx = base::fail_if_zero_or_overflows(bcx,
                                                  expr_info(binop_expr),
A
Ariel Ben-Yehuda 已提交
1887
                                                  op, lhs, rhs, lhs_t);
1888
            if is_signed {
1889
                SRem(bcx, lhs, rhs, binop_debug_loc)
1890
            } else {
1891
                URem(bcx, lhs, rhs, binop_debug_loc)
1892 1893 1894
            }
        }
      }
1895 1896 1897 1898
      hir::BiBitOr => Or(bcx, lhs, rhs, binop_debug_loc),
      hir::BiBitAnd => And(bcx, lhs, rhs, binop_debug_loc),
      hir::BiBitXor => Xor(bcx, lhs, rhs, binop_debug_loc),
      hir::BiShl => {
1899 1900 1901 1902 1903
          let (newbcx, res) = with_overflow_check(
              bcx, OverflowOp::Shl, info, lhs_t, lhs, rhs, binop_debug_loc);
          bcx = newbcx;
          res
      }
1904
      hir::BiShr => {
1905 1906 1907 1908
          let (newbcx, res) = with_overflow_check(
              bcx, OverflowOp::Shr, info, lhs_t, lhs, rhs, binop_debug_loc);
          bcx = newbcx;
          res
1909
      }
1910
      hir::BiEq | hir::BiNe | hir::BiLt | hir::BiGe | hir::BiLe | hir::BiGt => {
1911
          base::compare_scalar_types(bcx, lhs, rhs, lhs_t, op.node, binop_debug_loc)
1912
      }
1913
      _ => {
J
Jeong YunWon 已提交
1914
        bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
1915 1916 1917
      }
    };

1918
    immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
1919 1920 1921
}

// refinement types would obviate the need for this
1922 1923 1924 1925
enum lazy_binop_ty {
    lazy_and,
    lazy_or,
}
1926

1927
fn trans_lazy_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1928
                                binop_expr: &hir::Expr,
1929
                                op: lazy_binop_ty,
1930 1931
                                a: &hir::Expr,
                                b: &hir::Expr)
1932
                                -> DatumBlock<'blk, 'tcx, Expr> {
1933
    let _icx = push_ctxt("trans_lazy_binop");
1934
    let binop_ty = expr_ty(bcx, binop_expr);
1935
    let fcx = bcx.fcx;
1936

1937 1938
    let DatumBlock {bcx: past_lhs, datum: lhs} = trans(bcx, a);
    let lhs = lhs.to_llscalarish(past_lhs);
1939

1940
    if past_lhs.unreachable.get() {
1941
        return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock();
1942 1943
    }

1944 1945
    let join = fcx.new_id_block("join", binop_expr.id);
    let before_rhs = fcx.new_id_block("before_rhs", b.id);
1946 1947

    match op {
1948 1949
      lazy_and => CondBr(past_lhs, lhs, before_rhs.llbb, join.llbb, DebugLoc::None),
      lazy_or => CondBr(past_lhs, lhs, join.llbb, before_rhs.llbb, DebugLoc::None)
1950
    }
1951

1952 1953
    let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b);
    let rhs = rhs.to_llscalarish(past_rhs);
1954

1955
    if past_rhs.unreachable.get() {
1956
        return immediate_rvalue_bcx(join, lhs, binop_ty).to_expr_datumblock();
1957 1958
    }

1959
    Br(past_rhs, join.llbb, DebugLoc::None);
N
Nick Cameron 已提交
1960 1961
    let phi = Phi(join, Type::i1(bcx.ccx()), &[lhs, rhs],
                  &[past_lhs.llbb, past_rhs.llbb]);
1962

1963
    return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
1964 1965
}

1966
fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1967 1968 1969 1970
                            expr: &hir::Expr,
                            op: hir::BinOp,
                            lhs: &hir::Expr,
                            rhs: &hir::Expr)
1971
                            -> DatumBlock<'blk, 'tcx, Expr> {
1972
    let _icx = push_ctxt("trans_binary");
1973
    let ccx = bcx.ccx();
1974

1975
    // if overloaded, would be RvalueDpsExpr
1976
    assert!(!ccx.tcx().is_method_call(expr.id));
1977

1978
    match op.node {
1979
        hir::BiAnd => {
1980
            trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
1981
        }
1982
        hir::BiOr => {
1983
            trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
1984 1985 1986
        }
        _ => {
            let mut bcx = bcx;
1987
            let binop_ty = expr_ty(bcx, expr);
1988

A
Ariel Ben-Yehuda 已提交
1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006
            let lhs = unpack_datum!(bcx, trans(bcx, lhs));
            let lhs = unpack_datum!(bcx, lhs.to_rvalue_datum(bcx, "binop_lhs"));
            debug!("trans_binary (expr {}): lhs={}",
                   expr.id, lhs.to_string(ccx));
            let rhs = unpack_datum!(bcx, trans(bcx, rhs));
            let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "binop_rhs"));
            debug!("trans_binary (expr {}): rhs={}",
                   expr.id, rhs.to_string(ccx));

            if type_is_fat_ptr(ccx.tcx(), lhs.ty) {
                assert!(type_is_fat_ptr(ccx.tcx(), rhs.ty),
                        "built-in binary operators on fat pointers are homogeneous");
                trans_fat_ptr_binop(bcx, expr, binop_ty, op, lhs, rhs)
            } else {
                assert!(!type_is_fat_ptr(ccx.tcx(), rhs.ty),
                        "built-in binary operators on fat pointers are homogeneous");
                trans_scalar_binop(bcx, expr, binop_ty, op, lhs, rhs)
            }
2007 2008 2009 2010
        }
    }
}

2011
fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2012
                                   expr: &hir::Expr,
2013
                                   method_call: MethodCall,
2014
                                   lhs: Datum<'tcx, Expr>,
2015
                                   rhs: Option<(Datum<'tcx, Expr>, ast::NodeId)>,
2016 2017
                                   dest: Option<Dest>,
                                   autoref: bool)
2018
                                   -> Result<'blk, 'tcx> {
2019
    callee::trans_call_inner(bcx,
2020
                             expr.debug_loc(),
2021
                             |bcx, arg_cleanup_scope| {
2022
                                meth::trans_method_callee(bcx,
2023 2024
                                                          method_call,
                                                          None,
2025
                                                          arg_cleanup_scope)
2026
                             },
2027
                             callee::ArgOverloadedOp(lhs, rhs, autoref),
2028
                             dest)
2029 2030
}

2031
fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
2032 2033 2034
                                         expr: &hir::Expr,
                                         callee: &'a hir::Expr,
                                         args: &'a [P<hir::Expr>],
2035 2036
                                         dest: Option<Dest>)
                                         -> Block<'blk, 'tcx> {
2037
    debug!("trans_overloaded_call {}", expr.id);
2038
    let method_call = MethodCall::expr(expr.id);
2039
    let mut all_args = vec!(callee);
2040
    all_args.extend(args.iter().map(|e| &**e));
2041 2042
    unpack_result!(bcx,
                   callee::trans_call_inner(bcx,
2043
                                            expr.debug_loc(),
2044 2045 2046 2047 2048 2049 2050
                                            |bcx, arg_cleanup_scope| {
                                                meth::trans_method_callee(
                                                    bcx,
                                                    method_call,
                                                    None,
                                                    arg_cleanup_scope)
                                            },
2051
                                            callee::ArgOverloadedCall(all_args),
2052 2053 2054 2055
                                            dest));
    bcx
}

2056
pub fn cast_is_noop<'tcx>(tcx: &ty::ctxt<'tcx>,
2057
                          expr: &hir::Expr,
2058 2059 2060 2061 2062
                          t_in: Ty<'tcx>,
                          t_out: Ty<'tcx>)
                          -> bool {
    if let Some(&CastKind::CoercionCast) = tcx.cast_kinds.borrow().get(&expr.id) {
        return true;
2063 2064
    }

2065 2066
    match (t_in.builtin_deref(true, ty::NoPreference),
           t_out.builtin_deref(true, ty::NoPreference)) {
2067
        (Some(ty::TypeAndMut{ ty: t_in, .. }), Some(ty::TypeAndMut{ ty: t_out, .. })) => {
2068 2069
            t_in == t_out
        }
2070 2071 2072 2073 2074 2075
        _ => {
            // This condition isn't redundant with the check for CoercionCast:
            // different types can be substituted into the same type, and
            // == equality can be overconservative if there are regions.
            t_in == t_out
        }
2076 2077 2078
    }
}

2079
fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2080
                              expr: &hir::Expr,
2081
                              id: ast::NodeId)
2082 2083
                              -> DatumBlock<'blk, 'tcx, Expr>
{
2084 2085
    use middle::ty::cast::CastTy::*;
    use middle::ty::cast::IntTy::*;
2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123

    fn int_cast(bcx: Block,
                lldsttype: Type,
                llsrctype: Type,
                llsrc: ValueRef,
                signed: bool)
                -> ValueRef
    {
        let _icx = push_ctxt("int_cast");
        let srcsz = llsrctype.int_width();
        let dstsz = lldsttype.int_width();
        return if dstsz == srcsz {
            BitCast(bcx, llsrc, lldsttype)
        } else if srcsz > dstsz {
            TruncOrBitCast(bcx, llsrc, lldsttype)
        } else if signed {
            SExtOrBitCast(bcx, llsrc, lldsttype)
        } else {
            ZExtOrBitCast(bcx, llsrc, lldsttype)
        }
    }

    fn float_cast(bcx: Block,
                  lldsttype: Type,
                  llsrctype: Type,
                  llsrc: ValueRef)
                  -> ValueRef
    {
        let _icx = push_ctxt("float_cast");
        let srcsz = llsrctype.float_width();
        let dstsz = lldsttype.float_width();
        return if dstsz > srcsz {
            FPExt(bcx, llsrc, lldsttype)
        } else if srcsz > dstsz {
            FPTrunc(bcx, llsrc, lldsttype)
        } else { llsrc };
    }

A
Ariel Ben-Yehuda 已提交
2124 2125 2126
    let _icx = push_ctxt("trans_cast");
    let mut bcx = bcx;
    let ccx = bcx.ccx();
2127

N
Nick Cameron 已提交
2128
    let t_in = expr_ty_adjusted(bcx, expr);
2129
    let t_out = node_id_type(bcx, id);
2130

2131
    debug!("trans_cast({:?} as {:?})", t_in, t_out);
2132 2133
    let mut ll_t_in = type_of::arg_type_of(ccx, t_in);
    let ll_t_out = type_of::arg_type_of(ccx, t_out);
2134 2135
    // Convert the value to be cast into a ValueRef, either by-ref or
    // by-value as appropriate given its type:
2136 2137
    let mut datum = unpack_datum!(bcx, trans(bcx, expr));

N
Nick Cameron 已提交
2138
    let datum_ty = monomorphize_type(bcx, datum.ty);
2139 2140

    if cast_is_noop(bcx.tcx(), expr, datum_ty, t_out) {
2141 2142 2143 2144
        datum.ty = t_out;
        return DatumBlock::new(bcx, datum);
    }

2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155
    if type_is_fat_ptr(bcx.tcx(), t_in) {
        assert!(datum.kind.is_by_ref());
        if type_is_fat_ptr(bcx.tcx(), t_out) {
            return DatumBlock::new(bcx, Datum::new(
                PointerCast(bcx, datum.val, ll_t_out.ptr_to()),
                t_out,
                Rvalue::new(ByRef)
            )).to_expr_datumblock();
        } else {
            // Return the address
            return immediate_rvalue_bcx(bcx,
A
Ariel Ben-Yehuda 已提交
2156 2157 2158
                                        PointerCast(bcx,
                                                    Load(bcx, get_dataptr(bcx, datum.val)),
                                                    ll_t_out),
2159
                                        t_out).to_expr_datumblock();
2160
        }
2161 2162
    }

2163 2164
    let r_t_in = CastTy::from_ty(t_in).expect("bad input type for cast");
    let r_t_out = CastTy::from_ty(t_out).expect("bad output type for cast");
2165 2166 2167 2168 2169 2170 2171 2172 2173 2174

    let (llexpr, signed) = if let Int(CEnum) = r_t_in {
        let repr = adt::represent_type(ccx, t_in);
        let datum = unpack_datum!(
            bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
        let llexpr_ptr = datum.to_llref();
        let discr = adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
        ll_t_in = val_ty(discr);
        (discr, adt::is_discr_signed(&*repr))
    } else {
2175
        (datum.to_llscalarish(bcx), t_in.is_signed())
2176 2177 2178
    };

    let newval = match (r_t_in, r_t_out) {
A
Ariel Ben-Yehuda 已提交
2179 2180 2181 2182
        (Ptr(_), Ptr(_)) | (FnPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => {
            PointerCast(bcx, llexpr, ll_t_out)
        }
        (Ptr(_), Int(_)) | (FnPtr, Int(_)) => PtrToInt(bcx, llexpr, ll_t_out),
2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193
        (Int(_), Ptr(_)) => IntToPtr(bcx, llexpr, ll_t_out),

        (Int(_), Int(_)) => int_cast(bcx, ll_t_out, ll_t_in, llexpr, signed),
        (Float, Float) => float_cast(bcx, ll_t_out, ll_t_in, llexpr),
        (Int(_), Float) if signed => SIToFP(bcx, llexpr, ll_t_out),
        (Int(_), Float) => UIToFP(bcx, llexpr, ll_t_out),
        (Float, Int(I)) => FPToSI(bcx, llexpr, ll_t_out),
        (Float, Int(_)) => FPToUI(bcx, llexpr, ll_t_out),

        _ => ccx.sess().span_bug(expr.span,
                                  &format!("translating unsupported cast: \
2194 2195 2196
                                            {:?} -> {:?}",
                                           t_in,
                                           t_out)
2197
                                 )
2198 2199
    };
    return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
2200 2201
}

2202
fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2203 2204 2205 2206
                               expr: &hir::Expr,
                               op: hir::BinOp,
                               dst: &hir::Expr,
                               src: &hir::Expr)
2207
                               -> Block<'blk, 'tcx> {
2208
    let _icx = push_ctxt("trans_assign_op");
2209 2210
    let mut bcx = bcx;

2211
    debug!("trans_assign_op(expr={:?})", expr);
2212

2213
    // User-defined operator methods cannot be used with `+=` etc right now
2214
    assert!(!bcx.tcx().is_method_call(expr.id));
2215

2216
    // Evaluate LHS (destination), which should be an lvalue
A
Ariel Ben-Yehuda 已提交
2217 2218 2219 2220
    let dst = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
    assert!(!bcx.fcx.type_needs_drop(dst.ty));
    let lhs = load_ty(bcx, dst.val, dst.ty);
    let lhs = immediate_rvalue(lhs, dst.ty);
2221

A
Ariel Ben-Yehuda 已提交
2222 2223 2224
    // Evaluate RHS - FIXME(#28160) this sucks
    let rhs = unpack_datum!(bcx, trans(bcx, &*src));
    let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "assign_op_rhs"));
2225 2226

    // Perform computation and store the result
2227
    let result_datum = unpack_datum!(
A
Ariel Ben-Yehuda 已提交
2228 2229
        bcx, trans_scalar_binop(bcx, expr, dst.ty, op, lhs, rhs));
    return result_datum.store_to(bcx, dst.val);
2230 2231
}

2232
fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2233
                        datum: Datum<'tcx, Expr>,
2234
                        expr: &hir::Expr)
2235
                        -> DatumBlock<'blk, 'tcx, Expr> {
2236 2237 2238 2239 2240 2241 2242 2243 2244
    let mut bcx = bcx;

    // Ensure cleanup of `datum` if not already scheduled and obtain
    // a "by ref" pointer.
    let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id));

    // Compute final type. Note that we are loose with the region and
    // mutability, since those things don't matter in trans.
    let referent_ty = lv_datum.ty;
2245
    let ptr_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic), referent_ty);
2246 2247 2248 2249 2250 2251 2252

    // Get the pointer.
    let llref = lv_datum.to_llref();

    // Construct the resulting datum, using what was the "by ref"
    // ValueRef of type `referent_ty` to be the "by value" ValueRef
    // of type `&referent_ty`.
2253 2254 2255
    // Pointers to DST types are non-immediate, and therefore still use ByRef.
    let kind  = if type_is_sized(bcx.tcx(), referent_ty) { ByValue } else { ByRef };
    DatumBlock::new(bcx, Datum::new(llref, ptr_ty, RvalueExpr(Rvalue::new(kind))))
2256 2257
}

2258
fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2259
                              expr: &hir::Expr,
2260
                              datum: Datum<'tcx, Expr>,
2261
                              times: usize)
2262
                              -> DatumBlock<'blk, 'tcx, Expr> {
2263 2264
    let mut bcx = bcx;
    let mut datum = datum;
2265
    for i in 0..times {
2266
        let method_call = MethodCall::autoderef(expr.id, i as u32);
2267
        datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call));
2268 2269 2270 2271
    }
    DatumBlock { bcx: bcx, datum: datum }
}

2272
fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2273
                          expr: &hir::Expr,
2274
                          datum: Datum<'tcx, Expr>,
2275 2276
                          method_call: MethodCall)
                          -> DatumBlock<'blk, 'tcx, Expr> {
2277 2278
    let ccx = bcx.ccx();

2279 2280
    debug!("deref_once(expr={:?}, datum={}, method_call={:?})",
           expr,
2281
           datum.to_string(ccx),
2282
           method_call);
2283 2284 2285

    let mut bcx = bcx;

2286
    // Check for overloaded deref.
2287 2288 2289 2290
    let method_ty = ccx.tcx()
                       .tables
                       .borrow()
                       .method_map
2291
                       .get(&method_call).map(|method| method.ty);
2292

2293 2294
    let datum = match method_ty {
        Some(method_ty) => {
2295 2296
            let method_ty = monomorphize_type(bcx, method_ty);

2297 2298
            // Overloaded. Evaluate `trans_overloaded_op`, which will
            // invoke the user's deref() method, which basically
2299
            // converts from the `Smaht<T>` pointer that we have into
2300 2301
            // a `&T` pointer.  We can then proceed down the normal
            // path (below) to dereference that `&T`.
2302 2303 2304
            let datum = if method_call.autoderef == 0 {
                datum
            } else {
2305
                // Always perform an AutoPtr when applying an overloaded auto-deref
2306
                unpack_datum!(bcx, auto_ref(bcx, datum, expr))
2307
            };
2308

2309
            let ref_ty = // invoked methods have their LB regions instantiated
2310
                ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
2311 2312 2313
            let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");

            unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
2314
                                                    datum, None, Some(SaveIn(scratch.val)),
2315
                                                    false));
2316
            scratch.to_expr_datum()
2317
        }
2318 2319 2320 2321
        None => {
            // Not overloaded. We already have a pointer we know how to deref.
            datum
        }
2322 2323
    };

2324
    let r = match datum.ty.sty {
2325
        ty::TyBox(content_ty) => {
2326 2327 2328 2329 2330
            // Make sure we have an lvalue datum here to get the
            // proper cleanups scheduled
            let datum = unpack_datum!(
                bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));

2331
            if type_is_sized(bcx.tcx(), content_ty) {
2332
                let ptr = load_ty(bcx, datum.val, datum.ty);
2333
                DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr(datum.kind)))
N
Nick Cameron 已提交
2334
            } else {
2335 2336 2337 2338 2339
                // A fat pointer and a DST lvalue have the same representation
                // just different types. Since there is no temporary for `*e`
                // here (because it is unsized), we cannot emulate the sized
                // object code path for running drop glue and free. Instead,
                // we schedule cleanup for `e`, turning it into an lvalue.
2340

2341 2342
                let lval = Lvalue::new("expr::deref_once ty_uniq");
                let datum = Datum::new(datum.val, content_ty, LvalueExpr(lval));
2343
                DatumBlock::new(bcx, datum)
2344
            }
2345 2346
        }

2347 2348
        ty::TyRawPtr(ty::TypeAndMut { ty: content_ty, .. }) |
        ty::TyRef(_, ty::TypeAndMut { ty: content_ty, .. }) => {
2349
            let lval = Lvalue::new("expr::deref_once ptr");
2350
            if type_is_sized(bcx.tcx(), content_ty) {
N
Nick Cameron 已提交
2351 2352 2353 2354 2355 2356 2357
                let ptr = datum.to_llscalarish(bcx);

                // Always generate an lvalue datum, even if datum.mode is
                // an rvalue.  This is because datum.mode is only an
                // rvalue for non-owning pointers like &T or *T, in which
                // case cleanup *is* scheduled elsewhere, by the true
                // owner (or, in the case of *T, by the user).
2358
                DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr(lval)))
N
Nick Cameron 已提交
2359
            } else {
2360
                // A fat pointer and a DST lvalue have the same representation
N
Nick Cameron 已提交
2361
                // just different types.
2362
                DatumBlock::new(bcx, Datum::new(datum.val, content_ty, LvalueExpr(lval)))
2363
            }
2364 2365 2366 2367 2368
        }

        _ => {
            bcx.tcx().sess.span_bug(
                expr.span,
2369
                &format!("deref invoked on expr of invalid type {:?}",
2370
                        datum.ty));
2371 2372 2373
        }
    };

2374
    debug!("deref_once(expr={}, method_call={:?}, result={})",
2375
           expr.id, method_call, r.datum.to_string(ccx));
2376 2377

    return r;
2378
}
2379

2380
#[derive(Debug)]
2381 2382 2383 2384
enum OverflowOp {
    Add,
    Sub,
    Mul,
2385 2386
    Shl,
    Shr,
2387 2388 2389
}

impl OverflowOp {
2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409
    fn codegen_strategy(&self) -> OverflowCodegen {
        use self::OverflowCodegen::{ViaIntrinsic, ViaInputCheck};
        match *self {
            OverflowOp::Add => ViaIntrinsic(OverflowOpViaIntrinsic::Add),
            OverflowOp::Sub => ViaIntrinsic(OverflowOpViaIntrinsic::Sub),
            OverflowOp::Mul => ViaIntrinsic(OverflowOpViaIntrinsic::Mul),

            OverflowOp::Shl => ViaInputCheck(OverflowOpViaInputCheck::Shl),
            OverflowOp::Shr => ViaInputCheck(OverflowOpViaInputCheck::Shr),
        }
    }
}

enum OverflowCodegen {
    ViaIntrinsic(OverflowOpViaIntrinsic),
    ViaInputCheck(OverflowOpViaInputCheck),
}

enum OverflowOpViaInputCheck { Shl, Shr, }

2410
#[derive(Debug)]
2411 2412 2413 2414 2415 2416 2417
enum OverflowOpViaIntrinsic { Add, Sub, Mul, }

impl OverflowOpViaIntrinsic {
    fn to_intrinsic<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>, lhs_ty: Ty) -> ValueRef {
        let name = self.to_intrinsic_name(bcx.tcx(), lhs_ty);
        bcx.ccx().get_intrinsic(&name)
    }
2418
    fn to_intrinsic_name(&self, tcx: &ty::ctxt, ty: Ty) -> &'static str {
2419 2420
        use syntax::ast::IntTy::*;
        use syntax::ast::UintTy::*;
2421
        use middle::ty::{TyInt, TyUint};
2422 2423

        let new_sty = match ty.sty {
2424 2425 2426
            TyInt(TyIs) => match &tcx.sess.target.target.target_pointer_width[..] {
                "32" => TyInt(TyI32),
                "64" => TyInt(TyI64),
2427 2428
                _ => panic!("unsupported target word size")
            },
2429 2430 2431
            TyUint(TyUs) => match &tcx.sess.target.target.target_pointer_width[..] {
                "32" => TyUint(TyU32),
                "64" => TyUint(TyU64),
2432 2433
                _ => panic!("unsupported target word size")
            },
2434
            ref t @ TyUint(_) | ref t @ TyInt(_) => t.clone(),
2435 2436
            _ => panic!("tried to get overflow intrinsic for {:?} applied to non-int type",
                        *self)
2437 2438 2439
        };

        match *self {
2440
            OverflowOpViaIntrinsic::Add => match new_sty {
2441 2442 2443 2444
                TyInt(TyI8) => "llvm.sadd.with.overflow.i8",
                TyInt(TyI16) => "llvm.sadd.with.overflow.i16",
                TyInt(TyI32) => "llvm.sadd.with.overflow.i32",
                TyInt(TyI64) => "llvm.sadd.with.overflow.i64",
2445

2446 2447 2448 2449
                TyUint(TyU8) => "llvm.uadd.with.overflow.i8",
                TyUint(TyU16) => "llvm.uadd.with.overflow.i16",
                TyUint(TyU32) => "llvm.uadd.with.overflow.i32",
                TyUint(TyU64) => "llvm.uadd.with.overflow.i64",
2450 2451 2452

                _ => unreachable!(),
            },
2453
            OverflowOpViaIntrinsic::Sub => match new_sty {
2454 2455 2456 2457
                TyInt(TyI8) => "llvm.ssub.with.overflow.i8",
                TyInt(TyI16) => "llvm.ssub.with.overflow.i16",
                TyInt(TyI32) => "llvm.ssub.with.overflow.i32",
                TyInt(TyI64) => "llvm.ssub.with.overflow.i64",
2458

2459 2460 2461 2462
                TyUint(TyU8) => "llvm.usub.with.overflow.i8",
                TyUint(TyU16) => "llvm.usub.with.overflow.i16",
                TyUint(TyU32) => "llvm.usub.with.overflow.i32",
                TyUint(TyU64) => "llvm.usub.with.overflow.i64",
2463 2464 2465

                _ => unreachable!(),
            },
2466
            OverflowOpViaIntrinsic::Mul => match new_sty {
2467 2468 2469 2470 2471 2472 2473 2474 2475
                TyInt(TyI8) => "llvm.smul.with.overflow.i8",
                TyInt(TyI16) => "llvm.smul.with.overflow.i16",
                TyInt(TyI32) => "llvm.smul.with.overflow.i32",
                TyInt(TyI64) => "llvm.smul.with.overflow.i64",

                TyUint(TyU8) => "llvm.umul.with.overflow.i8",
                TyUint(TyU16) => "llvm.umul.with.overflow.i16",
                TyUint(TyU32) => "llvm.umul.with.overflow.i32",
                TyUint(TyU64) => "llvm.umul.with.overflow.i64",
2476 2477 2478 2479 2480 2481

                _ => unreachable!(),
            },
        }
    }

2482 2483 2484 2485 2486 2487 2488
    fn build_intrinsic_call<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>,
                                        info: NodeIdAndSpan,
                                        lhs_t: Ty<'tcx>, lhs: ValueRef,
                                        rhs: ValueRef,
                                        binop_debug_loc: DebugLoc)
                                        -> (Block<'blk, 'tcx>, ValueRef) {
        let llfn = self.to_intrinsic(bcx, lhs_t);
2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506

        let val = Call(bcx, llfn, &[lhs, rhs], None, binop_debug_loc);
        let result = ExtractValue(bcx, val, 0); // iN operation result
        let overflow = ExtractValue(bcx, val, 1); // i1 "did it overflow?"

        let cond = ICmp(bcx, llvm::IntEQ, overflow, C_integral(Type::i1(bcx.ccx()), 1, false),
                        binop_debug_loc);

        let expect = bcx.ccx().get_intrinsic(&"llvm.expect.i1");
        Call(bcx, expect, &[cond, C_integral(Type::i1(bcx.ccx()), 0, false)],
             None, binop_debug_loc);

        let bcx =
            base::with_cond(bcx, cond, |bcx|
                controlflow::trans_fail(bcx, info,
                    InternedString::new("arithmetic operation overflowed")));

        (bcx, result)
2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529
    }
}

impl OverflowOpViaInputCheck {
    fn build_with_input_check<'blk, 'tcx>(&self,
                                          bcx: Block<'blk, 'tcx>,
                                          info: NodeIdAndSpan,
                                          lhs_t: Ty<'tcx>,
                                          lhs: ValueRef,
                                          rhs: ValueRef,
                                          binop_debug_loc: DebugLoc)
                                          -> (Block<'blk, 'tcx>, ValueRef)
    {
        let lhs_llty = val_ty(lhs);
        let rhs_llty = val_ty(rhs);

        // Panic if any bits are set outside of bits that we always
        // mask in.
        //
        // Note that the mask's value is derived from the LHS type
        // (since that is where the 32/64 distinction is relevant) but
        // the mask's type must match the RHS type (since they will
        // both be fed into a and-binop)
2530
        let invert_mask = shift_mask_val(bcx, lhs_llty, rhs_llty, true);
2531 2532

        let outer_bits = And(bcx, rhs, invert_mask, binop_debug_loc);
2533
        let cond = build_nonzero_check(bcx, outer_bits, binop_debug_loc);
2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548
        let result = match *self {
            OverflowOpViaInputCheck::Shl =>
                build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc),
            OverflowOpViaInputCheck::Shr =>
                build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc),
        };
        let bcx =
            base::with_cond(bcx, cond, |bcx|
                controlflow::trans_fail(bcx, info,
                    InternedString::new("shift operation overflowed")));

        (bcx, result)
    }
}

2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588
fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                              llty: Type,
                              mask_llty: Type,
                              invert: bool) -> ValueRef {
    let kind = llty.kind();
    match kind {
        TypeKind::Integer => {
            // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
            let val = llty.int_width() - 1;
            if invert {
                C_integral(mask_llty, !val, true)
            } else {
                C_integral(mask_llty, val, false)
            }
        },
        TypeKind::Vector => {
            let mask = shift_mask_val(bcx, llty.element_type(), mask_llty.element_type(), invert);
            VectorSplat(bcx, mask_llty.vector_length(), mask)
        },
        _ => panic!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
    }
}

// Check if an integer or vector contains a nonzero element.
fn build_nonzero_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                   value: ValueRef,
                                   binop_debug_loc: DebugLoc) -> ValueRef {
    let llty = val_ty(value);
    let kind = llty.kind();
    match kind {
        TypeKind::Integer => ICmp(bcx, llvm::IntNE, value, C_null(llty), binop_debug_loc),
        TypeKind::Vector => {
            // Check if any elements of the vector are nonzero by treating
            // it as a wide integer and checking if the integer is nonzero.
            let width = llty.vector_length() as u64 * llty.element_type().int_width();
            let int_value = BitCast(bcx, value, Type::ix(bcx.ccx(), width));
            build_nonzero_check(bcx, int_value, binop_debug_loc)
        },
        _ => panic!("build_nonzero_check: expected Integer or Vector, found {:?}", kind),
    }
2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599
}

// To avoid UB from LLVM, these two functions mask RHS with an
// appropriate mask unconditionally (i.e. the fallback behavior for
// all shifts). For 32- and 64-bit types, this matches the semantics
// of Java. (See related discussion on #1877 and #10183.)

fn build_unchecked_lshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                      lhs: ValueRef,
                                      rhs: ValueRef,
                                      binop_debug_loc: DebugLoc) -> ValueRef {
2600
    let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShl, lhs, rhs);
2601 2602 2603 2604 2605 2606 2607 2608 2609 2610
    // #1877, #10183: Ensure that input is always valid
    let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
    Shl(bcx, lhs, rhs, binop_debug_loc)
}

fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                      lhs_t: Ty<'tcx>,
                                      lhs: ValueRef,
                                      rhs: ValueRef,
                                      binop_debug_loc: DebugLoc) -> ValueRef {
2611
    let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShr, lhs, rhs);
2612 2613
    // #1877, #10183: Ensure that input is always valid
    let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
2614
    let is_signed = lhs_t.is_signed();
2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625
    if is_signed {
        AShr(bcx, lhs, rhs, binop_debug_loc)
    } else {
        LShr(bcx, lhs, rhs, binop_debug_loc)
    }
}

fn shift_mask_rhs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                              rhs: ValueRef,
                              debug_loc: DebugLoc) -> ValueRef {
    let rhs_llty = val_ty(rhs);
2626
    And(bcx, rhs, shift_mask_val(bcx, rhs_llty, rhs_llty, false), debug_loc)
2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642
}

fn with_overflow_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, oop: OverflowOp, info: NodeIdAndSpan,
                                   lhs_t: Ty<'tcx>, lhs: ValueRef,
                                   rhs: ValueRef,
                                   binop_debug_loc: DebugLoc)
                                   -> (Block<'blk, 'tcx>, ValueRef) {
    if bcx.unreachable.get() { return (bcx, _Undef(lhs)); }
    if bcx.ccx().check_overflow() {

        match oop.codegen_strategy() {
            OverflowCodegen::ViaIntrinsic(oop) =>
                oop.build_intrinsic_call(bcx, info, lhs_t, lhs, rhs, binop_debug_loc),
            OverflowCodegen::ViaInputCheck(oop) =>
                oop.build_with_input_check(bcx, info, lhs_t, lhs, rhs, binop_debug_loc),
        }
2643 2644 2645 2646 2647
    } else {
        let res = match oop {
            OverflowOp::Add => Add(bcx, lhs, rhs, binop_debug_loc),
            OverflowOp::Sub => Sub(bcx, lhs, rhs, binop_debug_loc),
            OverflowOp::Mul => Mul(bcx, lhs, rhs, binop_debug_loc),
2648 2649 2650 2651 2652

            OverflowOp::Shl =>
                build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc),
            OverflowOp::Shr =>
                build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc),
2653 2654 2655 2656
        };
        (bcx, res)
    }
}
A
Ariel Ben-Yehuda 已提交
2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670

/// We categorize expressions into three kinds.  The distinction between
/// lvalue/rvalue is fundamental to the language.  The distinction between the
/// two kinds of rvalues is an artifact of trans which reflects how we will
/// generate code for that kind of expression.  See trans/expr.rs for more
/// information.
#[derive(Copy, Clone)]
enum ExprKind {
    Lvalue,
    RvalueDps,
    RvalueDatum,
    RvalueStmt
}

2671
fn expr_kind(tcx: &ty::ctxt, expr: &hir::Expr) -> ExprKind {
2672
    if tcx.is_method_call(expr.id) {
A
Ariel Ben-Yehuda 已提交
2673 2674 2675 2676
        // Overloaded operations are generally calls, and hence they are
        // generated via DPS, but there are a few exceptions:
        return match expr.node {
            // `a += b` has a unit result.
2677
            hir::ExprAssignOp(..) => ExprKind::RvalueStmt,
A
Ariel Ben-Yehuda 已提交
2678 2679

            // the deref method invoked for `*a` always yields an `&T`
2680
            hir::ExprUnary(hir::UnDeref, _) => ExprKind::Lvalue,
A
Ariel Ben-Yehuda 已提交
2681 2682

            // the index method invoked for `a[i]` always yields an `&T`
2683
            hir::ExprIndex(..) => ExprKind::Lvalue,
A
Ariel Ben-Yehuda 已提交
2684 2685 2686 2687 2688 2689 2690

            // in the general case, result could be any type, use DPS
            _ => ExprKind::RvalueDps
        };
    }

    match expr.node {
2691
        hir::ExprPath(..) => {
2692
            match tcx.resolve_expr(expr) {
A
Ariel Ben-Yehuda 已提交
2693
                def::DefStruct(_) | def::DefVariant(..) => {
2694
                    if let ty::TyBareFn(..) = tcx.node_id_to_type(expr.id).sty {
A
Ariel Ben-Yehuda 已提交
2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730
                        // ctor function
                        ExprKind::RvalueDatum
                    } else {
                        ExprKind::RvalueDps
                    }
                }

                // Special case: A unit like struct's constructor must be called without () at the
                // end (like `UnitStruct`) which means this is an ExprPath to a DefFn. But in case
                // of unit structs this is should not be interpreted as function pointer but as
                // call to the constructor.
                def::DefFn(_, true) => ExprKind::RvalueDps,

                // Fn pointers are just scalar values.
                def::DefFn(..) | def::DefMethod(..) => ExprKind::RvalueDatum,

                // Note: there is actually a good case to be made that
                // DefArg's, particularly those of immediate type, ought to
                // considered rvalues.
                def::DefStatic(..) |
                def::DefUpvar(..) |
                def::DefLocal(..) => ExprKind::Lvalue,

                def::DefConst(..) |
                def::DefAssociatedConst(..) => ExprKind::RvalueDatum,

                def => {
                    tcx.sess.span_bug(
                        expr.span,
                        &format!("uncategorized def for expr {}: {:?}",
                                expr.id,
                                def));
                }
            }
        }

2731 2732 2733 2734
        hir::ExprUnary(hir::UnDeref, _) |
        hir::ExprField(..) |
        hir::ExprTupField(..) |
        hir::ExprIndex(..) => {
A
Ariel Ben-Yehuda 已提交
2735 2736 2737
            ExprKind::Lvalue
        }

2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748
        hir::ExprCall(..) |
        hir::ExprMethodCall(..) |
        hir::ExprStruct(..) |
        hir::ExprRange(..) |
        hir::ExprTup(..) |
        hir::ExprIf(..) |
        hir::ExprMatch(..) |
        hir::ExprClosure(..) |
        hir::ExprBlock(..) |
        hir::ExprRepeat(..) |
        hir::ExprVec(..) => {
A
Ariel Ben-Yehuda 已提交
2749 2750 2751
            ExprKind::RvalueDps
        }

2752
        hir::ExprLit(ref lit) if ast_util::lit_is_str(&**lit) => {
A
Ariel Ben-Yehuda 已提交
2753 2754 2755
            ExprKind::RvalueDps
        }

2756 2757 2758 2759 2760 2761 2762 2763
        hir::ExprBreak(..) |
        hir::ExprAgain(..) |
        hir::ExprRet(..) |
        hir::ExprWhile(..) |
        hir::ExprLoop(..) |
        hir::ExprAssign(..) |
        hir::ExprInlineAsm(..) |
        hir::ExprAssignOp(..) => {
A
Ariel Ben-Yehuda 已提交
2764 2765 2766
            ExprKind::RvalueStmt
        }

2767 2768
        hir::ExprLit(_) | // Note: LitStr is carved out above
        hir::ExprUnary(..) |
2769
        hir::ExprBox(_) |
2770 2771 2772
        hir::ExprAddrOf(..) |
        hir::ExprBinary(..) |
        hir::ExprCast(..) => {
A
Ariel Ben-Yehuda 已提交
2773 2774 2775 2776
            ExprKind::RvalueDatum
        }
    }
}