expr.rs 103.0 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};
56
use middle::check_const;
57
use middle::def;
N
Nick Cameron 已提交
58
use middle::lang_items::CoerceUnsizedTraitLangItem;
59
use middle::mem_categorization::Typer;
N
Nick Cameron 已提交
60
use middle::subst::{Substs, VecPerParamSpace};
N
Nick Cameron 已提交
61
use middle::traits;
62
use trans::{_match, adt, asm, base, callee, closure, consts, controlflow};
63 64
use trans::base::*;
use trans::build::*;
65
use trans::cleanup::{self, CleanupMethods};
66 67
use trans::common::*;
use trans::datum::*;
68
use trans::debuginfo::{self, DebugLoc, ToDebugLoc};
69 70 71
use trans::glue;
use trans::machine;
use trans::meth;
72
use trans::monomorphize;
73 74
use trans::tvec;
use trans::type_of;
75
use middle::cast::{CastKind, CastTy};
76
use middle::ty::{struct_fields, tup_fields};
77
use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer};
78
use middle::ty::{self, Ty};
79
use middle::ty::MethodCall;
80
use util::common::indenter;
N
Niko Matsakis 已提交
81
use util::ppaux::Repr;
82 83
use trans::machine::{llsize_of, llsize_of_alloc};
use trans::type_::Type;
J
James Miller 已提交
84

85
use syntax::{ast, ast_util, codemap};
86
use syntax::parse::token::InternedString;
87
use syntax::ptr::P;
N
Nick Cameron 已提交
88
use syntax::parse::token;
A
Aaron Turon 已提交
89
use std::iter::repeat;
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 115 116 117
pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                              expr: &ast::Expr,
                              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 bcx.tcx().adjustments.borrow().contains_key(&expr.id) {
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
                ast::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.repr());
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

192
    let kind = ty::expr_kind(bcx.tcx(), expr);
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
    bcx = match kind {
        ty::LvalueExpr | ty::RvalueDatumExpr => {
            trans_unadjusted(bcx, expr).store_to_dest(dest, expr.id)
        }
        ty::RvalueDpsExpr => {
            trans_rvalue_dps_unadjusted(bcx, expr, dest)
        }
        ty::RvalueStmtExpr => {
            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 212 213
pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                         expr: &ast::Expr)
                         -> DatumBlock<'blk, 'tcx, Expr> {
214
    debug!("trans(expr={})", bcx.expr_to_string(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 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
            // 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());
            let datum = Datum::new(global, const_ty, Lvalue);
            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 {
            let llty = type_of::type_of(bcx.ccx(), const_ty);
            // HACK(eddyb) get around issues with lifetime intrinsics.
            let scratch = alloca_no_lifetime(bcx, llty, "const");
            let lldest = if !ty::type_is_structural(const_ty) {
                // 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
    };
270

271 272
    let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
                                                                          expr.id,
273 274 275
                                                                          expr.span,
                                                                          false);
    fcx.push_ast_cleanup_scope(cleanup_debug_loc);
276 277 278 279 280 281 282 283 284
    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))
    };
285
    bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id);
K
Kevin Butler 已提交
286
    return DatumBlock::new(bcx, datum);
287 288
}

289
pub fn get_len(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
290
    GEPi(bcx, fat_ptr, &[0, abi::FAT_PTR_EXTRA])
N
Nick Cameron 已提交
291 292
}

293
pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
294
    GEPi(bcx, fat_ptr, &[0, abi::FAT_PTR_ADDR])
N
Nick Cameron 已提交
295 296
}

297 298 299 300 301
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));
    Store(bcx, Load(bcx, get_len(bcx, src_ptr)), get_len(bcx, dst_ptr));
}

302 303 304 305 306 307 308 309 310 311
/// 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 已提交
312
                                param_substs: &'tcx Substs<'tcx>)
313 314 315
                                -> ValueRef {
    let (source, target) = ty::struct_lockstep_tails(ccx.tcx(), source, target);
    match (&source.sty, &target.sty) {
316
        (&ty::TyArray(_, len), &ty::TySlice(_)) => C_uint(ccx, len),
317
        (&ty::TyTrait(_), &ty::TyTrait(_)) => {
318 319 320 321 322
            // 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")
        }
323
        (_, &ty::TyTrait(box ty::TraitTy { ref principal, .. })) => {
324
            // Note that we preserve binding levels here:
325
            let substs = principal.0.substs.with_self_ty(source).erase_regions();
326
            let substs = ccx.tcx().mk_substs(substs);
327 328
            let trait_ref = ty::Binder(ty::TraitRef { def_id: principal.def_id(),
                                                      substs: substs });
329
            consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs),
330 331
                            Type::vtable_ptr(ccx))
        }
332
        _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {} -> {}",
333 334
                                     source.repr(),
                                     target.repr()))
335 336 337
    }
}

S
Steve Klabnik 已提交
338 339
/// Helper for trans that apply adjustments from `expr` to `datum`, which should be the unadjusted
/// translation of `expr`.
340 341
fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                 expr: &ast::Expr,
342
                                 datum: Datum<'tcx, Expr>)
343 344
                                 -> DatumBlock<'blk, 'tcx, Expr>
{
345 346
    let mut bcx = bcx;
    let mut datum = datum;
347
    let adjustment = match bcx.tcx().adjustments.borrow().get(&expr.id).cloned() {
348
        None => {
K
Kevin Butler 已提交
349
            return DatumBlock::new(bcx, datum);
350
        }
351
        Some(adj) => { adj }
352
    };
353
    debug!("unadjusted datum for expr {}: {} adjustment={:?}",
354
           expr.repr(),
355
           datum.to_string(bcx.ccx()),
356
           adjustment);
357
    match adjustment {
358
        AdjustReifyFnPointer => {
359 360
            // FIXME(#19925) once fn item types are
            // zero-sized, we'll need to do something here
361
        }
362 363 364
        AdjustUnsafeFnPointer => {
            // purely a type-level thing
        }
365
        AdjustDerefRef(ref adj) => {
366
            let skip_reborrows = if adj.autoderefs == 1 && adj.autoref.is_some() {
367 368
                // 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
369 370 371
                // 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.
372
                    ty::TyRef(..) => {
373 374 375 376 377 378
                        let method_call = MethodCall::autoderef(expr.id, 0);
                        if bcx.tcx().method_map.borrow().contains_key(&method_call) {
                            // Don't skip an overloaded deref.
                            0
                        } else {
                            1
379 380
                        }
                    }
381
                    _ => 0
382
                }
383 384
            } else {
                0
N
Nick Cameron 已提交
385 386
            };

387
            if adj.autoderefs > skip_reborrows {
388 389
                // Schedule cleanup.
                let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id));
390 391 392
                datum = unpack_datum!(bcx, deref_multiple(bcx, expr,
                                                          lval.to_expr_datum(),
                                                          adj.autoderefs - skip_reborrows));
393 394
            }

395
            // (You might think there is a more elegant way to do this than a
396 397
            // skip_reborrows bool, but then you remember that the borrow checker exists).
            if skip_reborrows == 0 && adj.autoref.is_some() {
N
Nick Cameron 已提交
398 399 400 401 402 403 404 405
                if !type_is_sized(bcx.tcx(), datum.ty) {
                    // Arrange cleanup
                    let lval = unpack_datum!(bcx,
                        datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id));
                    datum = unpack_datum!(bcx, ref_fat_ptr(bcx, lval));
                } else {
                    datum = unpack_datum!(bcx, auto_ref(bcx, datum, expr));
                }
406 407 408
            }

            if let Some(target) = adj.unsize {
N
Nick Cameron 已提交
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
                // 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);
                let llty = type_of::type_of(bcx.ccx(), target);

                // HACK(eddyb) get around issues with lifetime intrinsics.
                let scratch = alloca_no_lifetime(bcx, llty, "__coerce_target");
                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 已提交
427
            }
428
        }
429
    }
430
    debug!("after adjustments, datum={}", datum.to_string(bcx.ccx()));
N
Nick Cameron 已提交
431 432
    DatumBlock::new(bcx, datum)
}
433

N
Nick Cameron 已提交
434 435 436 437 438 439 440 441 442 443 444
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) {
445 446 447 448
        (&ty::TyBox(a), &ty::TyBox(b)) |
        (&ty::TyRef(_, ty::mt { ty: a, .. }), &ty::TyRef(_, ty::mt { ty: b, .. })) |
        (&ty::TyRef(_, ty::mt { ty: a, .. }), &ty::TyRawPtr(ty::mt { ty: b, .. })) |
        (&ty::TyRawPtr(ty::mt { ty: a, .. }), &ty::TyRawPtr(ty::mt { ty: b, .. })) => {
N
Nick Cameron 已提交
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
            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)),
                Some(Load(bcx, get_len(bcx, source.val))))
            } 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));
            Store(bcx, info, get_len(bcx, target.val));
479
        }
N
Nick Cameron 已提交
480

N
Nick Cameron 已提交
481
        // This can be extended to enums and tuples in the future.
