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

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

49
#![allow(non_camel_case_types)]
50

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

54
use back::abi;
55
use llvm::{self, ValueRef, TypeKind};
56
use middle::check_const;
57
use middle::def;
N
Nick Cameron 已提交
58
use middle::lang_items::CoerceUnsizedTraitLangItem;
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::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer};
77
use middle::ty::{self, Ty};
78
use middle::ty::MethodCall;
79
use util::common::indenter;
80 81
use trans::machine::{llsize_of, llsize_of_alloc};
use trans::type_::Type;
J
James Miller 已提交
82

83
use syntax::{ast, ast_util, codemap};
84
use syntax::parse::token::InternedString;
85
use syntax::ptr::P;
N
Nick Cameron 已提交
86
use syntax::parse::token;
A
Aaron Turon 已提交
87
use std::iter::repeat;
88
use std::mem;
89

90 91 92 93 94
// Destinations

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

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

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

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

118 119
    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);

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

127
    let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
T
Fallout  
Tamir Duberstein 已提交
128 129 130 131 132
    if !qualif.intersects(
        check_const::ConstQualif::NOT_CONST |
        check_const::ConstQualif::NEEDS_DROP
    ) {
        if !qualif.intersects(check_const::ConstQualif::PREFER_IN_PLACE) {
133 134 135 136 137 138 139
            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));
140
                return bcx;
141
            }
142 143 144 145
            // 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.
146 147 148 149 150
        } 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 {
151
                ast::ExprPath(..) => {
152 153
                    match bcx.def(expr.id) {
                        def::DefConst(did) => {
154
                            let const_expr = consts::get_const_expr(bcx.ccx(), did, expr);
155 156 157 158 159 160 161
                            // 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![]);
162 163 164 165 166 167 168
                            // 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)
                            });
169 170 171 172 173 174 175 176 177 178 179
                            let scopes = mem::replace(&mut *bcx.fcx.scopes.borrow_mut(),
                                                      scopes);
                            assert!(scopes.is_empty());
                            return bcx;
                        }
                        _ => {}
                    }
                }
                _ => {}
            }
        }
180 181
    }

182
    debug!("trans_into() expr={:?}", expr);
183

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

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

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

S
Steve Klabnik 已提交
206 207 208
/// 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.
209 210 211
pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                         expr: &ast::Expr)
                         -> DatumBlock<'blk, 'tcx, Expr> {
212
    debug!("trans(expr={:?})", expr);
N
Niko Matsakis 已提交
213

214
    let mut bcx = bcx;
215
    let fcx = bcx.fcx;
216
    let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
T
Fallout  
Tamir Duberstein 已提交
217 218 219 220 221
    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
    ) {
222 223 224
        let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
                                                      bcx.fcx.param_substs);

T
Fallout  
Tamir Duberstein 已提交
225
        if qualif.intersects(check_const::ConstQualif::HAS_STATIC_BORROWS) {
226 227 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
            // 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");
254
            let lldest = if !const_ty.is_structural() {
255 256 257 258 259 260 261 262 263 264 265 266 267
                // 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
    };
268

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

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

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

295 296 297
pub fn make_fat_ptr(bcx: Block, ty: Type, data: ValueRef, extra: ValueRef) -> ValueRef {
    InsertValue(bcx, InsertValue(bcx, C_undef(ty), data, 0), extra, 1)
}
298 299 300 301 302
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));
}

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

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

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

396
            // (You might think there is a more elegant way to do this than a
397 398
            // skip_reborrows bool, but then you remember that the borrow checker exists).
            if skip_reborrows == 0 && adj.autoref.is_some() {
N
Nick Cameron 已提交
399 400 401 402 403 404 405 406
                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));
                }
407 408 409
            }

            if let Some(target) = adj.unsize {
N
Nick Cameron 已提交
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
                // 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 已提交
428
            }
429
        }
430
    }
431
    debug!("after adjustments, datum={}", datum.to_string(bcx.ccx()));
N
Nick Cameron 已提交
432 433
    DatumBlock::new(bcx, datum)
}
434

N
Nick Cameron 已提交
435 436 437 438 439 440 441 442 443 444 445
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) {
446 447 448 449
        (&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 已提交
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 479
            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));
480
        }
N
Nick Cameron 已提交
481

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

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

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

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

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

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

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

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

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