482 483
        // (&ty::TyEnum(def_id_a, _), &ty::TyEnum(def_id_b, _)) |
        (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => {
N
Nick Cameron 已提交
484
            assert_eq!(def_id_a, def_id_b);
485

N
Nick Cameron 已提交
486 487 488
            // 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());
489

N
Nick Cameron 已提交
490 491 492
            let trait_substs = Substs::erased(VecPerParamSpace::new(vec![target.ty],
                                                                    vec![source.ty],
                                                                    Vec::new()));
N
Nick Cameron 已提交
493
            let trait_ref = ty::Binder(ty::TraitRef {
N
Nick Cameron 已提交
494 495 496
                def_id: langcall(bcx, Some(span), "coercion",
                                 CoerceUnsizedTraitLangItem),
                substs: bcx.tcx().mk_substs(trait_substs)
N
Nick Cameron 已提交
497
            });
N
Nick Cameron 已提交
498

N
Nick Cameron 已提交
499 500 501 502 503 504
            let kind = match fulfill_obligation(bcx.ccx(), span, trait_ref) {
                traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
                    ty::custom_coerce_unsized_kind(bcx.tcx(), impl_def_id)
                }
                vtable => {
                    bcx.sess().span_bug(span, &format!("invalid CoerceUnsized vtable: {}",
505
                                                       vtable.repr()));
N
Nick Cameron 已提交
506 507
                }
            };
N
Nick Cameron 已提交
508

N
Nick Cameron 已提交
509
            let repr_source = adt::represent_type(bcx.ccx(), source.ty);
N
Nick Cameron 已提交
510 511 512 513 514 515
            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 已提交
516
            let repr_target = adt::represent_type(bcx.ccx(), target.ty);
N
Nick Cameron 已提交
517 518 519 520 521 522
            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 已提交
523 524 525 526

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

529
            let iter = src_fields.iter().zip(target_fields).enumerate();
N
Nick Cameron 已提交
530
            for (i, (src_ty, target_ty)) in iter {
N
Nick Cameron 已提交
531 532 533 534 535 536
                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 已提交
537
                                   Datum::new(ll_source, src_ty,
N
Nick Cameron 已提交
538
                                              Rvalue::new(ByRef)),
N
Nick Cameron 已提交
539
                                   Datum::new(ll_target, target_ty,
N
Nick Cameron 已提交
540 541 542
                                              Rvalue::new(ByRef)));
                } else {
                    // Otherwise, simply copy the data from the source.
N
Nick Cameron 已提交
543 544
                    assert_eq!(src_ty, target_ty);
                    memcpy_ty(bcx, ll_target, ll_source, src_ty);
N
Nick Cameron 已提交
545 546 547 548
                }
            }
        }
        _ => bcx.sess().bug(&format!("coerce_unsized: invalid coercion {} -> {}",
549 550
                                     source.ty.repr(),
                                     target.ty.repr()))
551
    }
N
Nick Cameron 已提交
552
    bcx
553 554
}

S
Steve Klabnik 已提交
555 556 557 558 559 560 561
/// 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 }
562 563 564 565
pub fn trans_to_lvalue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                   expr: &ast::Expr,
                                   name: &str)
                                   -> DatumBlock<'blk, 'tcx, Lvalue> {
566 567 568
    let mut bcx = bcx;
    let datum = unpack_datum!(bcx, trans(bcx, expr));
    return datum.to_lvalue_datum(bcx, name, expr.id);
569 570
}

S
Steve Klabnik 已提交
571 572
/// A version of `trans` that ignores adjustments. You almost certainly do not want to call this
/// directly.
573 574 575
fn trans_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                expr: &ast::Expr)
                                -> DatumBlock<'blk, 'tcx, Expr> {
576 577
    let mut bcx = bcx;

578
    debug!("trans_unadjusted(expr={})", bcx.expr_to_string(expr));
579 580
    let _indenter = indenter();

581
    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
582

583
    return match ty::expr_kind(bcx.tcx(), expr) {
584
        ty::LvalueExpr | ty::RvalueDatumExpr => {
585
            let datum = unpack_datum!(bcx, {
586
                trans_datum_unadjusted(bcx, expr)
587
            });
588 589

            DatumBlock {bcx: bcx, datum: datum}
590 591 592
        }

        ty::RvalueStmtExpr => {
593
            bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
594
            nil(bcx, expr_ty(bcx, expr))
595 596 597 598
        }

        ty::RvalueDpsExpr => {
            let ty = expr_ty(bcx, expr);
599
            if type_is_zero_size(bcx.ccx(), ty) {
600
                bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
601
                nil(bcx, ty)
602
            } else {
603
                let scratch = rvalue_scratch_datum(bcx, ty, "");
604 605
                bcx = trans_rvalue_dps_unadjusted(
                    bcx, expr, SaveIn(scratch.val));
606 607 608 609 610 611 612 613 614 615

                // 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.
616 617
                let scratch = unpack_datum!(
                    bcx, scratch.to_appropriate_datum(bcx));
618

K
Kevin Butler 已提交
619
                DatumBlock::new(bcx, scratch.to_expr_datum())
620 621
            }
        }
622
    };
623

624
    fn nil<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>)
625
                       -> DatumBlock<'blk, 'tcx, Expr> {
626 627
        let llval = C_undef(type_of::type_of(bcx.ccx(), ty));
        let datum = immediate_rvalue(llval, ty);
K
Kevin Butler 已提交
628
        DatumBlock::new(bcx, datum.to_expr_datum())
629 630 631
    }
}

632 633 634
fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                      expr: &ast::Expr)
                                      -> DatumBlock<'blk, 'tcx, Expr> {
635 636 637
    let mut bcx = bcx;
    let fcx = bcx.fcx;
    let _icx = push_ctxt("trans_datum_unadjusted");
638 639

    match expr.node {
640 641
        ast::ExprParen(ref e) => {
            trans(bcx, &**e)
642
        }
643
        ast::ExprPath(..) => {
644 645
            trans_def(bcx, expr, bcx.def(expr.id))
        }
646
        ast::ExprField(ref base, ident) => {
647
            trans_rec_field(bcx, &**base, ident.node.name)
648
        }
649
        ast::ExprTupField(ref base, idx) => {
650 651
            trans_rec_tup_field(bcx, &**base, idx.node)
        }
N
Nick Cameron 已提交
652
        ast::ExprIndex(ref base, ref idx) => {
653
            trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
N
Nick Cameron 已提交
654
        }
655
        ast::ExprBox(_, ref contents) => {
E
Eduard Burtescu 已提交
656
            // Special case for `Box<T>`
657
            let box_ty = expr_ty(bcx, expr);
658
            let contents_ty = expr_ty(bcx, &**contents);
659
            match box_ty.sty {
660
                ty::TyBox(..) => {
661
                    trans_uniq_expr(bcx, expr, box_ty, &**contents, contents_ty)
662 663
                }
                _ => bcx.sess().span_bug(expr.span,
E
Eduard Burtescu 已提交
664
                                         "expected unique box")
665
            }
N
Nick Cameron 已提交
666

667
        }
668
        ast::ExprLit(ref lit) => trans_immediate_lit(bcx, expr, &**lit),
669 670
        ast::ExprBinary(op, ref lhs, ref rhs) => {
            trans_binary(bcx, expr, op, &**lhs, &**rhs)
671
        }
672 673
        ast::ExprUnary(op, ref x) => {
            trans_unary(bcx, expr, op, &**x)
674
        }
675
        ast::ExprAddrOf(_, ref x) => {
N
Nick Cameron 已提交
676 677 678
            match x.node {
                ast::ExprRepeat(..) | ast::ExprVec(..) => {
                    // Special case for slices.
679
                    let cleanup_debug_loc =
680 681 682 683
                        debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
                                                                      x.id,
                                                                      x.span,
                                                                      false);
684
                    fcx.push_ast_cleanup_scope(cleanup_debug_loc);
N
Nick Cameron 已提交
685 686 687 688 689 690 691 692 693
                    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)
                }
            }
694
        }
695
        ast::ExprCast(ref val, _) => {
696
            // Datum output mode means this is a scalar cast:
697
            trans_imm_cast(bcx, &**val, expr.id)
698
        }
699 700 701
        _ => {
            bcx.tcx().sess.span_bug(
                expr.span,
J
Jorge Aparicio 已提交
702
                &format!("trans_rvalue_datum_unadjusted reached \
703
                         fall-through case: {:?}",
704
                        expr.node));
705 706 707 708
        }
    }
}

709 710 711 712
fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                              base: &ast::Expr,
                              get_idx: F)
                              -> DatumBlock<'blk, 'tcx, Expr> where
713
    F: FnOnce(&'blk ty::ctxt<'tcx>, &[ty::field<'tcx>]) -> usize,
714
{
715 716 717 718
    let mut bcx = bcx;
    let _icx = push_ctxt("trans_rec_field");

    let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
719
    let bare_ty = base_datum.ty;
N
Nick Cameron 已提交
720
    let repr = adt::represent_type(bcx.ccx(), bare_ty);
721
    with_field_tys(bcx.tcx(), bare_ty, None, move |discr, field_tys| {
722
        let ix = get_idx(bcx.tcx(), field_tys);
N
Nick Cameron 已提交
723 724 725 726 727
        let d = base_datum.get_element(
            bcx,
            field_tys[ix].mt.ty,
            |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix));

728
        if type_is_sized(bcx.tcx(), d.ty) {
729
            DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
N
Nick Cameron 已提交
730
        } else {
731
            let scratch = rvalue_scratch_datum(bcx, d.ty, "");
N
Nick Cameron 已提交
732 733 734 735
            Store(bcx, d.val, get_dataptr(bcx, scratch.val));
            let info = Load(bcx, get_len(bcx, base_datum.val));
            Store(bcx, info, get_len(bcx, scratch.val));

736 737 738
            // 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))
N
Nick Cameron 已提交
739 740
        }
    })
741 742 743 744 745 746

}

/// Translates `base.field`.
fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                               base: &ast::Expr,
747
                               field: ast::Name)
748
                               -> DatumBlock<'blk, 'tcx, Expr> {
749
    trans_field(bcx, base, |tcx, field_tys| ty::field_idx_strict(tcx, field, field_tys))
750 751 752 753 754
}

/// Translates `base.<idx>`.
fn trans_rec_tup_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                   base: &ast::Expr,
755
                                   idx: usize)
756 757
                                   -> DatumBlock<'blk, 'tcx, Expr> {
    trans_field(bcx, base, |_, _| idx)
758 759
}

760 761 762 763 764 765
fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                           index_expr: &ast::Expr,
                           base: &ast::Expr,
                           idx: &ast::Expr,
                           method_call: MethodCall)
                           -> DatumBlock<'blk, 'tcx, Expr> {
766 767 768 769 770 771
    //! Translates `base[idx]`.

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

772 773
    let index_expr_debug_loc = index_expr.debug_loc();

774
    // Check for overloaded index.
775
    let method_ty = ccx.tcx()
776 777
                       .method_map
                       .borrow()
778
                       .get(&method_call)
779 780 781
                       .map(|method| method.ty);
    let elt_datum = match method_ty {
        Some(method_ty) => {
782 783
            let method_ty = monomorphize_type(bcx, method_ty);

784
            let base_datum = unpack_datum!(bcx, trans(bcx, base));
785

786 787
            // Translate index expression.
            let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
788

789
            let ref_ty = // invoked methods have LB regions instantiated:
790 791
                ty::no_late_bound_regions(
                    bcx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap().unwrap();
792 793 794 795 796 797 798 799
            let elt_ty = match ty::deref(ref_ty, true) {
                None => {
                    bcx.tcx().sess.span_bug(index_expr.span,
                                            "index method didn't return a \
                                             dereferenceable type?!")
                }
                Some(elt_tm) => elt_tm.ty,
            };
800 801 802 803 804 805 806 807 808 809 810 811

            // 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,
                                               vec![(ix_datum, idx.id)],
812
                                               Some(SaveIn(scratch.val)),
813
                                               false));
814
            let datum = scratch.to_expr_datum();
815
            if type_is_sized(bcx.tcx(), elt_ty) {
816 817
                Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr)
            } else {
818
                Datum::new(datum.val, elt_ty, LvalueExpr)
819
            }
820 821 822 823 824 825 826 827 828 829 830 831 832
        }
        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(),
833
                                                      ccx.int_type());
834 835 836
            let ix_val = {
                if ix_size < int_size {
                    if ty::type_is_signed(expr_ty(bcx, idx)) {
837 838
                        SExt(bcx, ix_val, ccx.int_type())
                    } else { ZExt(bcx, ix_val, ccx.int_type()) }
839
                } else if ix_size > int_size {
840
                    Trunc(bcx, ix_val, ccx.int_type())
841 842 843 844
                } else {
                    ix_val
                }
            };
845

846
            let unit_ty = ty::sequence_element_type(bcx.tcx(), base_datum.ty);
847 848 849

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

850 851
            debug!("trans_index: base {}", bcx.val_to_string(base));
            debug!("trans_index: len {}", bcx.val_to_string(len));
852

853 854 855 856 857
            let bounds_check = ICmp(bcx,
                                    llvm::IntUGE,
                                    ix_val,
                                    len,
                                    index_expr_debug_loc);
858 859 860
            let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
            let expected = Call(bcx,
                                expect,
N
Nick Cameron 已提交
861
                                &[bounds_check, C_bool(ccx, false)],
862
                                None,
863
                                index_expr_debug_loc);
864 865
            bcx = with_cond(bcx, expected, |bcx| {
                controlflow::trans_fail_bounds_check(bcx,
866
                                                     expr_info(index_expr),
867 868 869
                                                     ix_val,
                                                     len)
            });
N
Nick Cameron 已提交
870
            let elt = InBoundsGEP(bcx, base, &[ix_val]);
871 872
            let elt = PointerCast(bcx, elt, type_of::type_of(ccx, unit_ty).ptr_to());
            Datum::new(elt, unit_ty, LvalueExpr)
873 874
        }
    };
875

876
    DatumBlock::new(bcx, elt_datum)
877 878
}

879 880 881 882
fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                         ref_expr: &ast::Expr,
                         def: def::Def)
                         -> DatumBlock<'blk, 'tcx, Expr> {
883 884 885 886
    //! Translates a reference to a path.

    let _icx = push_ctxt("trans_def_lvalue");
    match def {
887
        def::DefFn(..) | def::DefMethod(..) |
888
        def::DefStruct(_) | def::DefVariant(..) => {
889 890 891
            let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def,
                                                bcx.fcx.param_substs);
            DatumBlock::new(bcx, datum.to_expr_datum())
892
        }
893
        def::DefStatic(did, _) => {
894
            // There are two things that may happen here:
895 896 897
            //  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.
898 899 900
            //  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.
901 902
            let const_ty = expr_ty(bcx, ref_expr);

903 904 905 906 907 908 909 910 911 912 913 914 915 916
            // For external constants, we don't inline.
            let val = if did.krate == ast::LOCAL_CRATE {
                // 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.
                let val = base::get_item_val(bcx.ccx(), did.node);
                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)
            };
K
Kevin Butler 已提交
917
            DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr))
918
        }
919 920 921
        def::DefConst(_) => {
            bcx.sess().span_bug(ref_expr.span,
                "constant expression should not reach expr::trans_def")
922
        }
923
        _ => {
K
Kevin Butler 已提交
924
            DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
925 926 927 928
        }
    }
}

929 930 931
fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                            expr: &ast::Expr)
                                            -> Block<'blk, 'tcx> {
932
    let mut bcx = bcx;
933
    let _icx = push_ctxt("trans_rvalue_stmt");
934

935
    if bcx.unreachable.get() {
936 937 938
        return bcx;
    }

939 940
    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);

941
    match expr.node {
942 943
        ast::ExprParen(ref e) => {
            trans_into(bcx, &**e, Ignore)
944
        }
945
        ast::ExprBreak(label_opt) => {
946
            controlflow::trans_break(bcx, expr, label_opt)
947
        }
948
        ast::ExprAgain(label_opt) => {
949
            controlflow::trans_cont(bcx, expr, label_opt)
950
        }
951
        ast::ExprRet(ref ex) => {
J
James Miller 已提交
952 953 954 955 956 957 958 959 960
            // 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 {
961
                controlflow::trans_ret(bcx, expr, ex.as_ref().map(|e| &**e))
J
James Miller 已提交
962 963 964 965 966 967
            } 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 已提交
968
                }
969 970 971 972
                // 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 已提交
973 974
                bcx
            }
975
        }
P
Pythoner6 已提交
976
        ast::ExprWhile(ref cond, ref body, _) => {
977
            controlflow::trans_while(bcx, expr, &**cond, &**body)
978
        }
979
        ast::ExprLoop(ref body, _) => {
980
            controlflow::trans_loop(bcx, expr, &**body)
981
        }
982
        ast::ExprAssign(ref dst, ref src) => {
983
            let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
984
            let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &**dst, "assign"));
985

986
            if bcx.fcx.type_needs_drop(dst_datum.ty) {
987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002
                // 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`.
1003
                debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
1004 1005
                let src_datum = unpack_datum!(
                    bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign"));
1006 1007 1008
                bcx = glue::drop_ty(bcx,
                                    dst_datum.val,
                                    dst_datum.ty,
1009
                                    expr.debug_loc());
1010 1011
                src_datum.store_to(bcx, dst_datum.val)
            } else {
1012
                src_datum.store_to(bcx, dst_datum.val)
1013
            }
1014
        }
1015
        ast::ExprAssignOp(op, ref dst, ref src) => {
1016
            trans_assign_op(bcx, expr, op, &**dst, &**src)
1017
        }
1018
        ast::ExprInlineAsm(ref a) => {
1019
            asm::trans_inline_asm(bcx, a)
1020
        }
1021 1022 1023
        _ => {
            bcx.tcx().sess.span_bug(
                expr.span,
J
Jorge Aparicio 已提交
1024
                &format!("trans_rvalue_stmt_unadjusted reached \
1025
                         fall-through case: {:?}",
1026
                        expr.node));
1027
        }
1028
    }
1029 1030
}

1031 1032 1033 1034
fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                           expr: &ast::Expr,
                                           dest: Dest)
                                           -> Block<'blk, 'tcx> {
1035
    let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
1036
    let mut bcx = bcx;
1037 1038
    let tcx = bcx.tcx();

1039 1040
    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);