579
    debug!("trans_unadjusted(expr={:?})", expr);
580 581
    let _indenter = indenter();

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

A
Ariel Ben-Yehuda 已提交
584 585
    return match expr_kind(bcx.tcx(), expr) {
        ExprKind::Lvalue | ExprKind::RvalueDatum => {
586
            let datum = unpack_datum!(bcx, {
587
                trans_datum_unadjusted(bcx, expr)
588
            });
589 590

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

A
Ariel Ben-Yehuda 已提交
593
        ExprKind::RvalueStmt => {
594
            bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
595
            nil(bcx, expr_ty(bcx, expr))
596 597
        }

A
Ariel Ben-Yehuda 已提交
598
        ExprKind::RvalueDps => {
599
            let ty = expr_ty(bcx, expr);
600
            if type_is_zero_size(bcx.ccx(), ty) {
601
                bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
602
                nil(bcx, ty)
603
            } else {
604
                let scratch = rvalue_scratch_datum(bcx, ty, "");
605 606
                bcx = trans_rvalue_dps_unadjusted(
                    bcx, expr, SaveIn(scratch.val));
607 608 609 610 611 612 613 614 615 616

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

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

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

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

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

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

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

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

729
        if type_is_sized(bcx.tcx(), d.ty) {
730
            DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
N
Nick Cameron 已提交
731
        } else {
732
            let scratch = rvalue_scratch_datum(bcx, d.ty, "");
N
Nick Cameron 已提交
733 734 735 736
            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));

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

}

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

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

761 762 763 764 765 766
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> {
767 768 769 770 771 772
    //! Translates `base[idx]`.

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

773 774
    let index_expr_debug_loc = index_expr.debug_loc();

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

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

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

790
            let ref_ty = // invoked methods have LB regions instantiated:
791
                bcx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
792
            let elt_ty = match ref_ty.builtin_deref(true) {
793 794 795 796 797 798 799
                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
            let ix_val = {
                if ix_size < int_size {
836
                    if expr_ty(bcx, idx).is_signed() {
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 = base_datum.ty.sequence_element_type(bcx.tcx());
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,
1111
                             tcx.mk_struct(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 = bcx.tcx().enum_variant_with_id(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 bcx.tcx().has_dtor(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));
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
                   nid, bcx.val_to_string(datum.val), datum.ty);
1321
            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
            let fields = tcx.struct_fields(did, substs);
1344
            let fields = monomorphize::normalize_associated_type(tcx, &fields);
1345
            op(0, &fields[..])
1346 1347
        }

1348
        ty::TyTuple(ref v) => {
1349 1350 1351 1352 1353 1354 1355 1356 1357 1358
            let fields: Vec<_> = v.iter().enumerate().map(|(i, &f)| {
                ty::field {
                    name: token::intern(&i.to_string()),
                    mt: ty::mt {
                        ty: f,
                        mutbl: ast::MutImmutable
                    }
                }
            }).collect();
            op(0, &fields)
1359 1360
        }

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

1388
        _ => {
J
Jorge Aparicio 已提交
1389
            tcx.sess.bug(&format!(
1390 1391
                "cannot get field types from the type {:?}",
                ty));
1392 1393 1394 1395
        }
    }
}

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

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

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

1444 1445 1446
        trans_adt(bcx,
                  ty,
                  discr,
1447
                  &numbered_fields,
1448 1449
                  optbase,
                  dest,
1450
                  DebugLoc::At(expr_id, expr_span))
1451
    })
1452 1453
}

S
Steve Klabnik 已提交
1454 1455 1456 1457 1458 1459
/// 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.
1460
pub struct StructBaseInfo<'a, 'tcx> {
1461
    /// The base expression; will be evaluated after all explicit fields.
1462
    expr: &'a ast::Expr,
1463
    /// The indices of fields to copy paired with their types.
1464
    fields: Vec<(usize, Ty<'tcx>)>
1465
}
1466

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

1487
    debug_location.apply(bcx.fcx);
1488

1489 1490
    // If we don't care about the result, just make a
    // temporary stack slot
1491
    let addr = match dest {
1492 1493
        SaveIn(pos) => pos,
        Ignore => alloc_ty(bcx, ty, "temp"),
1494
    };
1495 1496

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

1500
    if ty.is_simd(bcx.tcx()) {
1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538
        // 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.
1539 1540
        assert_eq!(discr, 0);

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

1560
        // Finally, move scratch field values into actual field locations
1561
        for (i, datum) in scratch_vals {
1562 1563
            let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
            bcx = datum.store_to(bcx, dest);
1564 1565
        }
    } else {
1566
        // No base means we can write all fields directly in place.
1567
        for &(i, ref e) in fields {
1568 1569 1570 1571 1572 1573 1574
            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);
        }
1575
    }
1576

1577
    adt::trans_set_discr(bcx, &*repr, addr, discr);
1578

1579 1580
    fcx.pop_custom_cleanup_scope(custom_cleanup_scope);

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

1592

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

1604 1605 1606 1607 1608
fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                           expr: &ast::Expr,
                           op: ast::UnOp,
                           sub_expr: &ast::Expr)
                           -> DatumBlock<'blk, 'tcx, Expr> {
1609
    let ccx = bcx.ccx();
1610
    let mut bcx = bcx;
1611
    let _icx = push_ctxt("trans_unary_datum");
1612

1613
    let method_call = MethodCall::expr(expr.id);
1614 1615 1616 1617 1618 1619

    // 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 ||
1620
        !ccx.tcx().method_map.borrow().contains_key(&method_call));