1041
    match expr.node {
1042 1043
        ast::ExprParen(ref e) => {
            trans_into(bcx, &**e, dest)
1044
        }
1045
        ast::ExprPath(..) => {
1046
            trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
1047
        }
1048 1049
        ast::ExprIf(ref cond, ref thn, ref els) => {
            controlflow::trans_if(bcx, expr.id, &**cond, &**thn, els.as_ref().map(|e| &**e), dest)
1050
        }
1051
        ast::ExprMatch(ref discr, ref arms, _) => {
1052
            _match::trans_match(bcx, expr, &**discr, &arms[..], dest)
1053
        }
1054 1055
        ast::ExprBlock(ref blk) => {
            controlflow::trans_block(bcx, &**blk, dest)
1056
        }
1057
        ast::ExprStruct(_, ref fields, ref base) => {
1058
            trans_struct(bcx,
1059
                         &fields[..],
1060
                         base.as_ref().map(|e| &**e),
1061 1062
                         expr.span,
                         expr.id,
N
Nick Cameron 已提交
1063
                         node_id_type(bcx, expr.id),
1064
                         dest)
1065
        }
N
Nick Cameron 已提交
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
        ast::ExprRange(ref start, ref end) => {
            // FIXME it is just not right that we are synthesising ast nodes in
            // trans. Shudder.
            fn make_field(field_name: &str, expr: P<ast::Expr>) -> ast::Field {
                ast::Field {
                    ident: codemap::dummy_spanned(token::str_to_ident(field_name)),
                    expr: expr,
                    span: codemap::DUMMY_SP,
                }
            }

            // A range just desugars into a struct.
1078 1079 1080 1081 1082
            // 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 已提交
1083
                    // Desugar to Range
N
Nick Cameron 已提交
1084 1085
                    let fields = vec![make_field("start", start.clone()),
                                      make_field("end", end.clone())];
1086
                    (tcx.lang_items.range_struct(), fields, vec![node_id_type(bcx, start.id)])
N
Nick Cameron 已提交
1087
                }
1088
                (&Some(ref start), &None) => {
N
Nick Cameron 已提交
1089
                    // Desugar to RangeFrom
N
Nick Cameron 已提交
1090
                    let fields = vec![make_field("start", start.clone())];
1091 1092 1093 1094
                    (tcx.lang_items.range_from_struct(), fields, vec![node_id_type(bcx, start.id)])
                }
                (&None, &Some(ref end)) => {
                    // Desugar to RangeTo
N
Nick Cameron 已提交
1095
                    let fields = vec![make_field("end", end.clone())];
1096 1097 1098
                    (tcx.lang_items.range_to_struct(), fields, vec![node_id_type(bcx, end.id)])
                }
                _ => {
N
Nick Cameron 已提交
1099 1100
                    // Desugar to RangeFull
                    (tcx.lang_items.range_full_struct(), vec![], vec![])
N
Nick Cameron 已提交
1101 1102 1103 1104
                }
            };

            if let Some(did) = did {
1105
                let substs = Substs::new_type(ty_params, vec![]);
N
Nick Cameron 已提交
1106
                trans_struct(bcx,
1107
                             &fields,
N
Nick Cameron 已提交
1108 1109 1110
                             None,
                             expr.span,
                             expr.id,
H
Huon Wilson 已提交
1111
                             ty::mk_struct(tcx, did, tcx.mk_substs(substs)),
N
Nick Cameron 已提交
1112 1113 1114 1115 1116 1117
                             dest)
            } else {
                tcx.sess.span_bug(expr.span,
                                  "No lang item for ranges (how did we get this far?)")
            }
        }
1118
        ast::ExprTup(ref args) => {
1119
            let numbered_fields: Vec<(usize, &ast::Expr)> =
1120
                args.iter().enumerate().map(|(i, arg)| (i, &**arg)).collect();
1121 1122 1123
            trans_adt(bcx,
                      expr_ty(bcx, expr),
                      0,
1124
                      &numbered_fields[..],
1125 1126
                      None,
                      dest,
1127
                      expr.debug_loc())
1128
        }
1129
        ast::ExprLit(ref lit) => {
1130
            match lit.node {
1131 1132
                ast::LitStr(ref s, _) => {
                    tvec::trans_lit_str(bcx, expr, (*s).clone(), dest)
1133 1134 1135 1136 1137 1138 1139 1140 1141
                }
                _ => {
                    bcx.tcx()
                       .sess
                       .span_bug(expr.span,
                                 "trans_rvalue_dps_unadjusted shouldn't be \
                                  translating this type of literal")
                }
            }
1142
        }
A
Alex Crichton 已提交
1143
        ast::ExprVec(..) | ast::ExprRepeat(..) => {
N
Nick Cameron 已提交
1144
            tvec::trans_fixed_vstore(bcx, expr, dest)
1145
        }
1146
        ast::ExprClosure(_, ref decl, ref body) => {
1147 1148 1149 1150
            let dest = match dest {
                SaveIn(lldest) => closure::Dest::SaveIn(bcx, lldest),
                Ignore => closure::Dest::Ignore(bcx.ccx())
            };
1151
            closure::trans_closure_expr(dest, decl, body, expr.id, bcx.fcx.param_substs)
1152
                .unwrap_or(bcx)
1153
        }
1154
        ast::ExprCall(ref f, ref args) => {
1155 1156 1157
            if bcx.tcx().is_method_call(expr.id) {
                trans_overloaded_call(bcx,
                                      expr,
1158
                                      &**f,
1159
                                      &args[..],
1160 1161 1162 1163
                                      Some(dest))
            } else {
                callee::trans_call(bcx,
                                   expr,
1164
                                   &**f,
1165
                                   callee::ArgExprs(&args[..]),
1166 1167
                                   dest)
            }
1168
        }
1169
        ast::ExprMethodCall(_, _, ref args) => {
1170 1171
            callee::trans_method_call(bcx,
                                      expr,
1172
                                      &*args[0],
1173
                                      callee::ArgExprs(&args[..]),
1174
                                      dest)
1175
        }
1176
        ast::ExprBinary(op, ref lhs, ref rhs) => {
1177
            // if not overloaded, would be RvalueDatumExpr
1178 1179
            let lhs = unpack_datum!(bcx, trans(bcx, &**lhs));
            let rhs_datum = unpack_datum!(bcx, trans(bcx, &**rhs));
1180
            trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs,
1181
                                vec![(rhs_datum, rhs.id)], Some(dest),
1182
                                !ast_util::is_by_value_binop(op.node)).bcx
1183
        }
1184
        ast::ExprUnary(op, ref subexpr) => {
1185
            // if not overloaded, would be RvalueDatumExpr
1186
            let arg = unpack_datum!(bcx, trans(bcx, &**subexpr));
1187
            trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
1188
                                arg, Vec::new(), Some(dest), !ast_util::is_by_value_unop(op)).bcx
1189
        }
1190
        ast::ExprIndex(ref base, ref idx) => {
1191
            // if not overloaded, would be RvalueDatumExpr
1192 1193
            let base = unpack_datum!(bcx, trans(bcx, &**base));
            let idx_datum = unpack_datum!(bcx, trans(bcx, &**idx));
1194
            trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
1195
                                vec![(idx_datum, idx.id)], Some(dest), true).bcx
1196
        }
N
Nick Cameron 已提交
1197 1198 1199
        ast::ExprCast(..) => {
            // 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?)")
1200
        }
1201
        ast::ExprAssignOp(op, ref dst, ref src) => {
1202
            trans_assign_op(bcx, expr, op, &**dst, &**src)
1203 1204 1205 1206
        }
        _ => {
            bcx.tcx().sess.span_bug(
                expr.span,
J
Jorge Aparicio 已提交
1207
                &format!("trans_rvalue_dps_unadjusted reached fall-through \
1208
                         case: {:?}",
1209
                        expr.node));
1210 1211 1212 1213
        }
    }
}

1214 1215 1216 1217 1218
fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                        ref_expr: &ast::Expr,
                                        def: def::Def,
                                        dest: Dest)
                                        -> Block<'blk, 'tcx> {
1219
    let _icx = push_ctxt("trans_def_dps_unadjusted");
1220 1221 1222 1223 1224 1225 1226

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

    match def {
1227
        def::DefVariant(tid, vid, _) => {
1228
            let variant_info = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
1229
            if !variant_info.args.is_empty() {
1230
                // N-ary variant.
1231 1232 1233
                let llfn = callee::trans_fn_ref(bcx.ccx(), vid,
                                                ExprId(ref_expr.id),
                                                bcx.fcx.param_substs).val;
1234
                Store(bcx, llfn, lldest);
1235
                return bcx;
1236
            } else {
1237 1238
                // Nullary variant.
                let ty = expr_ty(bcx, ref_expr);
1239
                let repr = adt::represent_type(bcx.ccx(), ty);
1240 1241
                adt::trans_set_discr(bcx, &*repr, lldest,
                                     variant_info.disr_val);
1242
                return bcx;
1243 1244
            }
        }
1245
        def::DefStruct(_) => {
1246
            let ty = expr_ty(bcx, ref_expr);
1247
            match ty.sty {
1248
                ty::TyStruct(did, _) if ty::has_dtor(bcx.tcx(), did) => {
1249
                    let repr = adt::represent_type(bcx.ccx(), ty);
1250
                    adt::trans_set_discr(bcx, &*repr, lldest, 0);
1251
                }
1252
                _ => {}
1253
            }
1254
            bcx
1255
        }
1256
        _ => {
J
Jorge Aparicio 已提交
1257
            bcx.tcx().sess.span_bug(ref_expr.span, &format!(
1258
                "Non-DPS def {:?} referened by {}",
1259
                def, bcx.node_id_to_string(ref_expr.id)));
1260 1261 1262 1263
        }
    }
}

1264 1265 1266
pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                         ref_expr: &ast::Expr,
                                         def: def::Def,
N
Nick Cameron 已提交
1267
                                         param_substs: &'tcx Substs<'tcx>)
1268
                                         -> Datum<'tcx, Rvalue> {
1269
    let _icx = push_ctxt("trans_def_datum_unadjusted");
1270

1271
    match def {
1272
        def::DefFn(did, _) |
1273
        def::DefStruct(did) | def::DefVariant(_, did, _) |
1274
        def::DefMethod(did, def::FromImpl(_)) => {
1275
            callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs)
1276
        }