1621

1622
    let un_ty = expr_ty(bcx, expr);
1623

1624 1625
    let debug_loc = expr.debug_loc();

1626
    match op {
1627
        ast::UnNot => {
1628
            let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1629
            let llresult = Not(bcx, datum.to_llscalarish(bcx), debug_loc);
1630
            immediate_rvalue_bcx(bcx, llresult, un_ty).to_expr_datumblock()
1631
        }
1632
        ast::UnNeg => {
1633 1634
            let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
            let val = datum.to_llscalarish(bcx);
1635
            let (bcx, llneg) = {
1636
                if un_ty.is_fp() {
1637 1638
                    let result = FNeg(bcx, val, debug_loc);
                    (bcx, result)
1639
                } else {
1640
                    let is_signed = un_ty.is_signed();
1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
                    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)
1655 1656
                }
            };
1657
            immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
1658
        }
1659
        ast::UnUniq => {
1660
            trans_uniq_expr(bcx, expr, un_ty, sub_expr, expr_ty(bcx, sub_expr))
1661
        }
1662
        ast::UnDeref => {
1663
            let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1664
            deref_once(bcx, expr, datum, method_call)
1665
        }
1666
    }
1667
}
1668

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

1704 1705 1706
fn ref_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                           lval: Datum<'tcx, Lvalue>)
                           -> DatumBlock<'blk, 'tcx, Expr> {
1707
    let dest_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic), lval.ty);
1708 1709 1710 1711 1712 1713
    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())
}

1714 1715 1716 1717
fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                             expr: &ast::Expr,
                             subexpr: &ast::Expr)
                             -> DatumBlock<'blk, 'tcx, Expr> {
1718
    let _icx = push_ctxt("trans_addr_of");
1719
    let mut bcx = bcx;
1720
    let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
1721 1722 1723 1724 1725 1726 1727
    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 已提交
1728
    }
1729 1730 1731 1732
}

// Important to get types for both lhs and rhs, because one might be _|_
// and the other not.
1733 1734
fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                 binop_expr: &ast::Expr,
1735
                                 binop_ty: Ty<'tcx>,
1736
                                 op: ast::BinOp,
1737
                                 lhs_t: Ty<'tcx>,
1738
                                 lhs: ValueRef,
1739
                                 rhs_t: Ty<'tcx>,
1740 1741
                                 rhs: ValueRef)
                                 -> DatumBlock<'blk, 'tcx, Expr> {
1742
    let _icx = push_ctxt("trans_eager_binop");
1743

1744
    let tcx = bcx.tcx();
1745
    let is_simd = lhs_t.is_simd(tcx);
1746
    let intype = if is_simd {
1747
        lhs_t.simd_type(tcx)
1748 1749
    } else {
        lhs_t
1750
    };
1751 1752
    let is_float = intype.is_fp();
    let is_signed = intype.is_signed();
1753
    let info = expr_info(binop_expr);
1754

1755 1756
    let binop_debug_loc = binop_expr.debug_loc();

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

1855
    immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
1856 1857 1858
}