1277
        def::DefMethod(impl_did, def::FromTrait(trait_did)) => {
1278 1279 1280
            meth::trans_static_method_callee(ccx, impl_did,
                                             trait_did, ref_expr.id,
                                             param_substs)
1281 1282
        }
        _ => {
J
Jorge Aparicio 已提交
1283
            ccx.tcx().sess.span_bug(ref_expr.span, &format!(
1284
                    "trans_def_fn_unadjusted invoked on: {:?} for {}",
1285
                    def,
1286
                    ref_expr.repr()));
1287
        }
1288
    }
1289 1290
}

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

1297
    match def {
1298
        def::DefUpvar(nid, _) => {
1299
            // Can't move upvars, so this is never a ZeroMemLastUse.
1300
            let local_ty = node_id_type(bcx, nid);
1301
            match bcx.fcx.llupvars.borrow().get(&nid) {
K
Kevin Butler 已提交
1302
                Some(&val) => Datum::new(val, local_ty, Lvalue),
1303
                None => {
J
Jorge Aparicio 已提交
1304
                    bcx.sess().bug(&format!(
L
Luqman Aden 已提交
1305
                        "trans_local_var: no llval for upvar {} found",
1306
                        nid));
1307 1308 1309
                }
            }
        }
1310
        def::DefLocal(nid) => {
1311
            let datum = match bcx.fcx.lllocals.borrow().get(&nid) {
1312 1313
                Some(&v) => v,
                None => {
J
Jorge Aparicio 已提交
1314
                    bcx.sess().bug(&format!(
L
Luqman Aden 已提交
1315
                        "trans_local_var: no datum for local/arg {} found",
1316
                        nid));
1317 1318
                }
            };
L
Luqman Aden 已提交
1319
            debug!("take_local(nid={}, v={}, ty={})",
1320 1321
                   nid, bcx.val_to_string(datum.val), bcx.ty_to_string(datum.ty));
            datum
1322 1323
        }
        _ => {
J
Jorge Aparicio 已提交
1324
            bcx.sess().unimpl(&format!(
1325
                "unsupported def type in trans_local_var: {:?}",
1326
                def));
1327 1328 1329 1330
        }
    }
}

S
Steve Klabnik 已提交
1331 1332 1333
/// Helper for enumerating the field types of structs, enums, or records. The optional node ID here
/// is the node ID of the path identifying the enum variant in use. If none, this cannot possibly
/// an enum variant (so, if it is and `node_id_opt` is none, this function panics).
1334 1335 1336 1337 1338 1339 1340
pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>,
                                  ty: Ty<'tcx>,
                                  node_id_opt: Option<ast::NodeId>,
                                  op: F)
                                  -> R where
    F: FnOnce(ty::Disr, &[ty::field<'tcx>]) -> R,
{
1341
    match ty.sty {
1342
        ty::TyStruct(did, substs) => {
1343 1344
            let fields = struct_fields(tcx, did, substs);
            let fields = monomorphize::normalize_associated_type(tcx, &fields);
1345
            op(0, &fields[..])
1346 1347
        }

1348
        ty::TyTuple(ref v) => {
1349
            op(0, &tup_fields(&v[..]))
1350 1351
        }

1352
        ty::TyEnum(_, substs) => {
1353 1354 1355
            // We want the *variant* ID here, not the enum ID.
            match node_id_opt {
                None => {
J
Jorge Aparicio 已提交
1356
                    tcx.sess.bug(&format!(
A
Alex Crichton 已提交
1357
                        "cannot get field types from the enum type {} \
1358
                         without a node ID",
1359
                        ty.repr()));
1360 1361
                }
                Some(node_id) => {
1362
                    let def = tcx.def_map.borrow().get(&node_id).unwrap().full_def();
1363
                    match def {
1364
                        def::DefVariant(enum_id, variant_id, _) => {
1365
                            let variant_info = ty::enum_variant_with_id(tcx, enum_id, variant_id);
1366 1367
                            let fields = struct_fields(tcx, variant_id, substs);
                            let fields = monomorphize::normalize_associated_type(tcx, &fields);
1368
                            op(variant_info.disr_val, &fields[..])
1369 1370
                        }
                        _ => {
1371 1372
                            tcx.sess.bug("resolve didn't map this expr to a \
                                          variant ID")
1373 1374 1375 1376 1377 1378
                        }
                    }
                }
            }
        }

1379
        _ => {
J
Jorge Aparicio 已提交
1380
            tcx.sess.bug(&format!(
A
Alex Crichton 已提交
1381
                "cannot get field types from the type {}",
1382
                ty.repr()));
1383 1384 1385 1386
        }
    }
}

1387 1388
fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                            fields: &[ast::Field],
1389
                            base: Option<&ast::Expr>,
1390
                            expr_span: codemap::Span,
1391
                            expr_id: ast::NodeId,
N
Nick Cameron 已提交
1392
                            ty: Ty<'tcx>,
1393
                            dest: Dest) -> Block<'blk, 'tcx> {
1394
    let _icx = push_ctxt("trans_rec");
1395 1396

    let tcx = bcx.tcx();
1397
    with_field_tys(tcx, ty, Some(expr_id), |discr, field_tys| {
N
fallout  
Nick Cameron 已提交
1398
        let mut need_base: Vec<bool> = repeat(true).take(field_tys.len()).collect();
1399

1400
        let numbered_fields = fields.iter().map(|field| {
1401 1402
            let opt_pos =
                field_tys.iter().position(|field_ty|
1403
                                          field_ty.name == field.ident.node.name);
N
fallout  
Nick Cameron 已提交
1404
            let result = match opt_pos {
1405
                Some(i) => {
1406
                    need_base[i] = false;
1407
                    (i, &*field.expr)
1408
                }
1409 1410
                None => {
                    tcx.sess.span_bug(field.span,
J
Jeong YunWon 已提交
1411
                                      "Couldn't find field in struct type")
1412
                }
N
fallout  
Nick Cameron 已提交
1413 1414
            };
            result
1415
        }).collect::<Vec<_>>();
1416 1417
        let optbase = match base {
            Some(base_expr) => {
1418
                let mut leftovers = Vec::new();
D
Daniel Micay 已提交
1419
                for (i, b) in need_base.iter().enumerate() {
1420
                    if *b {
N
fallout  
Nick Cameron 已提交
1421
                        leftovers.push((i, field_tys[i].mt.ty));
1422
                    }
1423
                }
1424 1425
                Some(StructBaseInfo {expr: base_expr,
                                     fields: leftovers })
1426
            }
1427
            None => {
1428
                if need_base.iter().any(|b| *b) {
1429
                    tcx.sess.span_bug(expr_span, "missing fields and no base expr")
1430 1431 1432 1433
                }
                None
            }
        };
1434

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

S
Steve Klabnik 已提交
1445 1446 1447 1448 1449 1450
/// 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.
1451
pub struct StructBaseInfo<'a, 'tcx> {
1452
    /// The base expression; will be evaluated after all explicit fields.
1453
    expr: &'a ast::Expr,
1454
    /// The indices of fields to copy paired with their types.
1455
    fields: Vec<(usize, Ty<'tcx>)>
1456
}
1457

S
Steve Klabnik 已提交
1458 1459 1460 1461 1462 1463 1464 1465
/// 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`.
1466 1467 1468
pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                 ty: Ty<'tcx>,
                                 discr: ty::Disr,
1469
                                 fields: &[(usize, &ast::Expr)],
1470 1471
                                 optbase: Option<StructBaseInfo<'a, 'tcx>>,
                                 dest: Dest,
1472
                                 debug_location: DebugLoc)
1473
                                 -> Block<'blk, 'tcx> {
1474
    let _icx = push_ctxt("trans_adt");
1475
    let fcx = bcx.fcx;
1476 1477
    let repr = adt::represent_type(bcx.ccx(), ty);

1478
    debug_location.apply(bcx.fcx);
1479

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

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

1491 1492 1493 1494 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
    if ty::type_is_simd(bcx.tcx(), ty) {
        // 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.
1530 1531 1532
        assert_eq!(discr, 0);

        match ty::expr_kind(bcx.tcx(), &*base.expr) {
1533
            ty::RvalueDpsExpr | ty::RvalueDatumExpr if !bcx.fcx.type_needs_drop(ty) => {
1534 1535 1536 1537
                bcx = trans_into(bcx, &*base.expr, SaveIn(addr));
            },
            ty::RvalueStmtExpr => bcx.tcx().sess.bug("unexpected expr kind for struct base expr"),
            _ => {
1538
                let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base"));
1539
                for &(i, t) in &base.fields {
1540
                    let datum = base_datum.get_element(
N
Nick Cameron 已提交
1541
                            bcx, t, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, i));
1542
                    assert!(type_is_sized(bcx.tcx(), datum.ty));
1543
                    let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
1544 1545
                    bcx = datum.store_to(bcx, dest);
                }
1546
            }
1547
        }
1548

1549
        // Finally, move scratch field values into actual field locations
1550
        for (i, datum) in scratch_vals {
1551 1552
            let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
            bcx = datum.store_to(bcx, dest);
1553 1554
        }
    } else {
1555
        // No base means we can write all fields directly in place.
1556
        for &(i, ref e) in fields {
1557 1558 1559 1560 1561 1562 1563
            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);
            fcx.schedule_drop_mem(scope, dest, e_ty);
        }
1564
    }
1565

1566
    adt::trans_set_discr(bcx, &*repr, addr, discr);
1567

1568 1569
    fcx.pop_custom_cleanup_scope(custom_cleanup_scope);

1570 1571 1572 1573
    // If we don't care about the result drop the temporary we made
    match dest {
        SaveIn(_) => bcx,
        Ignore => {
1574
            bcx = glue::drop_ty(bcx, addr, ty, debug_location);
1575 1576 1577 1578
            base::call_lifetime_end(bcx, addr);
            bcx
        }
    }
1579 1580
}

1581

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

1593 1594 1595 1596 1597
fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                           expr: &ast::Expr,
                           op: ast::UnOp,
                           sub_expr: &ast::Expr)
                           -> DatumBlock<'blk, 'tcx, Expr> {
1598
    let ccx = bcx.ccx();
1599
    let mut bcx = bcx;
1600
    let _icx = push_ctxt("trans_unary_datum");
1601

1602
    let method_call = MethodCall::expr(expr.id);
1603 1604 1605 1606 1607 1608

    // 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.
    assert!(
        op == ast::UnDeref ||
1609
        !ccx.tcx().method_map.borrow().contains_key(&method_call));
1610

1611
    let un_ty = expr_ty(bcx, expr);
1612

1613 1614
    let debug_loc = expr.debug_loc();

1615
    match op {
1616
        ast::UnNot => {
1617
            let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1618
            let llresult = Not(bcx, datum.to_llscalarish(bcx), debug_loc);
1619
            immediate_rvalue_bcx(bcx, llresult, un_ty).to_expr_datumblock()
1620
        }
1621
        ast::UnNeg => {
1622 1623
            let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
            let val = datum.to_llscalarish(bcx);
1624
            let (bcx, llneg) = {
1625
                if ty::type_is_fp(un_ty) {
1626 1627
                    let result = FNeg(bcx, val, debug_loc);
                    (bcx, result)
1628
                } else {
1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
                    let is_signed = ty::type_is_signed(un_ty);
                    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)
1644 1645
                }
            };
1646
            immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
1647
        }
1648
        ast::UnUniq => {
1649
            trans_uniq_expr(bcx, expr, un_ty, sub_expr, expr_ty(bcx, sub_expr))
1650
        }
1651
        ast::UnDeref => {
1652
            let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1653
            deref_once(bcx, expr, datum, method_call)
1654
        }
1655
    }
1656
}
1657