// refinement types would obviate the need for this
1859 1860 1861 1862
enum lazy_binop_ty {
    lazy_and,
    lazy_or,
}
1863

1864 1865 1866 1867 1868 1869
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> {
1870
    let _icx = push_ctxt("trans_lazy_binop");
1871
    let binop_ty = expr_ty(bcx, binop_expr);
1872
    let fcx = bcx.fcx;
1873

1874 1875
    let DatumBlock {bcx: past_lhs, datum: lhs} = trans(bcx, a);
    let lhs = lhs.to_llscalarish(past_lhs);
1876

1877
    if past_lhs.unreachable.get() {
1878
        return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock();
1879 1880
    }

1881 1882
    let join = fcx.new_id_block("join", binop_expr.id);
    let before_rhs = fcx.new_id_block("before_rhs", b.id);
1883 1884

    match op {
1885 1886
      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)
1887
    }
1888

1889 1890
    let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b);
    let rhs = rhs.to_llscalarish(past_rhs);
1891

1892
    if past_rhs.unreachable.get() {
1893
        return immediate_rvalue_bcx(join, lhs, binop_ty).to_expr_datumblock();
1894 1895
    }

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

1900
    return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
1901 1902
}

1903 1904 1905 1906 1907 1908
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> {
1909
    let _icx = push_ctxt("trans_binary");
1910
    let ccx = bcx.ccx();
1911

1912
    // if overloaded, would be RvalueDpsExpr
1913
    assert!(!ccx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
1914

1915
    match op.node {
1916
        ast::BiAnd => {
1917
            trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
1918
        }
1919
        ast::BiOr => {
1920
            trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
1921 1922 1923
        }
        _ => {
            let mut bcx = bcx;
1924 1925
            let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
            let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
1926
            let binop_ty = expr_ty(bcx, expr);
1927 1928

            debug!("trans_binary (expr {}): lhs_datum={}",
1929
                   expr.id,
1930
                   lhs_datum.to_string(ccx));
1931 1932 1933 1934
            let lhs_ty = lhs_datum.ty;
            let lhs = lhs_datum.to_llscalarish(bcx);

            debug!("trans_binary (expr {}): rhs_datum={}",
1935
                   expr.id,
1936
                   rhs_datum.to_string(ccx));
1937 1938
            let rhs_ty = rhs_datum.ty;
            let rhs = rhs_datum.to_llscalarish(bcx);
1939
            trans_eager_binop(bcx, expr, binop_ty, op,
1940
                              lhs_ty, lhs, rhs_ty, rhs)
1941 1942 1943 1944
        }
    }
}

1945 1946 1947
fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                   expr: &ast::Expr,
                                   method_call: MethodCall,
1948 1949
                                   lhs: Datum<'tcx, Expr>,
                                   rhs: Vec<(Datum<'tcx, Expr>, ast::NodeId)>,
1950 1951
                                   dest: Option<Dest>,
                                   autoref: bool)
1952
                                   -> Result<'blk, 'tcx> {
1953
    let method_ty = bcx.tcx().method_map.borrow().get(&method_call).unwrap().ty;
1954
    callee::trans_call_inner(bcx,
1955
                             expr.debug_loc(),
1956
                             monomorphize_type(bcx, method_ty),
1957
                             |bcx, arg_cleanup_scope| {
1958
                                meth::trans_method_callee(bcx,
1959 1960
                                                          method_call,
                                                          None,
1961
                                                          arg_cleanup_scope)
1962
                             },
1963
                             callee::ArgOverloadedOp(lhs, rhs, autoref),
1964
                             dest)
1965 1966
}

1967 1968 1969 1970 1971 1972
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> {
1973
    debug!("trans_overloaded_call {}", expr.id);
1974
    let method_call = MethodCall::expr(expr.id);
1975 1976 1977 1978 1979 1980
    let method_type = bcx.tcx()
                         .method_map
                         .borrow()
                         .get(&method_call)
                         .unwrap()
                         .ty;
1981
    let mut all_args = vec!(callee);
1982
    all_args.extend(args.iter().map(|e| &**e));
1983 1984
    unpack_result!(bcx,
                   callee::trans_call_inner(bcx,
1985
                                            expr.debug_loc(),
1986 1987 1988 1989 1990 1991 1992 1993 1994
                                            monomorphize_type(bcx,
                                                              method_type),
                                            |bcx, arg_cleanup_scope| {
                                                meth::trans_method_callee(
                                                    bcx,
                                                    method_call,
                                                    None,
                                                    arg_cleanup_scope)
                                            },
1995
                                            callee::ArgOverloadedCall(all_args),
1996 1997 1998 1999
                                            dest));
    bcx
}

2000 2001 2002 2003 2004 2005 2006
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;
2007 2008
    }

2009
    match (t_in.builtin_deref(true), t_out.builtin_deref(true)) {
2010 2011 2012
        (Some(ty::mt{ ty: t_in, .. }), Some(ty::mt{ ty: t_out, .. })) => {
            t_in == t_out
        }
2013 2014 2015 2016 2017 2018
        _ => {
            // 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
        }
2019 2020 2021
    }
}

2022 2023 2024
fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                              expr: &ast::Expr,
                              id: ast::NodeId)
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 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066
                              -> 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 已提交
2067 2068 2069
    let _icx = push_ctxt("trans_cast");
    let mut bcx = bcx;
    let ccx = bcx.ccx();
2070

N
Nick Cameron 已提交
2071
    let t_in = expr_ty_adjusted(bcx, expr);
2072
    let t_out = node_id_type(bcx, id);
2073

2074
    debug!("trans_cast({:?} as {:?})", t_in, t_out);
2075 2076
    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);
2077 2078
    // Convert the value to be cast into a ValueRef, either by-ref or
    // by-value as appropriate given its type:
2079 2080
    let mut datum = unpack_datum!(bcx, trans(bcx, expr));

N
Nick Cameron 已提交
2081
    let datum_ty = monomorphize_type(bcx, datum.ty);
2082 2083

    if cast_is_noop(bcx.tcx(), expr, datum_ty, t_out) {
2084 2085 2086 2087
        datum.ty = t_out;
        return DatumBlock::new(bcx, datum);
    }

2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098
    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 已提交
2099 2100 2101
                                        PointerCast(bcx,
                                                    Load(bcx, get_dataptr(bcx, datum.val)),
                                                    ll_t_out),
2102
                                        t_out).to_expr_datumblock();
2103
        }
2104 2105
    }

A
Ariel Ben-Yehuda 已提交
2106 2107
    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");
2108 2109 2110 2111 2112 2113 2114 2115 2116 2117

    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 {
2118
        (datum.to_llscalarish(bcx), t_in.is_signed())
2119 2120 2121
    };

    let newval = match (r_t_in, r_t_out) {
A
Ariel Ben-Yehuda 已提交
2122 2123 2124 2125
        (Ptr(_), Ptr(_)) | (FnPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => {
            PointerCast(bcx, llexpr, ll_t_out)
        }
        (Ptr(_), Int(_)) | (FnPtr, Int(_)) => PtrToInt(bcx, llexpr, ll_t_out),
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136
        (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: \
2137 2138 2139
                                            {:?} -> {:?}",
                                           t_in,
                                           t_out)
2140
                                 )
2141 2142
    };
    return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
2143 2144
}

2145 2146 2147 2148
fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                               expr: &ast::Expr,
                               op: ast::BinOp,
                               dst: &ast::Expr,
2149
                               src: &ast::Expr)
2150
                               -> Block<'blk, 'tcx> {
2151
    let _icx = push_ctxt("trans_assign_op");
2152 2153
    let mut bcx = bcx;

2154
    debug!("trans_assign_op(expr={:?})", expr);
2155

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

2159 2160
    // Evaluate LHS (destination), which should be an lvalue
    let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
2161
    assert!(!bcx.fcx.type_needs_drop(dst_datum.ty));
2162
    let dst_ty = dst_datum.ty;
2163
    let dst = load_ty(bcx, dst_datum.val, dst_datum.ty);
2164

2165
    // Evaluate RHS
2166
    let rhs_datum = unpack_datum!(bcx, trans(bcx, &*src));
2167 2168
    let rhs_ty = rhs_datum.ty;
    let rhs = rhs_datum.to_llscalarish(bcx);
2169 2170

    // Perform computation and store the result
2171 2172 2173 2174
    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);
2175 2176
}

2177
fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2178
                        datum: Datum<'tcx, Expr>,