1658
fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1659
                               box_expr: &ast::Expr,
1660
                               box_ty: Ty<'tcx>,
1661
                               contents: &ast::Expr,
1662
                               contents_ty: Ty<'tcx>)
1663
                               -> DatumBlock<'blk, 'tcx, Expr> {
E
Eduard Burtescu 已提交
1664
    let _icx = push_ctxt("trans_uniq_expr");
1665
    let fcx = bcx.fcx;
1666
    assert!(type_is_sized(bcx.tcx(), contents_ty));
E
Eduard Burtescu 已提交
1667 1668
    let llty = type_of::type_of(bcx.ccx(), contents_ty);
    let size = llsize_of(bcx.ccx(), llty);
1669
    let align = C_uint(bcx.ccx(), type_of::align_of(bcx.ccx(), contents_ty));
N
Nick Cameron 已提交
1670
    let llty_ptr = llty.ptr_to();
1671 1672 1673 1674 1675 1676
    let Result { bcx, val } = malloc_raw_dyn(bcx,
                                             llty_ptr,
                                             box_ty,
                                             size,
                                             align,
                                             box_expr.debug_loc());
1677 1678 1679
    // 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 已提交
1680 1681
    let bcx = if llsize_of_alloc(bcx.ccx(), llty) == 0 {
        trans_into(bcx, contents, SaveIn(val))
1682
    } else {
1683 1684
        let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
        fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
1685
                                val, cleanup::HeapExchange, contents_ty);
E
Eduard Burtescu 已提交
1686
        let bcx = trans_into(bcx, contents, SaveIn(val));
1687
        fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
E
Eduard Burtescu 已提交
1688 1689 1690 1691 1692
        bcx
    };
    immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
}

1693 1694 1695
fn ref_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                           lval: Datum<'tcx, Lvalue>)
                           -> DatumBlock<'blk, 'tcx, Expr> {
1696
    let dest_ty = ty::mk_imm_rptr(bcx.tcx(), bcx.tcx().mk_region(ty::ReStatic), lval.ty);
1697 1698 1699 1700 1701 1702
    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())
}

1703 1704 1705 1706
fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                             expr: &ast::Expr,
                             subexpr: &ast::Expr)
                             -> DatumBlock<'blk, 'tcx, Expr> {
1707
    let _icx = push_ctxt("trans_addr_of");
1708
    let mut bcx = bcx;
1709
    let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
1710 1711 1712 1713 1714 1715 1716
    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 已提交
1717
    }
1718 1719 1720 1721
}

// Important to get types for both lhs and rhs, because one might be _|_
// and the other not.
1722 1723
fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                 binop_expr: &ast::Expr,
1724
                                 binop_ty: Ty<'tcx>,
1725
                                 op: ast::BinOp,
1726
                                 lhs_t: Ty<'tcx>,
1727
                                 lhs: ValueRef,
1728
                                 rhs_t: Ty<'tcx>,
1729 1730
                                 rhs: ValueRef)
                                 -> DatumBlock<'blk, 'tcx, Expr> {
1731
    let _icx = push_ctxt("trans_eager_binop");
1732

1733 1734
    let tcx = bcx.tcx();
    let is_simd = ty::type_is_simd(tcx, lhs_t);
1735 1736 1737 1738
    let intype = if is_simd {
        ty::simd_type(tcx, lhs_t)
    } else {
        lhs_t
1739 1740
    };
    let is_float = ty::type_is_fp(intype);
1741
    let is_signed = ty::type_is_signed(intype);
1742
    let info = expr_info(binop_expr);
1743

1744 1745
    let binop_debug_loc = binop_expr.debug_loc();

1746
    let mut bcx = bcx;
1747
    let val = match op.node {
1748
      ast::BiAdd => {
1749 1750
        if is_float {
            FAdd(bcx, lhs, rhs, binop_debug_loc)
J
Jihyun Yu 已提交
1751 1752
        } else if is_simd {
            Add(bcx, lhs, rhs, binop_debug_loc)
1753
        } else {
1754 1755 1756 1757
            let (newbcx, res) = with_overflow_check(
                bcx, OverflowOp::Add, info, lhs_t, lhs, rhs, binop_debug_loc);
            bcx = newbcx;
            res
1758
        }
1759
      }
1760
      ast::BiSub => {
1761 1762
        if is_float {
            FSub(bcx, lhs, rhs, binop_debug_loc)
J
Jihyun Yu 已提交
1763 1764
        } else if is_simd {
            Sub(bcx, lhs, rhs, binop_debug_loc)
1765
        } else {
1766 1767 1768 1769
            let (newbcx, res) = with_overflow_check(
                bcx, OverflowOp::Sub, info, lhs_t, lhs, rhs, binop_debug_loc);
            bcx = newbcx;
            res
1770
        }
1771
      }
1772
      ast::BiMul => {
1773 1774
        if is_float {
            FMul(bcx, lhs, rhs, binop_debug_loc)
J
Jihyun Yu 已提交
1775 1776
        } else if is_simd {
            Mul(bcx, lhs, rhs, binop_debug_loc)
1777
        } else {
1778 1779 1780 1781
            let (newbcx, res) = with_overflow_check(
                bcx, OverflowOp::Mul, info, lhs_t, lhs, rhs, binop_debug_loc);
            bcx = newbcx;
            res
1782
        }
1783
      }
1784
      ast::BiDiv => {
1785
        if is_float {
1786
            FDiv(bcx, lhs, rhs, binop_debug_loc)
1787 1788
        } else {
            // Only zero-check integers; fp /0 is NaN
1789 1790 1791 1792 1793 1794
            bcx = base::fail_if_zero_or_overflows(bcx,
                                                  expr_info(binop_expr),
                                                  op,
                                                  lhs,
                                                  rhs,
                                                  rhs_t);
1795
            if is_signed {
1796
                SDiv(bcx, lhs, rhs, binop_debug_loc)
1797
            } else {
1798
                UDiv(bcx, lhs, rhs, binop_debug_loc)
1799 1800 1801
            }
        }
      }
1802
      ast::BiRem => {
1803
        if is_float {
1804
            FRem(bcx, lhs, rhs, binop_debug_loc)
1805 1806
        } else {
            // Only zero-check integers; fp %0 is NaN
1807 1808
            bcx = base::fail_if_zero_or_overflows(bcx,
                                                  expr_info(binop_expr),
1809
                                                  op, lhs, rhs, rhs_t);
1810
            if is_signed {
1811
                SRem(bcx, lhs, rhs, binop_debug_loc)
1812
            } else {
1813
                URem(bcx, lhs, rhs, binop_debug_loc)
1814 1815 1816
            }
        }
      }
1817 1818 1819
      ast::BiBitOr => Or(bcx, lhs, rhs, binop_debug_loc),
      ast::BiBitAnd => And(bcx, lhs, rhs, binop_debug_loc),
      ast::BiBitXor => Xor(bcx, lhs, rhs, binop_debug_loc),
1820 1821 1822 1823 1824 1825
      ast::BiShl => {
          let (newbcx, res) = with_overflow_check(
              bcx, OverflowOp::Shl, info, lhs_t, lhs, rhs, binop_debug_loc);
          bcx = newbcx;
          res
      }
1826
      ast::BiShr => {
1827 1828 1829 1830
          let (newbcx, res) = with_overflow_check(
              bcx, OverflowOp::Shr, info, lhs_t, lhs, rhs, binop_debug_loc);
          bcx = newbcx;
          res
1831
      }
1832
      ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
1833 1834
        if is_simd {
            base::compare_simd_types(bcx, lhs, rhs, intype, op.node, binop_debug_loc)
1835
        } else {
1836
            base::compare_scalar_types(bcx, lhs, rhs, intype, op.node, binop_debug_loc)
1837 1838
        }
      }
1839
      _ => {
J
Jeong YunWon 已提交
1840
        bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
1841 1842 1843
      }
    };