2179 2180
                        expr: &ast::Expr)
                        -> DatumBlock<'blk, 'tcx, Expr> {
2181 2182 2183 2184 2185 2186 2187 2188 2189
    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;
2190
    let ptr_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic), referent_ty);
2191 2192 2193 2194 2195 2196 2197

    // 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`.
2198 2199 2200
    // 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))))
2201 2202
}

2203 2204
fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                              expr: &ast::Expr,
2205
                              datum: Datum<'tcx, Expr>,
2206
                              times: usize)
2207
                              -> DatumBlock<'blk, 'tcx, Expr> {
2208 2209
    let mut bcx = bcx;
    let mut datum = datum;
2210
    for i in 0..times {
2211
        let method_call = MethodCall::autoderef(expr.id, i as u32);
2212
        datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call));
2213 2214 2215 2216
    }
    DatumBlock { bcx: bcx, datum: datum }
}

2217 2218
fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                          expr: &ast::Expr,
2219
                          datum: Datum<'tcx, Expr>,
2220 2221
                          method_call: MethodCall)
                          -> DatumBlock<'blk, 'tcx, Expr> {
2222 2223
    let ccx = bcx.ccx();

2224 2225
    debug!("deref_once(expr={:?}, datum={}, method_call={:?})",
           expr,
2226
           datum.to_string(ccx),
2227
           method_call);
2228 2229 2230

    let mut bcx = bcx;

2231
    // Check for overloaded deref.
2232
    let method_ty = ccx.tcx().method_map.borrow()
2233
                       .get(&method_call).map(|method| method.ty);
2234 2235
    let datum = match method_ty {
        Some(method_ty) => {
2236 2237
            let method_ty = monomorphize_type(bcx, method_ty);

2238 2239
            // Overloaded. Evaluate `trans_overloaded_op`, which will
            // invoke the user's deref() method, which basically
2240
            // converts from the `Smaht<T>` pointer that we have into
2241 2242
            // a `&T` pointer.  We can then proceed down the normal
            // path (below) to dereference that `&T`.
2243 2244 2245
            let datum = if method_call.autoderef == 0 {
                datum
            } else {
2246
                // Always perform an AutoPtr when applying an overloaded auto-deref
2247
                unpack_datum!(bcx, auto_ref(bcx, datum, expr))
2248
            };
2249

2250
            let ref_ty = // invoked methods have their LB regions instantiated
2251
                ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
2252 2253 2254
            let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");

            unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
2255 2256
                                                    datum, Vec::new(), Some(SaveIn(scratch.val)),
                                                    false));
2257
            scratch.to_expr_datum()
2258
        }
2259 2260 2261 2262
        None => {
            // Not overloaded. We already have a pointer we know how to deref.
            datum
        }
2263 2264
    };

2265
    let r = match datum.ty.sty {
2266
        ty::TyBox(content_ty) => {
2267 2268 2269 2270 2271
            // 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));

2272
            if type_is_sized(bcx.tcx(), content_ty) {
2273 2274
                let ptr = load_ty(bcx, datum.val, datum.ty);
                DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr))
N
Nick Cameron 已提交
2275
            } else {
2276 2277 2278 2279 2280
                // 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.
2281

2282
                let datum = Datum::new(datum.val, content_ty, LvalueExpr);
2283
                DatumBlock::new(bcx, datum)
2284
            }
2285 2286
        }

2287 2288
        ty::TyRawPtr(ty::mt { ty: content_ty, .. }) |
        ty::TyRef(_, ty::mt { ty: content_ty, .. }) => {
2289
            if type_is_sized(bcx.tcx(), content_ty) {
N
Nick Cameron 已提交
2290 2291 2292 2293 2294 2295 2296 2297 2298
                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 {
2299
                // A fat pointer and a DST lvalue have the same representation
N
Nick Cameron 已提交
2300
                // just different types.
2301
                DatumBlock::new(bcx, Datum::new(datum.val, content_ty, LvalueExpr))
2302
            }
2303 2304 2305 2306 2307
        }

        _ => {
            bcx.tcx().sess.span_bug(
                expr.span,
2308 2309
                &format!("deref invoked on expr of illegal type {:?}",
                        datum.ty));
2310 2311 2312
        }
    };

2313
    debug!("deref_once(expr={}, method_call={:?}, result={})",
2314
           expr.id, method_call, r.datum.to_string(ccx));
2315 2316

    return r;
2317
}
2318

2319
#[derive(Debug)]
2320 2321 2322 2323
enum OverflowOp {
    Add,
    Sub,
    Mul,
2324 2325
    Shl,
    Shr,
2326 2327 2328
}

impl OverflowOp {
2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348
    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, }

2349
#[derive(Debug)]
2350 2351 2352 2353 2354 2355 2356
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)
    }
2357 2358 2359
    fn to_intrinsic_name(&self, tcx: &ty::ctxt, ty: Ty) -> &'static str {
        use syntax::ast::IntTy::*;
        use syntax::ast::UintTy::*;
2360
        use middle::ty::{TyInt, TyUint};
2361 2362

        let new_sty = match ty.sty {
2363 2364 2365
            TyInt(TyIs) => match &tcx.sess.target.target.target_pointer_width[..] {
                "32" => TyInt(TyI32),
                "64" => TyInt(TyI64),
2366 2367
                _ => panic!("unsupported target word size")
            },
2368 2369 2370
            TyUint(TyUs) => match &tcx.sess.target.target.target_pointer_width[..] {
                "32" => TyUint(TyU32),
                "64" => TyUint(TyU64),
2371 2372
                _ => panic!("unsupported target word size")
            },
2373
            ref t @ TyUint(_) | ref t @ TyInt(_) => t.clone(),
2374 2375
            _ => panic!("tried to get overflow intrinsic for {:?} applied to non-int type",
                        *self)
2376 2377 2378
        };

        match *self {
2379
            OverflowOpViaIntrinsic::Add => match new_sty {
2380 2381 2382 2383
                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",
2384

2385 2386 2387 2388
                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",
2389 2390 2391

                _ => unreachable!(),
            },
2392
            OverflowOpViaIntrinsic::Sub => match new_sty {
2393 2394 2395 2396
                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",
2397

2398 2399 2400 2401
                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",
2402 2403 2404

                _ => unreachable!(),
            },
2405
            OverflowOpViaIntrinsic::Mul => match new_sty {
2406 2407 2408 2409 2410 2411 2412 2413 2414
                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",
2415 2416 2417 2418 2419 2420

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

2421 2422 2423 2424 2425 2426 2427
    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);
2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445

        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)
2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468
    }
}

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)
2469
        let invert_mask = shift_mask_val(bcx, lhs_llty, rhs_llty, true);
2470 2471

        let outer_bits = And(bcx, rhs, invert_mask, binop_debug_loc);
2472
        let cond = build_nonzero_check(bcx, outer_bits, binop_debug_loc);
2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487
        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)
    }
}

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
fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                              llty: Type,
                              mask_llty: Type,
                              invert: bool) -> ValueRef {
    let kind = llty.kind();
    match kind {
        TypeKind::Integer => {
            // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
            let val = llty.int_width() - 1;
            if invert {
                C_integral(mask_llty, !val, true)
            } else {
                C_integral(mask_llty, val, false)
            }
        },
        TypeKind::Vector => {
            let mask = shift_mask_val(bcx, llty.element_type(), mask_llty.element_type(), invert);
            VectorSplat(bcx, mask_llty.vector_length(), mask)
        },
        _ => panic!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
    }
}

// Check if an integer or vector contains a nonzero element.
fn build_nonzero_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                   value: ValueRef,
                                   binop_debug_loc: DebugLoc) -> ValueRef {
    let llty = val_ty(value);
    let kind = llty.kind();
    match kind {
        TypeKind::Integer => ICmp(bcx, llvm::IntNE, value, C_null(llty), binop_debug_loc),
        TypeKind::Vector => {
            // Check if any elements of the vector are nonzero by treating
            // it as a wide integer and checking if the integer is nonzero.
            let width = llty.vector_length() as u64 * llty.element_type().int_width();
            let int_value = BitCast(bcx, value, Type::ix(bcx.ccx(), width));
            build_nonzero_check(bcx, int_value, binop_debug_loc)
        },
        _ => panic!("build_nonzero_check: expected Integer or Vector, found {:?}", kind),
    }
2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552
}

// 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);
2553
    let tcx = bcx.tcx();
2554
    let is_simd = lhs_t.is_simd(tcx);