1844
    immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
1845 1846 1847
}

// refinement types would obviate the need for this
1848 1849 1850 1851
enum lazy_binop_ty {
    lazy_and,
    lazy_or,
}
1852

1853 1854 1855 1856 1857 1858
fn trans_lazy_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                binop_expr: &ast::Expr,
                                op: lazy_binop_ty,
                                a: &ast::Expr,
                                b: &ast::Expr)
                                -> DatumBlock<'blk, 'tcx, Expr> {
1859
    let _icx = push_ctxt("trans_lazy_binop");
1860
    let binop_ty = expr_ty(bcx, binop_expr);
1861
    let fcx = bcx.fcx;
1862

1863 1864
    let DatumBlock {bcx: past_lhs, datum: lhs} = trans(bcx, a);
    let lhs = lhs.to_llscalarish(past_lhs);
1865

1866
    if past_lhs.unreachable.get() {
1867
        return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock();
1868 1869
    }

1870 1871
    let join = fcx.new_id_block("join", binop_expr.id);
    let before_rhs = fcx.new_id_block("before_rhs", b.id);
1872 1873

    match op {
1874 1875
      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)
1876
    }
1877

1878 1879
    let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b);
    let rhs = rhs.to_llscalarish(past_rhs);
1880

1881
    if past_rhs.unreachable.get() {
1882
        return immediate_rvalue_bcx(join, lhs, binop_ty).to_expr_datumblock();
1883 1884
    }

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

1889
    return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
1890 1891
}

1892 1893 1894 1895 1896 1897
fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                            expr: &ast::Expr,
                            op: ast::BinOp,
                            lhs: &ast::Expr,
                            rhs: &ast::Expr)
                            -> DatumBlock<'blk, 'tcx, Expr> {
1898
    let _icx = push_ctxt("trans_binary");
1899
    let ccx = bcx.ccx();
1900

1901
    // if overloaded, would be RvalueDpsExpr
1902
    assert!(!ccx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
1903

1904
    match op.node {
1905
        ast::BiAnd => {
1906
            trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
1907
        }
1908
        ast::BiOr => {
1909
            trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
1910 1911 1912
        }
        _ => {
            let mut bcx = bcx;
1913 1914
            let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
            let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
1915
            let binop_ty = expr_ty(bcx, expr);
1916 1917

            debug!("trans_binary (expr {}): lhs_datum={}",
1918
                   expr.id,
1919
                   lhs_datum.to_string(ccx));
1920 1921 1922 1923
            let lhs_ty = lhs_datum.ty;
            let lhs = lhs_datum.to_llscalarish(bcx);

            debug!("trans_binary (expr {}): rhs_datum={}",
1924
                   expr.id,
1925
                   rhs_datum.to_string(ccx));
1926 1927
            let rhs_ty = rhs_datum.ty;
            let rhs = rhs_datum.to_llscalarish(bcx);
1928
            trans_eager_binop(bcx, expr, binop_ty, op,
1929
                              lhs_ty, lhs, rhs_ty, rhs)
1930 1931 1932 1933
        }
    }
}

1934 1935 1936
fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                   expr: &ast::Expr,
                                   method_call: MethodCall,
1937 1938
                                   lhs: Datum<'tcx, Expr>,
                                   rhs: Vec<(Datum<'tcx, Expr>, ast::NodeId)>,
1939 1940
                                   dest: Option<Dest>,
                                   autoref: bool)
1941
                                   -> Result<'blk, 'tcx> {
1942
    let method_ty = bcx.tcx().method_map.borrow().get(&method_call).unwrap().ty;
1943
    callee::trans_call_inner(bcx,
1944
                             expr.debug_loc(),
1945
                             monomorphize_type(bcx, method_ty),
1946
                             |bcx, arg_cleanup_scope| {
1947
                                meth::trans_method_callee(bcx,
1948 1949
                                                          method_call,
                                                          None,
1950
                                                          arg_cleanup_scope)
1951
                             },
1952
                             callee::ArgOverloadedOp(lhs, rhs, autoref),
1953
                             dest)
1954 1955
}

1956 1957 1958 1959 1960 1961
fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                         expr: &ast::Expr,
                                         callee: &'a ast::Expr,
                                         args: &'a [P<ast::Expr>],
                                         dest: Option<Dest>)
                                         -> Block<'blk, 'tcx> {
1962
    debug!("trans_overloaded_call {}", expr.id);
1963
    let method_call = MethodCall::expr(expr.id);
1964 1965 1966 1967 1968 1969
    let method_type = bcx.tcx()
                         .method_map
                         .borrow()
                         .get(&method_call)
                         .unwrap()
                         .ty;
1970
    let mut all_args = vec!(callee);
1971
    all_args.extend(args.iter().map(|e| &**e));
1972 1973
    unpack_result!(bcx,
                   callee::trans_call_inner(bcx,
1974
                                            expr.debug_loc(),
1975 1976 1977 1978 1979 1980 1981 1982 1983
                                            monomorphize_type(bcx,
                                                              method_type),
                                            |bcx, arg_cleanup_scope| {
                                                meth::trans_method_callee(
                                                    bcx,
                                                    method_call,
                                                    None,
                                                    arg_cleanup_scope)
                                            },
1984
                                            callee::ArgOverloadedCall(all_args),
1985 1986 1987 1988
                                            dest));
    bcx
}

1989 1990 1991 1992 1993 1994 1995
pub fn cast_is_noop<'tcx>(tcx: &ty::ctxt<'tcx>,
                          expr: &ast::Expr,
                          t_in: Ty<'tcx>,
                          t_out: Ty<'tcx>)
                          -> bool {
    if let Some(&CastKind::CoercionCast) = tcx.cast_kinds.borrow().get(&expr.id) {
        return true;
1996 1997
    }

1998 1999 2000 2001
    match (ty::deref(t_in, true), ty::deref(t_out, true)) {
        (Some(ty::mt{ ty: t_in, .. }), Some(ty::mt{ ty: t_out, .. })) => {
            t_in == t_out
        }
2002 2003 2004 2005 2006 2007
        _ => {
            // 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
        }
2008 2009 2010
    }
}

2011 2012 2013
fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                              expr: &ast::Expr,
                              id: ast::NodeId)
2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055
                              -> DatumBlock<'blk, 'tcx, Expr>
{
    use middle::cast::CastTy::*;
    use middle::cast::IntTy::*;

    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 已提交
2056 2057 2058
    let _icx = push_ctxt("trans_cast");
    let mut bcx = bcx;
    let ccx = bcx.ccx();
2059

N
Nick Cameron 已提交
2060
    let t_in = expr_ty_adjusted(bcx, expr);
2061
    let t_out = node_id_type(bcx, id);
2062

2063
    debug!("trans_cast({} as {})", t_in.repr(), t_out.repr());
2064 2065
    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);
2066 2067
    // Convert the value to be cast into a ValueRef, either by-ref or
    // by-value as appropriate given its type:
2068 2069
    let mut datum = unpack_datum!(bcx, trans(bcx, expr));

N
Nick Cameron 已提交
2070
    let datum_ty = monomorphize_type(bcx, datum.ty);
2071 2072

    if cast_is_noop(bcx.tcx(), expr, datum_ty, t_out) {
2073 2074 2075 2076
        datum.ty = t_out;
        return DatumBlock::new(bcx, datum);
    }

2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087
    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 已提交
2088 2089 2090
                                        PointerCast(bcx,
                                                    Load(bcx, get_dataptr(bcx, datum.val)),
                                                    ll_t_out),
2091
                                        t_out).to_expr_datumblock();
2092
        }
2093 2094
    }

A
Ariel Ben-Yehuda 已提交
2095 2096
    let r_t_in = CastTy::from_ty(bcx.tcx(), t_in).expect("bad input type for cast");
    let r_t_out = CastTy::from_ty(bcx.tcx(), t_out).expect("bad output type for cast");
2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110

    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 {
        (datum.to_llscalarish(bcx), ty::type_is_signed(t_in))
    };

    let newval = match (r_t_in, r_t_out) {
A
Ariel Ben-Yehuda 已提交
2111 2112 2113 2114
        (Ptr(_), Ptr(_)) | (FnPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => {
            PointerCast(bcx, llexpr, ll_t_out)
        }
        (Ptr(_), Int(_)) | (FnPtr, Int(_)) => PtrToInt(bcx, llexpr, ll_t_out),
2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126
        (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: \
                                            {} -> {}",
2127 2128
                                           t_in.repr(),
                                           t_out.repr())
2129
                                 )
2130 2131
    };
    return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
2132 2133
}

2134 2135 2136 2137
fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                               expr: &ast::Expr,
                               op: ast::BinOp,
                               dst: &ast::Expr,
2138
                               src: &ast::Expr)