2555
    let intype = if is_simd {
2556
        lhs_t.simd_type(tcx)
2557 2558 2559
    } else {
        lhs_t
    };
2560
    let is_signed = intype.is_signed();
2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571
    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);
2572
    And(bcx, rhs, shift_mask_val(bcx, rhs_llty, rhs_llty, false), debug_loc)
2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588
}

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),
        }
2589 2590 2591 2592 2593
    } 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),
2594 2595 2596 2597 2598

            OverflowOp::Shl =>
                build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc),
            OverflowOp::Shr =>
                build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc),
2599 2600 2601 2602
        };
        (bcx, res)
    }
}
A
Ariel Ben-Yehuda 已提交
2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637

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

fn expr_kind(tcx: &ty::ctxt, expr: &ast::Expr) -> ExprKind {
    if tcx.method_map.borrow().contains_key(&MethodCall::expr(expr.id)) {
        // Overloaded operations are generally calls, and hence they are
        // generated via DPS, but there are a few exceptions:
        return match expr.node {
            // `a += b` has a unit result.
            ast::ExprAssignOp(..) => ExprKind::RvalueStmt,

            // the deref method invoked for `*a` always yields an `&T`
            ast::ExprUnary(ast::UnDeref, _) => ExprKind::Lvalue,

            // the index method invoked for `a[i]` always yields an `&T`
            ast::ExprIndex(..) => ExprKind::Lvalue,

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

    match expr.node {
        ast::ExprPath(..) => {
2638
            match tcx.resolve_expr(expr) {
A
Ariel Ben-Yehuda 已提交
2639
                def::DefStruct(_) | def::DefVariant(..) => {
2640
                    if let ty::TyBareFn(..) = tcx.node_id_to_type(expr.id).sty {
A
Ariel Ben-Yehuda 已提交
2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754
                        // ctor function
                        ExprKind::RvalueDatum
                    } else {
                        ExprKind::RvalueDps
                    }
                }

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

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

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

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

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

        ast::ExprUnary(ast::UnDeref, _) |
        ast::ExprField(..) |
        ast::ExprTupField(..) |
        ast::ExprIndex(..) => {
            ExprKind::Lvalue
        }

        ast::ExprCall(..) |
        ast::ExprMethodCall(..) |
        ast::ExprStruct(..) |
        ast::ExprRange(..) |
        ast::ExprTup(..) |
        ast::ExprIf(..) |
        ast::ExprMatch(..) |
        ast::ExprClosure(..) |
        ast::ExprBlock(..) |
        ast::ExprRepeat(..) |
        ast::ExprVec(..) => {
            ExprKind::RvalueDps
        }

        ast::ExprIfLet(..) => {
            tcx.sess.span_bug(expr.span, "non-desugared ExprIfLet");
        }
        ast::ExprWhileLet(..) => {
            tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
        }

        ast::ExprForLoop(..) => {
            tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop");
        }

        ast::ExprLit(ref lit) if ast_util::lit_is_str(&**lit) => {
            ExprKind::RvalueDps
        }

        ast::ExprBreak(..) |
        ast::ExprAgain(..) |
        ast::ExprRet(..) |
        ast::ExprWhile(..) |
        ast::ExprLoop(..) |
        ast::ExprAssign(..) |
        ast::ExprInlineAsm(..) |
        ast::ExprAssignOp(..) => {
            ExprKind::RvalueStmt
        }

        ast::ExprLit(_) | // Note: LitStr is carved out above
        ast::ExprUnary(..) |
        ast::ExprBox(None, _) |
        ast::ExprAddrOf(..) |
        ast::ExprBinary(..) |
        ast::ExprCast(..) => {
            ExprKind::RvalueDatum
        }

        ast::ExprBox(Some(ref place), _) => {
            // Special case `Box<T>` for now:
            let def_id = match tcx.def_map.borrow().get(&place.id) {
                Some(def) => def.def_id(),
                None => panic!("no def for place"),
            };
            if tcx.lang_items.exchange_heap() == Some(def_id) {
                ExprKind::RvalueDatum
            } else {
                ExprKind::RvalueDps
            }
        }

        ast::ExprParen(ref e) => expr_kind(tcx, &**e),

        ast::ExprMac(..) => {
            tcx.sess.span_bug(
                expr.span,
                "macro expression remains after expansion");
        }
    }
}