2139
                               -> Block<'blk, 'tcx> {
2140
    let _icx = push_ctxt("trans_assign_op");
2141 2142
    let mut bcx = bcx;

2143
    debug!("trans_assign_op(expr={})", bcx.expr_to_string(expr));
2144

2145
    // User-defined operator methods cannot be used with `+=` etc right now
2146
    assert!(!bcx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
2147

2148 2149
    // Evaluate LHS (destination), which should be an lvalue
    let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
2150
    assert!(!bcx.fcx.type_needs_drop(dst_datum.ty));
2151
    let dst_ty = dst_datum.ty;
2152
    let dst = load_ty(bcx, dst_datum.val, dst_datum.ty);
2153

2154
    // Evaluate RHS
2155
    let rhs_datum = unpack_datum!(bcx, trans(bcx, &*src));
2156 2157
    let rhs_ty = rhs_datum.ty;
    let rhs = rhs_datum.to_llscalarish(bcx);
2158 2159

    // Perform computation and store the result
2160 2161 2162 2163
    let result_datum = unpack_datum!(
        bcx, trans_eager_binop(bcx, expr, dst_datum.ty, op,
                               dst_ty, dst, rhs_ty, rhs));
    return result_datum.store_to(bcx, dst_datum.val);
2164 2165
}

2166
fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2167
                        datum: Datum<'tcx, Expr>,
2168 2169
                        expr: &ast::Expr)
                        -> DatumBlock<'blk, 'tcx, Expr> {
2170 2171 2172 2173 2174 2175 2176 2177 2178
    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;
H
Huon Wilson 已提交
2179
    let ptr_ty = ty::mk_imm_rptr(bcx.tcx(), bcx.tcx().mk_region(ty::ReStatic), referent_ty);
2180 2181 2182 2183 2184 2185 2186

    // 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`.
2187 2188 2189
    // 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))))
2190 2191
}

2192 2193
fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                              expr: &ast::Expr,
2194
                              datum: Datum<'tcx, Expr>,
2195
                              times: usize)
2196
                              -> DatumBlock<'blk, 'tcx, Expr> {
2197 2198
    let mut bcx = bcx;
    let mut datum = datum;
2199
    for i in 0..times {
2200
        let method_call = MethodCall::autoderef(expr.id, i as u32);
2201
        datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call));
2202 2203 2204 2205
    }
    DatumBlock { bcx: bcx, datum: datum }
}

2206 2207
fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                          expr: &ast::Expr,
2208
                          datum: Datum<'tcx, Expr>,
2209 2210
                          method_call: MethodCall)
                          -> DatumBlock<'blk, 'tcx, Expr> {
2211 2212
    let ccx = bcx.ccx();

2213
    debug!("deref_once(expr={}, datum={}, method_call={:?})",
2214
           expr.repr(),
2215
           datum.to_string(ccx),
2216
           method_call);
2217 2218 2219

    let mut bcx = bcx;

2220
    // Check for overloaded deref.
2221
    let method_ty = ccx.tcx().method_map.borrow()
2222
                       .get(&method_call).map(|method| method.ty);
2223 2224
    let datum = match method_ty {
        Some(method_ty) => {
2225 2226
            let method_ty = monomorphize_type(bcx, method_ty);

2227 2228
            // Overloaded. Evaluate `trans_overloaded_op`, which will
            // invoke the user's deref() method, which basically
2229
            // converts from the `Smaht<T>` pointer that we have into
2230 2231
            // a `&T` pointer.  We can then proceed down the normal
            // path (below) to dereference that `&T`.
2232 2233 2234
            let datum = if method_call.autoderef == 0 {
                datum
            } else {
2235
                // Always perform an AutoPtr when applying an overloaded auto-deref
2236
                unpack_datum!(bcx, auto_ref(bcx, datum, expr))
2237
            };
2238

2239
            let ref_ty = // invoked methods have their LB regions instantiated
2240 2241
                ty::no_late_bound_regions(
                    ccx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap().unwrap();
2242 2243 2244
            let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");

            unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
2245 2246
                                                    datum, Vec::new(), Some(SaveIn(scratch.val)),
                                                    false));
2247
            scratch.to_expr_datum()
2248
        }
2249 2250 2251 2252
        None => {
            // Not overloaded. We already have a pointer we know how to deref.
            datum
        }
2253 2254
    };

2255
    let r = match datum.ty.sty {
2256
        ty::TyBox(content_ty) => {
2257 2258 2259 2260 2261
            // 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));

2262
            if type_is_sized(bcx.tcx(), content_ty) {
2263 2264
                let ptr = load_ty(bcx, datum.val, datum.ty);
                DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr))
N
Nick Cameron 已提交
2265
            } else {
2266 2267 2268 2269 2270
                // 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.
2271

2272
                let datum = Datum::new(datum.val, content_ty, LvalueExpr);
2273
                DatumBlock::new(bcx, datum)
2274
            }
2275 2276
        }

2277 2278
        ty::TyRawPtr(ty::mt { ty: content_ty, .. }) |
        ty::TyRef(_, ty::mt { ty: content_ty, .. }) => {
2279
            if type_is_sized(bcx.tcx(), content_ty) {
N
Nick Cameron 已提交
2280 2281 2282 2283 2284 2285 2286 2287 2288
                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).
                DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr))
            } else {
2289
                // A fat pointer and a DST lvalue have the same representation
N
Nick Cameron 已提交
2290
                // just different types.
2291
                DatumBlock::new(bcx, Datum::new(datum.val, content_ty, LvalueExpr))
2292
            }
2293 2294 2295 2296 2297
        }

        _ => {
            bcx.tcx().sess.span_bug(
                expr.span,
J
Jorge Aparicio 已提交
2298
                &format!("deref invoked on expr of illegal type {}",
2299
                        datum.ty.repr()));
2300 2301 2302
        }
    };

2303
    debug!("deref_once(expr={}, method_call={:?}, result={})",
2304
           expr.id, method_call, r.datum.to_string(ccx));
2305 2306

    return r;
2307
}
2308

2309
#[derive(Debug)]
2310 2311 2312 2313
enum OverflowOp {
    Add,
    Sub,
    Mul,
2314 2315
    Shl,
    Shr,
2316 2317 2318
}

impl OverflowOp {
2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338
    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, }

2339
#[derive(Debug)]
2340 2341 2342 2343 2344 2345 2346
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)
    }
2347 2348 2349
    fn to_intrinsic_name(&self, tcx: &ty::ctxt, ty: Ty) -> &'static str {
        use syntax::ast::IntTy::*;
        use syntax::ast::UintTy::*;
2350
        use middle::ty::{TyInt, TyUint};
2351 2352

        let new_sty = match ty.sty {
2353 2354 2355
            TyInt(TyIs) => match &tcx.sess.target.target.target_pointer_width[..] {
                "32" => TyInt(TyI32),
                "64" => TyInt(TyI64),
2356 2357
                _ => panic!("unsupported target word size")
            },
2358 2359 2360
            TyUint(TyUs) => match &tcx.sess.target.target.target_pointer_width[..] {
                "32" => TyUint(TyU32),
                "64" => TyUint(TyU64),
2361 2362
                _ => panic!("unsupported target word size")
            },
2363
            ref t @ TyUint(_) | ref t @ TyInt(_) => t.clone(),
2364 2365
            _ => panic!("tried to get overflow intrinsic for {:?} applied to non-int type",
                        *self)
2366 2367 2368
        };

        match *self {
2369
            OverflowOpViaIntrinsic::Add => match new_sty {
2370 2371 2372 2373
                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",
2374

2375 2376 2377 2378
                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",
2379 2380 2381

                _ => unreachable!(),
            },
2382
            OverflowOpViaIntrinsic::Sub => match new_sty {
2383 2384 2385 2386
                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",
2387

2388 2389 2390 2391
                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",
2392 2393 2394

                _ => unreachable!(),
            },
2395
            OverflowOpViaIntrinsic::Mul => match new_sty {
2396 2397 2398 2399 2400 2401 2402 2403 2404
                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",
2405 2406 2407 2408 2409 2410

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

2411 2412 2413 2414 2415 2416 2417
    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);
2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435

        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)
2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537
    }
}

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)
        let invert_mask = !shift_mask_val(lhs_llty);
        let invert_mask = C_integral(rhs_llty, invert_mask, true);

        let outer_bits = And(bcx, rhs, invert_mask, binop_debug_loc);
        let cond = ICmp(bcx, llvm::IntNE, outer_bits,
                        C_integral(rhs_llty, 0, false), binop_debug_loc);
        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)
    }
}

fn shift_mask_val(llty: Type) -> u64 {
    // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
    llty.int_width() - 1
}

// 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 {
    let rhs = base::cast_shift_expr_rhs(bcx, ast::BinOp_::BiShl, lhs, rhs);
    // #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 {
    let rhs = base::cast_shift_expr_rhs(bcx, ast::BinOp_::BiShr, lhs, rhs);
    // #1877, #10183: Ensure that input is always valid
    let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
    let is_signed = ty::type_is_signed(lhs_t);
    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);
    let mask = shift_mask_val(rhs_llty);
    And(bcx, rhs, C_integral(rhs_llty, mask, false), debug_loc)
}

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),
        }
2538 2539 2540 2541 2542
    } 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),
2543 2544 2545 2546 2547

            OverflowOp::Shl =>
                build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc),
            OverflowOp::Shr =>
                build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc),
2548 2549 2550 2551
        };
        (bcx, res)
    }
}