]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/expr.rs
Make AdjustEmptyToAny actually perform the adjustment
[rust.git] / src / librustc_trans / expr.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! # Translation of Expressions
12 //!
13 //! The expr module handles translation of expressions. The most general
14 //! translation routine is `trans()`, which will translate an expression
15 //! into a datum. `trans_into()` is also available, which will translate
16 //! an expression and write the result directly into memory, sometimes
17 //! avoiding the need for a temporary stack slot. Finally,
18 //! `trans_to_lvalue()` is available if you'd like to ensure that the
19 //! result has cleanup scheduled.
20 //!
21 //! Internally, each of these functions dispatches to various other
22 //! expression functions depending on the kind of expression. We divide
23 //! up expressions into:
24 //!
25 //! - **Datum expressions:** Those that most naturally yield values.
26 //!   Examples would be `22`, `box x`, or `a + b` (when not overloaded).
27 //! - **DPS expressions:** Those that most naturally write into a location
28 //!   in memory. Examples would be `foo()` or `Point { x: 3, y: 4 }`.
29 //! - **Statement expressions:** That that do not generate a meaningful
30 //!   result. Examples would be `while { ... }` or `return 44`.
31 //!
32 //! Public entry points:
33 //!
34 //! - `trans_into(bcx, expr, dest) -> bcx`: evaluates an expression,
35 //!   storing the result into `dest`. This is the preferred form, if you
36 //!   can manage it.
37 //!
38 //! - `trans(bcx, expr) -> DatumBlock`: evaluates an expression, yielding
39 //!   `Datum` with the result. You can then store the datum, inspect
40 //!   the value, etc. This may introduce temporaries if the datum is a
41 //!   structural type.
42 //!
43 //! - `trans_to_lvalue(bcx, expr, "...") -> DatumBlock`: evaluates an
44 //!   expression and ensures that the result has a cleanup associated with it,
45 //!   creating a temporary stack slot if necessary.
46 //!
47 //! - `trans_var -> Datum`: looks up a local variable, upvar or static.
48
49 #![allow(non_camel_case_types)]
50
51 pub use self::Dest::*;
52 use self::lazy_binop_ty::*;
53
54 use llvm::{self, ValueRef, TypeKind};
55 use middle::const_qualif::ConstQualif;
56 use rustc::hir::def::Def;
57 use rustc::ty::subst::Substs;
58 use {_match, abi, adt, asm, base, closure, consts, controlflow};
59 use base::*;
60 use build::*;
61 use callee::{Callee, ArgExprs, ArgOverloadedCall, ArgOverloadedOp};
62 use cleanup::{self, CleanupMethods, DropHintMethods};
63 use common::*;
64 use datum::*;
65 use debuginfo::{self, DebugLoc, ToDebugLoc};
66 use glue;
67 use machine;
68 use tvec;
69 use type_of;
70 use value::Value;
71 use Disr;
72 use rustc::ty::adjustment::{AdjustEmptyToAny, AdjustDerefRef, AdjustReifyFnPointer};
73 use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
74 use rustc::ty::adjustment::CustomCoerceUnsized;
75 use rustc::ty::{self, Ty, TyCtxt};
76 use rustc::ty::MethodCall;
77 use rustc::ty::cast::{CastKind, CastTy};
78 use util::common::indenter;
79 use machine::{llsize_of, llsize_of_alloc};
80 use type_::Type;
81
82 use rustc::hir;
83
84 use syntax::ast;
85 use syntax::parse::token::InternedString;
86 use syntax_pos;
87 use std::fmt;
88 use std::mem;
89
90 // Destinations
91
92 // These are passed around by the code generating functions to track the
93 // destination of a computation's value.
94
95 #[derive(Copy, Clone, PartialEq)]
96 pub enum Dest {
97     SaveIn(ValueRef),
98     Ignore,
99 }
100
101 impl fmt::Debug for Dest {
102     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
103         match *self {
104             SaveIn(v) => write!(f, "SaveIn({:?})", Value(v)),
105             Ignore => f.write_str("Ignore")
106         }
107     }
108 }
109
110 /// This function is equivalent to `trans(bcx, expr).store_to_dest(dest)` but it may generate
111 /// better optimized LLVM code.
112 pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
113                               expr: &hir::Expr,
114                               dest: Dest)
115                               -> Block<'blk, 'tcx> {
116     let mut bcx = bcx;
117
118     expr.debug_loc().apply(bcx.fcx);
119
120     if adjustment_required(bcx, expr) {
121         // use trans, which may be less efficient but
122         // which will perform the adjustments:
123         let datum = unpack_datum!(bcx, trans(bcx, expr));
124         return datum.store_to_dest(bcx, dest, expr.id);
125     }
126
127     let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
128     if !qualif.intersects(ConstQualif::NOT_CONST | ConstQualif::NEEDS_DROP) {
129         if !qualif.intersects(ConstQualif::PREFER_IN_PLACE) {
130             if let SaveIn(lldest) = dest {
131                 match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
132                                                        bcx.fcx.param_substs,
133                                                        consts::TrueConst::No) {
134                     Ok(global) => {
135                         // Cast pointer to destination, because constants
136                         // have different types.
137                         let lldest = PointerCast(bcx, lldest, val_ty(global));
138                         memcpy_ty(bcx, lldest, global, expr_ty_adjusted(bcx, expr));
139                         return bcx;
140                     },
141                     Err(consts::ConstEvalFailure::Runtime(_)) => {
142                         // in case const evaluation errors, translate normally
143                         // debug assertions catch the same errors
144                         // see RFC 1229
145                     },
146                     Err(consts::ConstEvalFailure::Compiletime(_)) => {
147                         return bcx;
148                     },
149                 }
150             }
151
152             // If we see a const here, that's because it evaluates to a type with zero size. We
153             // should be able to just discard it, since const expressions are guaranteed not to
154             // have side effects. This seems to be reached through tuple struct constructors being
155             // passed zero-size constants.
156             if let hir::ExprPath(..) = expr.node {
157                 match bcx.tcx().expect_def(expr.id) {
158                     Def::Const(_) | Def::AssociatedConst(_) => {
159                         assert!(type_is_zero_size(bcx.ccx(), bcx.tcx().node_id_to_type(expr.id)));
160                         return bcx;
161                     }
162                     _ => {}
163                 }
164             }
165
166             // Even if we don't have a value to emit, and the expression
167             // doesn't have any side-effects, we still have to translate the
168             // body of any closures.
169             // FIXME: Find a better way of handling this case.
170         } else {
171             // The only way we're going to see a `const` at this point is if
172             // it prefers in-place instantiation, likely because it contains
173             // `[x; N]` somewhere within.
174             match expr.node {
175                 hir::ExprPath(..) => {
176                     match bcx.tcx().expect_def(expr.id) {
177                         Def::Const(did) | Def::AssociatedConst(did) => {
178                             let empty_substs = bcx.tcx().mk_substs(Substs::empty());
179                             let const_expr = consts::get_const_expr(bcx.ccx(), did, expr,
180                                                                     empty_substs);
181                             // Temporarily get cleanup scopes out of the way,
182                             // as they require sub-expressions to be contained
183                             // inside the current AST scope.
184                             // These should record no cleanups anyways, `const`
185                             // can't have destructors.
186                             let scopes = mem::replace(&mut *bcx.fcx.scopes.borrow_mut(),
187                                                       vec![]);
188                             // Lock emitted debug locations to the location of
189                             // the constant reference expression.
190                             debuginfo::with_source_location_override(bcx.fcx,
191                                                                      expr.debug_loc(),
192                                                                      || {
193                                 bcx = trans_into(bcx, const_expr, dest)
194                             });
195                             let scopes = mem::replace(&mut *bcx.fcx.scopes.borrow_mut(),
196                                                       scopes);
197                             assert!(scopes.is_empty());
198                             return bcx;
199                         }
200                         _ => {}
201                     }
202                 }
203                 _ => {}
204             }
205         }
206     }
207
208     debug!("trans_into() expr={:?}", expr);
209
210     let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
211                                                                           expr.id,
212                                                                           expr.span,
213                                                                           false);
214     bcx.fcx.push_ast_cleanup_scope(cleanup_debug_loc);
215
216     let kind = expr_kind(bcx.tcx(), expr);
217     bcx = match kind {
218         ExprKind::Lvalue | ExprKind::RvalueDatum => {
219             trans_unadjusted(bcx, expr).store_to_dest(dest, expr.id)
220         }
221         ExprKind::RvalueDps => {
222             trans_rvalue_dps_unadjusted(bcx, expr, dest)
223         }
224         ExprKind::RvalueStmt => {
225             trans_rvalue_stmt_unadjusted(bcx, expr)
226         }
227     };
228
229     bcx.fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id)
230 }
231
232 /// Translates an expression, returning a datum (and new block) encapsulating the result. When
233 /// possible, it is preferred to use `trans_into`, as that may avoid creating a temporary on the
234 /// stack.
235 pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
236                          expr: &hir::Expr)
237                          -> DatumBlock<'blk, 'tcx, Expr> {
238     debug!("trans(expr={:?})", expr);
239
240     let mut bcx = bcx;
241     let fcx = bcx.fcx;
242     let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
243     let adjusted_global = !qualif.intersects(ConstQualif::NON_STATIC_BORROWS);
244     let global = if !qualif.intersects(ConstQualif::NOT_CONST | ConstQualif::NEEDS_DROP) {
245         match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
246                                                             bcx.fcx.param_substs,
247                                                             consts::TrueConst::No) {
248             Ok(global) => {
249                 if qualif.intersects(ConstQualif::HAS_STATIC_BORROWS) {
250                     // Is borrowed as 'static, must return lvalue.
251
252                     // Cast pointer to global, because constants have different types.
253                     let const_ty = expr_ty_adjusted(bcx, expr);
254                     let llty = type_of::type_of(bcx.ccx(), const_ty);
255                     let global = PointerCast(bcx, global, llty.ptr_to());
256                     let datum = Datum::new(global, const_ty, Lvalue::new("expr::trans"));
257                     return DatumBlock::new(bcx, datum.to_expr_datum());
258                 }
259
260                 // Otherwise, keep around and perform adjustments, if needed.
261                 let const_ty = if adjusted_global {
262                     expr_ty_adjusted(bcx, expr)
263                 } else {
264                     expr_ty(bcx, expr)
265                 };
266
267                 // This could use a better heuristic.
268                 Some(if type_is_immediate(bcx.ccx(), const_ty) {
269                     // Cast pointer to global, because constants have different types.
270                     let llty = type_of::type_of(bcx.ccx(), const_ty);
271                     let global = PointerCast(bcx, global, llty.ptr_to());
272                     // Maybe just get the value directly, instead of loading it?
273                     immediate_rvalue(load_ty(bcx, global, const_ty), const_ty)
274                 } else {
275                     let scratch = alloc_ty(bcx, const_ty, "const");
276                     call_lifetime_start(bcx, scratch);
277                     let lldest = if !const_ty.is_structural() {
278                         // Cast pointer to slot, because constants have different types.
279                         PointerCast(bcx, scratch, val_ty(global))
280                     } else {
281                         // In this case, memcpy_ty calls llvm.memcpy after casting both
282                         // source and destination to i8*, so we don't need any casts.
283                         scratch
284                     };
285                     memcpy_ty(bcx, lldest, global, const_ty);
286                     Datum::new(scratch, const_ty, Rvalue::new(ByRef))
287                 })
288             },
289             Err(consts::ConstEvalFailure::Runtime(_)) => {
290                 // in case const evaluation errors, translate normally
291                 // debug assertions catch the same errors
292                 // see RFC 1229
293                 None
294             },
295             Err(consts::ConstEvalFailure::Compiletime(_)) => {
296                 // generate a dummy llvm value
297                 let const_ty = expr_ty(bcx, expr);
298                 let llty = type_of::type_of(bcx.ccx(), const_ty);
299                 let dummy = C_undef(llty.ptr_to());
300                 Some(Datum::new(dummy, const_ty, Rvalue::new(ByRef)))
301             },
302         }
303     } else {
304         None
305     };
306
307     let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
308                                                                           expr.id,
309                                                                           expr.span,
310                                                                           false);
311     fcx.push_ast_cleanup_scope(cleanup_debug_loc);
312     let datum = match global {
313         Some(rvalue) => rvalue.to_expr_datum(),
314         None => unpack_datum!(bcx, trans_unadjusted(bcx, expr))
315     };
316     let datum = if adjusted_global {
317         datum // trans::consts already performed adjustments.
318     } else {
319         unpack_datum!(bcx, apply_adjustments(bcx, expr, datum))
320     };
321     bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id);
322     return DatumBlock::new(bcx, datum);
323 }
324
325 pub fn get_meta(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
326     StructGEP(bcx, fat_ptr, abi::FAT_PTR_EXTRA)
327 }
328
329 pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
330     StructGEP(bcx, fat_ptr, abi::FAT_PTR_ADDR)
331 }
332
333 pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) {
334     Store(bcx, Load(bcx, get_dataptr(bcx, src_ptr)), get_dataptr(bcx, dst_ptr));
335     Store(bcx, Load(bcx, get_meta(bcx, src_ptr)), get_meta(bcx, dst_ptr));
336 }
337
338 fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
339                                    expr: &hir::Expr) -> bool {
340     let adjustment = match bcx.tcx().tables.borrow().adjustments.get(&expr.id).cloned() {
341         None => { return false; }
342         Some(adj) => adj
343     };
344
345     // Don't skip a conversion from Box<T> to &T, etc.
346     if bcx.tcx().is_overloaded_autoderef(expr.id, 0) {
347         return true;
348     }
349
350     match adjustment {
351         AdjustEmptyToAny(..) => true,
352         AdjustReifyFnPointer => true,
353         AdjustUnsafeFnPointer | AdjustMutToConstPointer => {
354             // purely a type-level thing
355             false
356         }
357         AdjustDerefRef(ref adj) => {
358             // We are a bit paranoid about adjustments and thus might have a re-
359             // borrow here which merely derefs and then refs again (it might have
360             // a different region or mutability, but we don't care here).
361             !(adj.autoderefs == 1 && adj.autoref.is_some() && adj.unsize.is_none())
362         }
363     }
364 }
365
366 /// Helper for trans that apply adjustments from `expr` to `datum`, which should be the unadjusted
367 /// translation of `expr`.
368 fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
369                                  expr: &hir::Expr,
370                                  datum: Datum<'tcx, Expr>)
371                                  -> DatumBlock<'blk, 'tcx, Expr>
372 {
373     let mut bcx = bcx;
374     let mut datum = datum;
375     let adjustment = match bcx.tcx().tables.borrow().adjustments.get(&expr.id).cloned() {
376         None => {
377             return DatumBlock::new(bcx, datum);
378         }
379         Some(adj) => { adj }
380     };
381     debug!("unadjusted datum for expr {:?}: {:?} adjustment={:?}",
382            expr, datum, adjustment);
383     match adjustment {
384         AdjustEmptyToAny(ref target) => {
385             let mono_target = bcx.monomorphize(target);
386             let llty = type_of::type_of(bcx.ccx(), mono_target);
387             let dummy = C_undef(llty.ptr_to());
388             datum = Datum::new(dummy, mono_target, Rvalue::new(ByRef)).to_expr_datum();
389         }
390         AdjustReifyFnPointer => {
391             match datum.ty.sty {
392                 ty::TyFnDef(def_id, substs, _) => {
393                     datum = Callee::def(bcx.ccx(), def_id, substs)
394                         .reify(bcx.ccx()).to_expr_datum();
395                 }
396                 _ => {
397                     bug!("{} cannot be reified to a fn ptr", datum.ty)
398                 }
399             }
400         }
401         AdjustUnsafeFnPointer | AdjustMutToConstPointer => {
402             // purely a type-level thing
403         }
404         AdjustDerefRef(ref adj) => {
405             let skip_reborrows = if adj.autoderefs == 1 && adj.autoref.is_some() {
406                 // We are a bit paranoid about adjustments and thus might have a re-
407                 // borrow here which merely derefs and then refs again (it might have
408                 // a different region or mutability, but we don't care here).
409                 match datum.ty.sty {
410                     // Don't skip a conversion from Box<T> to &T, etc.
411                     ty::TyRef(..) => {
412                         if bcx.tcx().is_overloaded_autoderef(expr.id, 0) {
413                             // Don't skip an overloaded deref.
414                             0
415                         } else {
416                             1
417                         }
418                     }
419                     _ => 0
420                 }
421             } else {
422                 0
423             };
424
425             if adj.autoderefs > skip_reborrows {
426                 // Schedule cleanup.
427                 let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id));
428                 datum = unpack_datum!(bcx, deref_multiple(bcx, expr,
429                                                           lval.to_expr_datum(),
430                                                           adj.autoderefs - skip_reborrows));
431             }
432
433             // (You might think there is a more elegant way to do this than a
434             // skip_reborrows bool, but then you remember that the borrow checker exists).
435             if skip_reborrows == 0 && adj.autoref.is_some() {
436                 datum = unpack_datum!(bcx, auto_ref(bcx, datum, expr));
437             }
438
439             if let Some(target) = adj.unsize {
440                 // We do not arrange cleanup ourselves; if we already are an
441                 // L-value, then cleanup will have already been scheduled (and
442                 // the `datum.to_rvalue_datum` call below will emit code to zero
443                 // the drop flag when moving out of the L-value). If we are an
444                 // R-value, then we do not need to schedule cleanup.
445                 let source_datum = unpack_datum!(bcx,
446                     datum.to_rvalue_datum(bcx, "__coerce_source"));
447
448                 let target = bcx.monomorphize(&target);
449
450                 let scratch = alloc_ty(bcx, target, "__coerce_target");
451                 call_lifetime_start(bcx, scratch);
452                 let target_datum = Datum::new(scratch, target,
453                                               Rvalue::new(ByRef));
454                 bcx = coerce_unsized(bcx, expr.span, source_datum, target_datum);
455                 datum = Datum::new(scratch, target,
456                                    RvalueExpr(Rvalue::new(ByRef)));
457             }
458         }
459     }
460     debug!("after adjustments, datum={:?}", datum);
461     DatumBlock::new(bcx, datum)
462 }
463
464 fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
465                               span: syntax_pos::Span,
466                               source: Datum<'tcx, Rvalue>,
467                               target: Datum<'tcx, Rvalue>)
468                               -> Block<'blk, 'tcx> {
469     let mut bcx = bcx;
470     debug!("coerce_unsized({:?} -> {:?})", source, target);
471
472     match (&source.ty.sty, &target.ty.sty) {
473         (&ty::TyBox(a), &ty::TyBox(b)) |
474         (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }),
475          &ty::TyRef(_, ty::TypeAndMut { ty: b, .. })) |
476         (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }),
477          &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) |
478         (&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }),
479          &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => {
480             let (inner_source, inner_target) = (a, b);
481
482             let (base, old_info) = if !type_is_sized(bcx.tcx(), inner_source) {
483                 // Normally, the source is a thin pointer and we are
484                 // adding extra info to make a fat pointer. The exception
485                 // is when we are upcasting an existing object fat pointer
486                 // to use a different vtable. In that case, we want to
487                 // load out the original data pointer so we can repackage
488                 // it.
489                 (Load(bcx, get_dataptr(bcx, source.val)),
490                 Some(Load(bcx, get_meta(bcx, source.val))))
491             } else {
492                 let val = if source.kind.is_by_ref() {
493                     load_ty(bcx, source.val, source.ty)
494                 } else {
495                     source.val
496                 };
497                 (val, None)
498             };
499
500             let info = unsized_info(bcx.ccx(), inner_source, inner_target, old_info);
501
502             // Compute the base pointer. This doesn't change the pointer value,
503             // but merely its type.
504             let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), inner_target).ptr_to();
505             let base = PointerCast(bcx, base, ptr_ty);
506
507             Store(bcx, base, get_dataptr(bcx, target.val));
508             Store(bcx, info, get_meta(bcx, target.val));
509         }
510
511         // This can be extended to enums and tuples in the future.
512         // (&ty::TyEnum(def_id_a, _), &ty::TyEnum(def_id_b, _)) |
513         (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => {
514             assert_eq!(def_id_a, def_id_b);
515
516             // The target is already by-ref because it's to be written to.
517             let source = unpack_datum!(bcx, source.to_ref_datum(bcx));
518             assert!(target.kind.is_by_ref());
519
520             let kind = custom_coerce_unsize_info(bcx.ccx().shared(),
521                                                  source.ty,
522                                                  target.ty);
523
524             let repr_source = adt::represent_type(bcx.ccx(), source.ty);
525             let src_fields = match &*repr_source {
526                 &adt::Repr::Univariant(ref s, _) => &s.fields,
527                 _ => span_bug!(span,
528                                "Non univariant struct? (repr_source: {:?})",
529                                repr_source),
530             };
531             let repr_target = adt::represent_type(bcx.ccx(), target.ty);
532             let target_fields = match &*repr_target {
533                 &adt::Repr::Univariant(ref s, _) => &s.fields,
534                 _ => span_bug!(span,
535                                "Non univariant struct? (repr_target: {:?})",
536                                repr_target),
537             };
538
539             let coerce_index = match kind {
540                 CustomCoerceUnsized::Struct(i) => i
541             };
542             assert!(coerce_index < src_fields.len() && src_fields.len() == target_fields.len());
543
544             let source_val = adt::MaybeSizedValue::sized(source.val);
545             let target_val = adt::MaybeSizedValue::sized(target.val);
546
547             let iter = src_fields.iter().zip(target_fields).enumerate();
548             for (i, (src_ty, target_ty)) in iter {
549                 let ll_source = adt::trans_field_ptr(bcx, &repr_source, source_val, Disr(0), i);
550                 let ll_target = adt::trans_field_ptr(bcx, &repr_target, target_val, Disr(0), i);
551
552                 // If this is the field we need to coerce, recurse on it.
553                 if i == coerce_index {
554                     coerce_unsized(bcx, span,
555                                    Datum::new(ll_source, src_ty,
556                                               Rvalue::new(ByRef)),
557                                    Datum::new(ll_target, target_ty,
558                                               Rvalue::new(ByRef)));
559                 } else {
560                     // Otherwise, simply copy the data from the source.
561                     assert!(src_ty.is_phantom_data() || src_ty == target_ty);
562                     memcpy_ty(bcx, ll_target, ll_source, src_ty);
563                 }
564             }
565         }
566         _ => bug!("coerce_unsized: invalid coercion {:?} -> {:?}",
567                   source.ty,
568                   target.ty)
569     }
570     bcx
571 }
572
573 /// Translates an expression in "lvalue" mode -- meaning that it returns a reference to the memory
574 /// that the expr represents.
575 ///
576 /// If this expression is an rvalue, this implies introducing a temporary.  In other words,
577 /// something like `x().f` is translated into roughly the equivalent of
578 ///
579 ///   { tmp = x(); tmp.f }
580 pub fn trans_to_lvalue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
581                                    expr: &hir::Expr,
582                                    name: &str)
583                                    -> DatumBlock<'blk, 'tcx, Lvalue> {
584     let mut bcx = bcx;
585     let datum = unpack_datum!(bcx, trans(bcx, expr));
586     return datum.to_lvalue_datum(bcx, name, expr.id);
587 }
588
589 /// A version of `trans` that ignores adjustments. You almost certainly do not want to call this
590 /// directly.
591 fn trans_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
592                                 expr: &hir::Expr)
593                                 -> DatumBlock<'blk, 'tcx, Expr> {
594     let mut bcx = bcx;
595
596     debug!("trans_unadjusted(expr={:?})", expr);
597     let _indenter = indenter();
598
599     expr.debug_loc().apply(bcx.fcx);
600
601     return match expr_kind(bcx.tcx(), expr) {
602         ExprKind::Lvalue | ExprKind::RvalueDatum => {
603             let datum = unpack_datum!(bcx, {
604                 trans_datum_unadjusted(bcx, expr)
605             });
606
607             DatumBlock {bcx: bcx, datum: datum}
608         }
609
610         ExprKind::RvalueStmt => {
611             bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
612             nil(bcx, expr_ty(bcx, expr))
613         }
614
615         ExprKind::RvalueDps => {
616             let ty = expr_ty(bcx, expr);
617             if type_is_zero_size(bcx.ccx(), ty) {
618                 bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
619                 nil(bcx, ty)
620             } else {
621                 let scratch = rvalue_scratch_datum(bcx, ty, "");
622                 bcx = trans_rvalue_dps_unadjusted(
623                     bcx, expr, SaveIn(scratch.val));
624
625                 // Note: this is not obviously a good idea.  It causes
626                 // immediate values to be loaded immediately after a
627                 // return from a call or other similar expression,
628                 // which in turn leads to alloca's having shorter
629                 // lifetimes and hence larger stack frames.  However,
630                 // in turn it can lead to more register pressure.
631                 // Still, in practice it seems to increase
632                 // performance, since we have fewer problems with
633                 // morestack churn.
634                 let scratch = unpack_datum!(
635                     bcx, scratch.to_appropriate_datum(bcx));
636
637                 DatumBlock::new(bcx, scratch.to_expr_datum())
638             }
639         }
640     };
641
642     fn nil<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>)
643                        -> DatumBlock<'blk, 'tcx, Expr> {
644         let llval = C_undef(type_of::type_of(bcx.ccx(), ty));
645         let datum = immediate_rvalue(llval, ty);
646         DatumBlock::new(bcx, datum.to_expr_datum())
647     }
648 }
649
650 fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
651                                       expr: &hir::Expr)
652                                       -> DatumBlock<'blk, 'tcx, Expr> {
653     let mut bcx = bcx;
654     let fcx = bcx.fcx;
655     let _icx = push_ctxt("trans_datum_unadjusted");
656
657     match expr.node {
658         hir::ExprType(ref e, _) => {
659             trans(bcx, &e)
660         }
661         hir::ExprPath(..) => {
662             let var = trans_var(bcx, bcx.tcx().expect_def(expr.id));
663             DatumBlock::new(bcx, var.to_expr_datum())
664         }
665         hir::ExprField(ref base, name) => {
666             trans_rec_field(bcx, &base, name.node)
667         }
668         hir::ExprTupField(ref base, idx) => {
669             trans_rec_tup_field(bcx, &base, idx.node)
670         }
671         hir::ExprIndex(ref base, ref idx) => {
672             trans_index(bcx, expr, &base, &idx, MethodCall::expr(expr.id))
673         }
674         hir::ExprBox(ref contents) => {
675             // Special case for `Box<T>`
676             let box_ty = expr_ty(bcx, expr);
677             let contents_ty = expr_ty(bcx, &contents);
678             match box_ty.sty {
679                 ty::TyBox(..) => {
680                     trans_uniq_expr(bcx, expr, box_ty, &contents, contents_ty)
681                 }
682                 _ => span_bug!(expr.span,
683                                "expected unique box")
684             }
685
686         }
687         hir::ExprLit(ref lit) => trans_immediate_lit(bcx, expr, &lit),
688         hir::ExprBinary(op, ref lhs, ref rhs) => {
689             trans_binary(bcx, expr, op, &lhs, &rhs)
690         }
691         hir::ExprUnary(op, ref x) => {
692             trans_unary(bcx, expr, op, &x)
693         }
694         hir::ExprAddrOf(_, ref x) => {
695             match x.node {
696                 hir::ExprRepeat(..) | hir::ExprVec(..) => {
697                     // Special case for slices.
698                     let cleanup_debug_loc =
699                         debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
700                                                                       x.id,
701                                                                       x.span,
702                                                                       false);
703                     fcx.push_ast_cleanup_scope(cleanup_debug_loc);
704                     let datum = unpack_datum!(
705                         bcx, tvec::trans_slice_vec(bcx, expr, &x));
706                     bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, x.id);
707                     DatumBlock::new(bcx, datum)
708                 }
709                 _ => {
710                     trans_addr_of(bcx, expr, &x)
711                 }
712             }
713         }
714         hir::ExprCast(ref val, _) => {
715             // Datum output mode means this is a scalar cast:
716             trans_imm_cast(bcx, &val, expr.id)
717         }
718         _ => {
719             span_bug!(
720                 expr.span,
721                 "trans_rvalue_datum_unadjusted reached \
722                  fall-through case: {:?}",
723                 expr.node);
724         }
725     }
726 }
727
728 fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
729                               base: &hir::Expr,
730                               get_idx: F)
731                               -> DatumBlock<'blk, 'tcx, Expr> where
732     F: FnOnce(TyCtxt<'blk, 'tcx, 'tcx>, &VariantInfo<'tcx>) -> usize,
733 {
734     let mut bcx = bcx;
735     let _icx = push_ctxt("trans_rec_field");
736
737     let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
738     let bare_ty = base_datum.ty;
739     let repr = adt::represent_type(bcx.ccx(), bare_ty);
740     let vinfo = VariantInfo::from_ty(bcx.tcx(), bare_ty, None);
741
742     let ix = get_idx(bcx.tcx(), &vinfo);
743     let d = base_datum.get_element(
744         bcx,
745         vinfo.fields[ix].1,
746         |srcval| {
747             adt::trans_field_ptr(bcx, &repr, srcval, vinfo.discr, ix)
748         });
749
750     if type_is_sized(bcx.tcx(), d.ty) {
751         DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
752     } else {
753         let scratch = rvalue_scratch_datum(bcx, d.ty, "");
754         Store(bcx, d.val, get_dataptr(bcx, scratch.val));
755         let info = Load(bcx, get_meta(bcx, base_datum.val));
756         Store(bcx, info, get_meta(bcx, scratch.val));
757
758         // Always generate an lvalue datum, because this pointer doesn't own
759         // the data and cleanup is scheduled elsewhere.
760         DatumBlock::new(bcx, Datum::new(scratch.val, scratch.ty, LvalueExpr(d.kind)))
761     }
762 }
763
764 /// Translates `base.field`.
765 fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
766                                base: &hir::Expr,
767                                field: ast::Name)
768                                -> DatumBlock<'blk, 'tcx, Expr> {
769     trans_field(bcx, base, |_, vinfo| vinfo.field_index(field))
770 }
771
772 /// Translates `base.<idx>`.
773 fn trans_rec_tup_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
774                                    base: &hir::Expr,
775                                    idx: usize)
776                                    -> DatumBlock<'blk, 'tcx, Expr> {
777     trans_field(bcx, base, |_, _| idx)
778 }
779
780 fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
781                            index_expr: &hir::Expr,
782                            base: &hir::Expr,
783                            idx: &hir::Expr,
784                            method_call: MethodCall)
785                            -> DatumBlock<'blk, 'tcx, Expr> {
786     //! Translates `base[idx]`.
787
788     let _icx = push_ctxt("trans_index");
789     let ccx = bcx.ccx();
790     let mut bcx = bcx;
791
792     let index_expr_debug_loc = index_expr.debug_loc();
793
794     // Check for overloaded index.
795     let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned();
796     let elt_datum = match method {
797         Some(method) => {
798             let method_ty = monomorphize_type(bcx, method.ty);
799
800             let base_datum = unpack_datum!(bcx, trans(bcx, base));
801
802             // Translate index expression.
803             let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
804
805             let ref_ty = // invoked methods have LB regions instantiated:
806                 bcx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
807             let elt_ty = match ref_ty.builtin_deref(true, ty::NoPreference) {
808                 None => {
809                     span_bug!(index_expr.span,
810                               "index method didn't return a \
811                               dereferenceable type?!")
812                 }
813                 Some(elt_tm) => elt_tm.ty,
814             };
815
816             // Overloaded. Invoke the index() method, which basically
817             // yields a `&T` pointer.  We can then proceed down the
818             // normal path (below) to dereference that `&T`.
819             let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_index_elt");
820
821             bcx = Callee::method(bcx, method)
822                 .call(bcx, index_expr_debug_loc,
823                       ArgOverloadedOp(base_datum, Some(ix_datum)),
824                       Some(SaveIn(scratch.val))).bcx;
825
826             let datum = scratch.to_expr_datum();
827             let lval = Lvalue::new("expr::trans_index overload");
828             if type_is_sized(bcx.tcx(), elt_ty) {
829                 Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr(lval))
830             } else {
831                 Datum::new(datum.val, elt_ty, LvalueExpr(lval))
832             }
833         }
834         None => {
835             let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx,
836                                                                 base,
837                                                                 "index"));
838
839             // Translate index expression and cast to a suitable LLVM integer.
840             // Rust is less strict than LLVM in this regard.
841             let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
842             let ix_val = ix_datum.to_llscalarish(bcx);
843             let ix_size = machine::llbitsize_of_real(bcx.ccx(),
844                                                      val_ty(ix_val));
845             let int_size = machine::llbitsize_of_real(bcx.ccx(),
846                                                       ccx.int_type());
847             let ix_val = {
848                 if ix_size < int_size {
849                     if expr_ty(bcx, idx).is_signed() {
850                         SExt(bcx, ix_val, ccx.int_type())
851                     } else { ZExt(bcx, ix_val, ccx.int_type()) }
852                 } else if ix_size > int_size {
853                     Trunc(bcx, ix_val, ccx.int_type())
854                 } else {
855                     ix_val
856                 }
857             };
858
859             let unit_ty = base_datum.ty.sequence_element_type(bcx.tcx());
860
861             let (base, len) = base_datum.get_vec_base_and_len(bcx);
862
863             debug!("trans_index: base {:?}", Value(base));
864             debug!("trans_index: len {:?}", Value(len));
865
866             let bounds_check = ICmp(bcx,
867                                     llvm::IntUGE,
868                                     ix_val,
869                                     len,
870                                     index_expr_debug_loc);
871             let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
872             let expected = Call(bcx,
873                                 expect,
874                                 &[bounds_check, C_bool(ccx, false)],
875                                 index_expr_debug_loc);
876             bcx = with_cond(bcx, expected, |bcx| {
877                 controlflow::trans_fail_bounds_check(bcx,
878                                                      expr_info(index_expr),
879                                                      ix_val,
880                                                      len)
881             });
882             let elt = InBoundsGEP(bcx, base, &[ix_val]);
883             let elt = PointerCast(bcx, elt, type_of::type_of(ccx, unit_ty).ptr_to());
884             let lval = Lvalue::new("expr::trans_index fallback");
885             Datum::new(elt, unit_ty, LvalueExpr(lval))
886         }
887     };
888
889     DatumBlock::new(bcx, elt_datum)
890 }
891
892 /// Translates a reference to a variable.
893 pub fn trans_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, def: Def)
894                              -> Datum<'tcx, Lvalue> {
895
896     match def {
897         Def::Static(did, _) => consts::get_static(bcx.ccx(), did),
898         Def::Upvar(_, nid, _, _) => {
899             // Can't move upvars, so this is never a ZeroMemLastUse.
900             let local_ty = node_id_type(bcx, nid);
901             let lval = Lvalue::new_with_hint("expr::trans_var (upvar)",
902                                              bcx, nid, HintKind::ZeroAndMaintain);
903             match bcx.fcx.llupvars.borrow().get(&nid) {
904                 Some(&val) => Datum::new(val, local_ty, lval),
905                 None => {
906                     bug!("trans_var: no llval for upvar {} found", nid);
907                 }
908             }
909         }
910         Def::Local(_, nid) => {
911             let datum = match bcx.fcx.lllocals.borrow().get(&nid) {
912                 Some(&v) => v,
913                 None => {
914                     bug!("trans_var: no datum for local/arg {} found", nid);
915                 }
916             };
917             debug!("take_local(nid={}, v={:?}, ty={})",
918                    nid, Value(datum.val), datum.ty);
919             datum
920         }
921         _ => bug!("{:?} should not reach expr::trans_var", def)
922     }
923 }
924
925 fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
926                                             expr: &hir::Expr)
927                                             -> Block<'blk, 'tcx> {
928     let mut bcx = bcx;
929     let _icx = push_ctxt("trans_rvalue_stmt");
930
931     if bcx.unreachable.get() {
932         return bcx;
933     }
934
935     expr.debug_loc().apply(bcx.fcx);
936
937     match expr.node {
938         hir::ExprBreak(label_opt) => {
939             controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node))
940         }
941         hir::ExprType(ref e, _) => {
942             trans_into(bcx, &e, Ignore)
943         }
944         hir::ExprAgain(label_opt) => {
945             controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node))
946         }
947         hir::ExprRet(ref ex) => {
948             // Check to see if the return expression itself is reachable.
949             // This can occur when the inner expression contains a return
950             let reachable = if let Some(ref cfg) = bcx.fcx.cfg {
951                 cfg.node_is_reachable(expr.id)
952             } else {
953                 true
954             };
955
956             if reachable {
957                 controlflow::trans_ret(bcx, expr, ex.as_ref().map(|e| &**e))
958             } else {
959                 // If it's not reachable, just translate the inner expression
960                 // directly. This avoids having to manage a return slot when
961                 // it won't actually be used anyway.
962                 if let &Some(ref x) = ex {
963                     bcx = trans_into(bcx, &x, Ignore);
964                 }
965                 // Mark the end of the block as unreachable. Once we get to
966                 // a return expression, there's no more we should be doing
967                 // after this.
968                 Unreachable(bcx);
969                 bcx
970             }
971         }
972         hir::ExprWhile(ref cond, ref body, _) => {
973             controlflow::trans_while(bcx, expr, &cond, &body)
974         }
975         hir::ExprLoop(ref body, _) => {
976             controlflow::trans_loop(bcx, expr, &body)
977         }
978         hir::ExprAssign(ref dst, ref src) => {
979             let src_datum = unpack_datum!(bcx, trans(bcx, &src));
980             let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &dst, "assign"));
981
982             if bcx.fcx.type_needs_drop(dst_datum.ty) {
983                 // If there are destructors involved, make sure we
984                 // are copying from an rvalue, since that cannot possible
985                 // alias an lvalue. We are concerned about code like:
986                 //
987                 //   a = a
988                 //
989                 // but also
990                 //
991                 //   a = a.b
992                 //
993                 // where e.g. a : Option<Foo> and a.b :
994                 // Option<Foo>. In that case, freeing `a` before the
995                 // assignment may also free `a.b`!
996                 //
997                 // We could avoid this intermediary with some analysis
998                 // to determine whether `dst` may possibly own `src`.
999                 expr.debug_loc().apply(bcx.fcx);
1000                 let src_datum = unpack_datum!(
1001                     bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign"));
1002                 let opt_hint_datum = dst_datum.kind.drop_flag_info.hint_datum(bcx);
1003                 let opt_hint_val = opt_hint_datum.map(|d|d.to_value());
1004
1005                 // 1. Drop the data at the destination, passing the
1006                 //    drop-hint in case the lvalue has already been
1007                 //    dropped or moved.
1008                 bcx = glue::drop_ty_core(bcx,
1009                                          dst_datum.val,
1010                                          dst_datum.ty,
1011                                          expr.debug_loc(),
1012                                          false,
1013                                          opt_hint_val);
1014
1015                 // 2. We are overwriting the destination; ensure that
1016                 //    its drop-hint (if any) says "initialized."
1017                 if let Some(hint_val) = opt_hint_val {
1018                     let hint_llval = hint_val.value();
1019                     let drop_needed = C_u8(bcx.fcx.ccx, adt::DTOR_NEEDED_HINT);
1020                     Store(bcx, drop_needed, hint_llval);
1021                 }
1022                 src_datum.store_to(bcx, dst_datum.val)
1023             } else {
1024                 src_datum.store_to(bcx, dst_datum.val)
1025             }
1026         }
1027         hir::ExprAssignOp(op, ref dst, ref src) => {
1028             let method = bcx.tcx().tables
1029                                   .borrow()
1030                                   .method_map
1031                                   .get(&MethodCall::expr(expr.id)).cloned();
1032
1033             if let Some(method) = method {
1034                 let dst = unpack_datum!(bcx, trans(bcx, &dst));
1035                 let src_datum = unpack_datum!(bcx, trans(bcx, &src));
1036
1037                 Callee::method(bcx, method)
1038                     .call(bcx, expr.debug_loc(),
1039                           ArgOverloadedOp(dst, Some(src_datum)), None).bcx
1040             } else {
1041                 trans_assign_op(bcx, expr, op, &dst, &src)
1042             }
1043         }
1044         hir::ExprInlineAsm(ref a, ref outputs, ref inputs) => {
1045             let outputs = outputs.iter().map(|output| {
1046                 let out_datum = unpack_datum!(bcx, trans(bcx, output));
1047                 unpack_datum!(bcx, out_datum.to_lvalue_datum(bcx, "out", expr.id))
1048             }).collect();
1049             let inputs = inputs.iter().map(|input| {
1050                 let input = unpack_datum!(bcx, trans(bcx, input));
1051                 let input = unpack_datum!(bcx, input.to_rvalue_datum(bcx, "in"));
1052                 input.to_llscalarish(bcx)
1053             }).collect();
1054             asm::trans_inline_asm(bcx, a, outputs, inputs);
1055             bcx
1056         }
1057         _ => {
1058             span_bug!(
1059                 expr.span,
1060                 "trans_rvalue_stmt_unadjusted reached \
1061                  fall-through case: {:?}",
1062                 expr.node);
1063         }
1064     }
1065 }
1066
1067 fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1068                                            expr: &hir::Expr,
1069                                            dest: Dest)
1070                                            -> Block<'blk, 'tcx> {
1071     let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
1072     let mut bcx = bcx;
1073
1074     expr.debug_loc().apply(bcx.fcx);
1075
1076     // Entry into the method table if this is an overloaded call/op.
1077     let method_call = MethodCall::expr(expr.id);
1078
1079     match expr.node {
1080         hir::ExprType(ref e, _) => {
1081             trans_into(bcx, &e, dest)
1082         }
1083         hir::ExprPath(..) => {
1084             trans_def_dps_unadjusted(bcx, expr, bcx.tcx().expect_def(expr.id), dest)
1085         }
1086         hir::ExprIf(ref cond, ref thn, ref els) => {
1087             controlflow::trans_if(bcx, expr.id, &cond, &thn, els.as_ref().map(|e| &**e), dest)
1088         }
1089         hir::ExprMatch(ref discr, ref arms, _) => {
1090             _match::trans_match(bcx, expr, &discr, &arms[..], dest)
1091         }
1092         hir::ExprBlock(ref blk) => {
1093             controlflow::trans_block(bcx, &blk, dest)
1094         }
1095         hir::ExprStruct(_, ref fields, ref base) => {
1096             trans_struct(bcx,
1097                          &fields[..],
1098                          base.as_ref().map(|e| &**e),
1099                          expr.span,
1100                          expr.id,
1101                          node_id_type(bcx, expr.id),
1102                          dest)
1103         }
1104         hir::ExprTup(ref args) => {
1105             let numbered_fields: Vec<(usize, &hir::Expr)> =
1106                 args.iter().enumerate().map(|(i, arg)| (i, &**arg)).collect();
1107             trans_adt(bcx,
1108                       expr_ty(bcx, expr),
1109                       Disr(0),
1110                       &numbered_fields[..],
1111                       None,
1112                       dest,
1113                       expr.debug_loc())
1114         }
1115         hir::ExprLit(ref lit) => {
1116             match lit.node {
1117                 ast::LitKind::Str(ref s, _) => {
1118                     tvec::trans_lit_str(bcx, expr, (*s).clone(), dest)
1119                 }
1120                 _ => {
1121                     span_bug!(expr.span,
1122                               "trans_rvalue_dps_unadjusted shouldn't be \
1123                               translating this type of literal")
1124                 }
1125             }
1126         }
1127         hir::ExprVec(..) | hir::ExprRepeat(..) => {
1128             tvec::trans_fixed_vstore(bcx, expr, dest)
1129         }
1130         hir::ExprClosure(_, ref decl, ref body, _) => {
1131             let dest = match dest {
1132                 SaveIn(lldest) => closure::Dest::SaveIn(bcx, lldest),
1133                 Ignore => closure::Dest::Ignore(bcx.ccx())
1134             };
1135
1136             // NB. To get the id of the closure, we don't use
1137             // `local_def_id(id)`, but rather we extract the closure
1138             // def-id from the expr's type. This is because this may
1139             // be an inlined expression from another crate, and we
1140             // want to get the ORIGINAL closure def-id, since that is
1141             // the key we need to find the closure-kind and
1142             // closure-type etc.
1143             let (def_id, substs) = match expr_ty(bcx, expr).sty {
1144                 ty::TyClosure(def_id, substs) => (def_id, substs),
1145                 ref t =>
1146                     span_bug!(
1147                         expr.span,
1148                         "closure expr without closure type: {:?}", t),
1149             };
1150
1151             closure::trans_closure_expr(dest,
1152                                         decl,
1153                                         body,
1154                                         expr.id,
1155                                         def_id,
1156                                         substs).unwrap_or(bcx)
1157         }
1158         hir::ExprCall(ref f, ref args) => {
1159             let method = bcx.tcx().tables.borrow().method_map.get(&method_call).cloned();
1160             let (callee, args) = if let Some(method) = method {
1161                 let mut all_args = vec![&**f];
1162                 all_args.extend(args.iter().map(|e| &**e));
1163
1164                 (Callee::method(bcx, method), ArgOverloadedCall(all_args))
1165             } else {
1166                 let f = unpack_datum!(bcx, trans(bcx, f));
1167                 (match f.ty.sty {
1168                     ty::TyFnDef(def_id, substs, _) => {
1169                         Callee::def(bcx.ccx(), def_id, substs)
1170                     }
1171                     ty::TyFnPtr(_) => {
1172                         let f = unpack_datum!(bcx,
1173                             f.to_rvalue_datum(bcx, "callee"));
1174                         Callee::ptr(f)
1175                     }
1176                     _ => {
1177                         span_bug!(expr.span,
1178                             "type of callee is not a fn: {}", f.ty);
1179                     }
1180                 }, ArgExprs(&args))
1181             };
1182             callee.call(bcx, expr.debug_loc(), args, Some(dest)).bcx
1183         }
1184         hir::ExprMethodCall(_, _, ref args) => {
1185             Callee::method_call(bcx, method_call)
1186                 .call(bcx, expr.debug_loc(), ArgExprs(&args), Some(dest)).bcx
1187         }
1188         hir::ExprBinary(op, ref lhs, ref rhs_expr) => {
1189             // if not overloaded, would be RvalueDatumExpr
1190             let lhs = unpack_datum!(bcx, trans(bcx, &lhs));
1191             let mut rhs = unpack_datum!(bcx, trans(bcx, &rhs_expr));
1192             if !op.node.is_by_value() {
1193                 rhs = unpack_datum!(bcx, auto_ref(bcx, rhs, rhs_expr));
1194             }
1195
1196             Callee::method_call(bcx, method_call)
1197                 .call(bcx, expr.debug_loc(),
1198                       ArgOverloadedOp(lhs, Some(rhs)), Some(dest)).bcx
1199         }
1200         hir::ExprUnary(_, ref subexpr) => {
1201             // if not overloaded, would be RvalueDatumExpr
1202             let arg = unpack_datum!(bcx, trans(bcx, &subexpr));
1203
1204             Callee::method_call(bcx, method_call)
1205                 .call(bcx, expr.debug_loc(),
1206                       ArgOverloadedOp(arg, None), Some(dest)).bcx
1207         }
1208         hir::ExprCast(..) => {
1209             // Trait casts used to come this way, now they should be coercions.
1210             span_bug!(expr.span, "DPS expr_cast (residual trait cast?)")
1211         }
1212         hir::ExprAssignOp(op, _, _) => {
1213             span_bug!(
1214                 expr.span,
1215                 "augmented assignment `{}=` should always be a rvalue_stmt",
1216                 op.node.as_str())
1217         }
1218         _ => {
1219             span_bug!(
1220                 expr.span,
1221                 "trans_rvalue_dps_unadjusted reached fall-through \
1222                  case: {:?}",
1223                 expr.node);
1224         }
1225     }
1226 }
1227
1228 fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1229                                         ref_expr: &hir::Expr,
1230                                         def: Def,
1231                                         dest: Dest)
1232                                         -> Block<'blk, 'tcx> {
1233     let _icx = push_ctxt("trans_def_dps_unadjusted");
1234
1235     let lldest = match dest {
1236         SaveIn(lldest) => lldest,
1237         Ignore => { return bcx; }
1238     };
1239
1240     let ty = expr_ty(bcx, ref_expr);
1241     if let ty::TyFnDef(..) = ty.sty {
1242         // Zero-sized function or ctor.
1243         return bcx;
1244     }
1245
1246     match def {
1247         Def::Variant(tid, vid) => {
1248             let variant = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
1249             // Nullary variant.
1250             let ty = expr_ty(bcx, ref_expr);
1251             let repr = adt::represent_type(bcx.ccx(), ty);
1252             adt::trans_set_discr(bcx, &repr, lldest, Disr::from(variant.disr_val));
1253             bcx
1254         }
1255         Def::Struct(..) => {
1256             match ty.sty {
1257                 ty::TyStruct(def, _) if def.has_dtor() => {
1258                     let repr = adt::represent_type(bcx.ccx(), ty);
1259                     adt::trans_set_discr(bcx, &repr, lldest, Disr(0));
1260                 }
1261                 _ => {}
1262             }
1263             bcx
1264         }
1265         _ => {
1266             span_bug!(ref_expr.span,
1267                       "Non-DPS def {:?} referened by {}",
1268                       def, bcx.node_id_to_string(ref_expr.id));
1269         }
1270     }
1271 }
1272
1273 fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1274                             fields: &[hir::Field],
1275                             base: Option<&hir::Expr>,
1276                             expr_span: syntax_pos::Span,
1277                             expr_id: ast::NodeId,
1278                             ty: Ty<'tcx>,
1279                             dest: Dest) -> Block<'blk, 'tcx> {
1280     let _icx = push_ctxt("trans_rec");
1281
1282     let tcx = bcx.tcx();
1283     let vinfo = VariantInfo::of_node(tcx, ty, expr_id);
1284
1285     let mut need_base = vec![true; vinfo.fields.len()];
1286
1287     let numbered_fields = fields.iter().map(|field| {
1288         let pos = vinfo.field_index(field.name.node);
1289         need_base[pos] = false;
1290         (pos, &*field.expr)
1291     }).collect::<Vec<_>>();
1292
1293     let optbase = match base {
1294         Some(base_expr) => {
1295             let mut leftovers = Vec::new();
1296             for (i, b) in need_base.iter().enumerate() {
1297                 if *b {
1298                     leftovers.push((i, vinfo.fields[i].1));
1299                 }
1300             }
1301             Some(StructBaseInfo {expr: base_expr,
1302                                  fields: leftovers })
1303         }
1304         None => {
1305             if need_base.iter().any(|b| *b) {
1306                 span_bug!(expr_span, "missing fields and no base expr")
1307             }
1308             None
1309         }
1310     };
1311
1312     trans_adt(bcx,
1313               ty,
1314               vinfo.discr,
1315               &numbered_fields,
1316               optbase,
1317               dest,
1318               DebugLoc::At(expr_id, expr_span))
1319 }
1320
1321 /// Information that `trans_adt` needs in order to fill in the fields
1322 /// of a struct copied from a base struct (e.g., from an expression
1323 /// like `Foo { a: b, ..base }`.
1324 ///
1325 /// Note that `fields` may be empty; the base expression must always be
1326 /// evaluated for side-effects.
1327 pub struct StructBaseInfo<'a, 'tcx> {
1328     /// The base expression; will be evaluated after all explicit fields.
1329     expr: &'a hir::Expr,
1330     /// The indices of fields to copy paired with their types.
1331     fields: Vec<(usize, Ty<'tcx>)>
1332 }
1333
1334 /// Constructs an ADT instance:
1335 ///
1336 /// - `fields` should be a list of field indices paired with the
1337 /// expression to store into that field.  The initializers will be
1338 /// evaluated in the order specified by `fields`.
1339 ///
1340 /// - `optbase` contains information on the base struct (if any) from
1341 /// which remaining fields are copied; see comments on `StructBaseInfo`.
1342 pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
1343                                  ty: Ty<'tcx>,
1344                                  discr: Disr,
1345                                  fields: &[(usize, &hir::Expr)],
1346                                  optbase: Option<StructBaseInfo<'a, 'tcx>>,
1347                                  dest: Dest,
1348                                  debug_location: DebugLoc)
1349                                  -> Block<'blk, 'tcx> {
1350     let _icx = push_ctxt("trans_adt");
1351     let fcx = bcx.fcx;
1352     let repr = adt::represent_type(bcx.ccx(), ty);
1353
1354     debug_location.apply(bcx.fcx);
1355
1356     // If we don't care about the result, just make a
1357     // temporary stack slot
1358     let addr = match dest {
1359         SaveIn(pos) => pos,
1360         Ignore => {
1361             let llresult = alloc_ty(bcx, ty, "temp");
1362             call_lifetime_start(bcx, llresult);
1363             llresult
1364         }
1365     };
1366
1367     debug!("trans_adt");
1368
1369     // This scope holds intermediates that must be cleaned should
1370     // panic occur before the ADT as a whole is ready.
1371     let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
1372
1373     if ty.is_simd() {
1374         // Issue 23112: The original logic appeared vulnerable to same
1375         // order-of-eval bug. But, SIMD values are tuple-structs;
1376         // i.e. functional record update (FRU) syntax is unavailable.
1377         //
1378         // To be safe, double-check that we did not get here via FRU.
1379         assert!(optbase.is_none());
1380
1381         // This is the constructor of a SIMD type, such types are
1382         // always primitive machine types and so do not have a
1383         // destructor or require any clean-up.
1384         let llty = type_of::type_of(bcx.ccx(), ty);
1385
1386         // keep a vector as a register, and running through the field
1387         // `insertelement`ing them directly into that register
1388         // (i.e. avoid GEPi and `store`s to an alloca) .
1389         let mut vec_val = C_undef(llty);
1390
1391         for &(i, ref e) in fields {
1392             let block_datum = trans(bcx, &e);
1393             bcx = block_datum.bcx;
1394             let position = C_uint(bcx.ccx(), i);
1395             let value = block_datum.datum.to_llscalarish(bcx);
1396             vec_val = InsertElement(bcx, vec_val, value, position);
1397         }
1398         Store(bcx, vec_val, addr);
1399     } else if let Some(base) = optbase {
1400         // Issue 23112: If there is a base, then order-of-eval
1401         // requires field expressions eval'ed before base expression.
1402
1403         // First, trans field expressions to temporary scratch values.
1404         let scratch_vals: Vec<_> = fields.iter().map(|&(i, ref e)| {
1405             let datum = unpack_datum!(bcx, trans(bcx, &e));
1406             (i, datum)
1407         }).collect();
1408
1409         debug_location.apply(bcx.fcx);
1410
1411         // Second, trans the base to the dest.
1412         assert_eq!(discr, Disr(0));
1413
1414         let addr = adt::MaybeSizedValue::sized(addr);
1415         match expr_kind(bcx.tcx(), &base.expr) {
1416             ExprKind::RvalueDps | ExprKind::RvalueDatum if !bcx.fcx.type_needs_drop(ty) => {
1417                 bcx = trans_into(bcx, &base.expr, SaveIn(addr.value));
1418             },
1419             ExprKind::RvalueStmt => {
1420                 bug!("unexpected expr kind for struct base expr")
1421             }
1422             _ => {
1423                 let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &base.expr, "base"));
1424                 for &(i, t) in &base.fields {
1425                     let datum = base_datum.get_element(
1426                             bcx, t, |srcval| adt::trans_field_ptr(bcx, &repr, srcval, discr, i));
1427                     assert!(type_is_sized(bcx.tcx(), datum.ty));
1428                     let dest = adt::trans_field_ptr(bcx, &repr, addr, discr, i);
1429                     bcx = datum.store_to(bcx, dest);
1430                 }
1431             }
1432         }
1433
1434         // Finally, move scratch field values into actual field locations
1435         for (i, datum) in scratch_vals {
1436             let dest = adt::trans_field_ptr(bcx, &repr, addr, discr, i);
1437             bcx = datum.store_to(bcx, dest);
1438         }
1439     } else {
1440         // No base means we can write all fields directly in place.
1441         let addr = adt::MaybeSizedValue::sized(addr);
1442         for &(i, ref e) in fields {
1443             let dest = adt::trans_field_ptr(bcx, &repr, addr, discr, i);
1444             let e_ty = expr_ty_adjusted(bcx, &e);
1445             bcx = trans_into(bcx, &e, SaveIn(dest));
1446             let scope = cleanup::CustomScope(custom_cleanup_scope);
1447             fcx.schedule_lifetime_end(scope, dest);
1448             // FIXME: nonzeroing move should generalize to fields
1449             fcx.schedule_drop_mem(scope, dest, e_ty, None);
1450         }
1451     }
1452
1453     adt::trans_set_discr(bcx, &repr, addr, discr);
1454
1455     fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
1456
1457     // If we don't care about the result drop the temporary we made
1458     match dest {
1459         SaveIn(_) => bcx,
1460         Ignore => {
1461             bcx = glue::drop_ty(bcx, addr, ty, debug_location);
1462             base::call_lifetime_end(bcx, addr);
1463             bcx
1464         }
1465     }
1466 }
1467
1468
1469 fn trans_immediate_lit<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1470                                    expr: &hir::Expr,
1471                                    lit: &ast::Lit)
1472                                    -> DatumBlock<'blk, 'tcx, Expr> {
1473     // must not be a string constant, that is a RvalueDpsExpr
1474     let _icx = push_ctxt("trans_immediate_lit");
1475     let ty = expr_ty(bcx, expr);
1476     let v = consts::const_lit(bcx.ccx(), expr, lit);
1477     immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock()
1478 }
1479
1480 fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1481                            expr: &hir::Expr,
1482                            op: hir::UnOp,
1483                            sub_expr: &hir::Expr)
1484                            -> DatumBlock<'blk, 'tcx, Expr> {
1485     let ccx = bcx.ccx();
1486     let mut bcx = bcx;
1487     let _icx = push_ctxt("trans_unary_datum");
1488
1489     let method_call = MethodCall::expr(expr.id);
1490
1491     // The only overloaded operator that is translated to a datum
1492     // is an overloaded deref, since it is always yields a `&T`.
1493     // Otherwise, we should be in the RvalueDpsExpr path.
1494     assert!(op == hir::UnDeref || !ccx.tcx().is_method_call(expr.id));
1495
1496     let un_ty = expr_ty(bcx, expr);
1497
1498     let debug_loc = expr.debug_loc();
1499
1500     match op {
1501         hir::UnNot => {
1502             let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1503             let llresult = Not(bcx, datum.to_llscalarish(bcx), debug_loc);
1504             immediate_rvalue_bcx(bcx, llresult, un_ty).to_expr_datumblock()
1505         }
1506         hir::UnNeg => {
1507             let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1508             let val = datum.to_llscalarish(bcx);
1509             let (bcx, llneg) = {
1510                 if un_ty.is_fp() {
1511                     let result = FNeg(bcx, val, debug_loc);
1512                     (bcx, result)
1513                 } else {
1514                     let is_signed = un_ty.is_signed();
1515                     let result = Neg(bcx, val, debug_loc);
1516                     let bcx = if bcx.ccx().check_overflow() && is_signed {
1517                         let (llty, min) = base::llty_and_min_for_signed_ty(bcx, un_ty);
1518                         let is_min = ICmp(bcx, llvm::IntEQ, val,
1519                                           C_integral(llty, min, true), debug_loc);
1520                         with_cond(bcx, is_min, |bcx| {
1521                             let msg = InternedString::new(
1522                                 "attempt to negate with overflow");
1523                             controlflow::trans_fail(bcx, expr_info(expr), msg)
1524                         })
1525                     } else {
1526                         bcx
1527                     };
1528                     (bcx, result)
1529                 }
1530             };
1531             immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
1532         }
1533         hir::UnDeref => {
1534             let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1535             deref_once(bcx, expr, datum, method_call)
1536         }
1537     }
1538 }
1539
1540 fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1541                                box_expr: &hir::Expr,
1542                                box_ty: Ty<'tcx>,
1543                                contents: &hir::Expr,
1544                                contents_ty: Ty<'tcx>)
1545                                -> DatumBlock<'blk, 'tcx, Expr> {
1546     let _icx = push_ctxt("trans_uniq_expr");
1547     let fcx = bcx.fcx;
1548     assert!(type_is_sized(bcx.tcx(), contents_ty));
1549     let llty = type_of::type_of(bcx.ccx(), contents_ty);
1550     let size = llsize_of(bcx.ccx(), llty);
1551     let align = C_uint(bcx.ccx(), type_of::align_of(bcx.ccx(), contents_ty));
1552     let llty_ptr = llty.ptr_to();
1553     let Result { bcx, val } = malloc_raw_dyn(bcx,
1554                                              llty_ptr,
1555                                              box_ty,
1556                                              size,
1557                                              align,
1558                                              box_expr.debug_loc());
1559     // Unique boxes do not allocate for zero-size types. The standard library
1560     // may assume that `free` is never called on the pointer returned for
1561     // `Box<ZeroSizeType>`.
1562     let bcx = if llsize_of_alloc(bcx.ccx(), llty) == 0 {
1563         trans_into(bcx, contents, SaveIn(val))
1564     } else {
1565         let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
1566         fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
1567                                 val, cleanup::HeapExchange, contents_ty);
1568         let bcx = trans_into(bcx, contents, SaveIn(val));
1569         fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
1570         bcx
1571     };
1572     immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
1573 }
1574
1575 fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1576                              expr: &hir::Expr,
1577                              subexpr: &hir::Expr)
1578                              -> DatumBlock<'blk, 'tcx, Expr> {
1579     let _icx = push_ctxt("trans_addr_of");
1580     let mut bcx = bcx;
1581     let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
1582     let ty = expr_ty(bcx, expr);
1583     if !type_is_sized(bcx.tcx(), sub_datum.ty) {
1584         // Always generate an lvalue datum, because this pointer doesn't own
1585         // the data and cleanup is scheduled elsewhere.
1586         DatumBlock::new(bcx, Datum::new(sub_datum.val, ty, LvalueExpr(sub_datum.kind)))
1587     } else {
1588         // Sized value, ref to a thin pointer
1589         immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock()
1590     }
1591 }
1592
1593 fn trans_scalar_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1594                                   binop_expr: &hir::Expr,
1595                                   binop_ty: Ty<'tcx>,
1596                                   op: hir::BinOp,
1597                                   lhs: Datum<'tcx, Rvalue>,
1598                                   rhs: Datum<'tcx, Rvalue>)
1599                                   -> DatumBlock<'blk, 'tcx, Expr>
1600 {
1601     let _icx = push_ctxt("trans_scalar_binop");
1602
1603     let lhs_t = lhs.ty;
1604     assert!(!lhs_t.is_simd());
1605     let is_float = lhs_t.is_fp();
1606     let is_signed = lhs_t.is_signed();
1607     let info = expr_info(binop_expr);
1608
1609     let binop_debug_loc = binop_expr.debug_loc();
1610
1611     let mut bcx = bcx;
1612     let lhs = lhs.to_llscalarish(bcx);
1613     let rhs = rhs.to_llscalarish(bcx);
1614     let val = match op.node {
1615       hir::BiAdd => {
1616         if is_float {
1617             FAdd(bcx, lhs, rhs, binop_debug_loc)
1618         } else {
1619             let (newbcx, res) = with_overflow_check(
1620                 bcx, OverflowOp::Add, info, lhs_t, lhs, rhs, binop_debug_loc);
1621             bcx = newbcx;
1622             res
1623         }
1624       }
1625       hir::BiSub => {
1626         if is_float {
1627             FSub(bcx, lhs, rhs, binop_debug_loc)
1628         } else {
1629             let (newbcx, res) = with_overflow_check(
1630                 bcx, OverflowOp::Sub, info, lhs_t, lhs, rhs, binop_debug_loc);
1631             bcx = newbcx;
1632             res
1633         }
1634       }
1635       hir::BiMul => {
1636         if is_float {
1637             FMul(bcx, lhs, rhs, binop_debug_loc)
1638         } else {
1639             let (newbcx, res) = with_overflow_check(
1640                 bcx, OverflowOp::Mul, info, lhs_t, lhs, rhs, binop_debug_loc);
1641             bcx = newbcx;
1642             res
1643         }
1644       }
1645       hir::BiDiv => {
1646         if is_float {
1647             FDiv(bcx, lhs, rhs, binop_debug_loc)
1648         } else {
1649             // Only zero-check integers; fp /0 is NaN
1650             bcx = base::fail_if_zero_or_overflows(bcx,
1651                                                   expr_info(binop_expr),
1652                                                   op,
1653                                                   lhs,
1654                                                   rhs,
1655                                                   lhs_t);
1656             if is_signed {
1657                 SDiv(bcx, lhs, rhs, binop_debug_loc)
1658             } else {
1659                 UDiv(bcx, lhs, rhs, binop_debug_loc)
1660             }
1661         }
1662       }
1663       hir::BiRem => {
1664         if is_float {
1665             FRem(bcx, lhs, rhs, binop_debug_loc)
1666         } else {
1667             // Only zero-check integers; fp %0 is NaN
1668             bcx = base::fail_if_zero_or_overflows(bcx,
1669                                                   expr_info(binop_expr),
1670                                                   op, lhs, rhs, lhs_t);
1671             if is_signed {
1672                 SRem(bcx, lhs, rhs, binop_debug_loc)
1673             } else {
1674                 URem(bcx, lhs, rhs, binop_debug_loc)
1675             }
1676         }
1677       }
1678       hir::BiBitOr => Or(bcx, lhs, rhs, binop_debug_loc),
1679       hir::BiBitAnd => And(bcx, lhs, rhs, binop_debug_loc),
1680       hir::BiBitXor => Xor(bcx, lhs, rhs, binop_debug_loc),
1681       hir::BiShl => {
1682           let (newbcx, res) = with_overflow_check(
1683               bcx, OverflowOp::Shl, info, lhs_t, lhs, rhs, binop_debug_loc);
1684           bcx = newbcx;
1685           res
1686       }
1687       hir::BiShr => {
1688           let (newbcx, res) = with_overflow_check(
1689               bcx, OverflowOp::Shr, info, lhs_t, lhs, rhs, binop_debug_loc);
1690           bcx = newbcx;
1691           res
1692       }
1693       hir::BiEq | hir::BiNe | hir::BiLt | hir::BiGe | hir::BiLe | hir::BiGt => {
1694           base::compare_scalar_types(bcx, lhs, rhs, lhs_t, op.node, binop_debug_loc)
1695       }
1696       _ => {
1697         span_bug!(binop_expr.span, "unexpected binop");
1698       }
1699     };
1700
1701     immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
1702 }
1703
1704 // refinement types would obviate the need for this
1705 #[derive(Clone, Copy)]
1706 enum lazy_binop_ty {
1707     lazy_and,
1708     lazy_or,
1709 }
1710
1711
1712 fn trans_lazy_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1713                                 binop_expr: &hir::Expr,
1714                                 op: lazy_binop_ty,
1715                                 a: &hir::Expr,
1716                                 b: &hir::Expr)
1717                                 -> DatumBlock<'blk, 'tcx, Expr> {
1718     let _icx = push_ctxt("trans_lazy_binop");
1719     let binop_ty = expr_ty(bcx, binop_expr);
1720     let fcx = bcx.fcx;
1721
1722     let DatumBlock {bcx: past_lhs, datum: lhs} = trans(bcx, a);
1723     let lhs = lhs.to_llscalarish(past_lhs);
1724
1725     if past_lhs.unreachable.get() {
1726         return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock();
1727     }
1728
1729     // If the rhs can never be reached, don't generate code for it.
1730     if let Some(cond_val) = const_to_opt_uint(lhs) {
1731         match (cond_val, op) {
1732             (0, lazy_and) |
1733             (1, lazy_or)  => {
1734                 return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock();
1735             }
1736             _ => { /* continue */ }
1737         }
1738     }
1739
1740     let join = fcx.new_id_block("join", binop_expr.id);
1741     let before_rhs = fcx.new_id_block("before_rhs", b.id);
1742
1743     match op {
1744       lazy_and => CondBr(past_lhs, lhs, before_rhs.llbb, join.llbb, DebugLoc::None),
1745       lazy_or => CondBr(past_lhs, lhs, join.llbb, before_rhs.llbb, DebugLoc::None)
1746     }
1747
1748     let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b);
1749     let rhs = rhs.to_llscalarish(past_rhs);
1750
1751     if past_rhs.unreachable.get() {
1752         return immediate_rvalue_bcx(join, lhs, binop_ty).to_expr_datumblock();
1753     }
1754
1755     Br(past_rhs, join.llbb, DebugLoc::None);
1756     let phi = Phi(join, Type::i1(bcx.ccx()), &[lhs, rhs],
1757                   &[past_lhs.llbb, past_rhs.llbb]);
1758
1759     return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
1760 }
1761
1762 fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1763                             expr: &hir::Expr,
1764                             op: hir::BinOp,
1765                             lhs: &hir::Expr,
1766                             rhs: &hir::Expr)
1767                             -> DatumBlock<'blk, 'tcx, Expr> {
1768     let _icx = push_ctxt("trans_binary");
1769     let ccx = bcx.ccx();
1770
1771     // if overloaded, would be RvalueDpsExpr
1772     assert!(!ccx.tcx().is_method_call(expr.id));
1773
1774     match op.node {
1775         hir::BiAnd => {
1776             trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
1777         }
1778         hir::BiOr => {
1779             trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
1780         }
1781         _ => {
1782             let mut bcx = bcx;
1783             let binop_ty = expr_ty(bcx, expr);
1784
1785             let lhs = unpack_datum!(bcx, trans(bcx, lhs));
1786             let lhs = unpack_datum!(bcx, lhs.to_rvalue_datum(bcx, "binop_lhs"));
1787             debug!("trans_binary (expr {}): lhs={:?}", expr.id, lhs);
1788             let rhs = unpack_datum!(bcx, trans(bcx, rhs));
1789             let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "binop_rhs"));
1790             debug!("trans_binary (expr {}): rhs={:?}", expr.id, rhs);
1791
1792             if type_is_fat_ptr(ccx.tcx(), lhs.ty) {
1793                 assert!(type_is_fat_ptr(ccx.tcx(), rhs.ty),
1794                         "built-in binary operators on fat pointers are homogeneous");
1795                 assert_eq!(binop_ty, bcx.tcx().types.bool);
1796                 let val = base::compare_scalar_types(
1797                     bcx,
1798                     lhs.val,
1799                     rhs.val,
1800                     lhs.ty,
1801                     op.node,
1802                     expr.debug_loc());
1803                 immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
1804             } else {
1805                 assert!(!type_is_fat_ptr(ccx.tcx(), rhs.ty),
1806                         "built-in binary operators on fat pointers are homogeneous");
1807                 trans_scalar_binop(bcx, expr, binop_ty, op, lhs, rhs)
1808             }
1809         }
1810     }
1811 }
1812
1813 pub fn cast_is_noop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1814                               expr: &hir::Expr,
1815                               t_in: Ty<'tcx>,
1816                               t_out: Ty<'tcx>)
1817                               -> bool {
1818     if let Some(&CastKind::CoercionCast) = tcx.cast_kinds.borrow().get(&expr.id) {
1819         return true;
1820     }
1821
1822     match (t_in.builtin_deref(true, ty::NoPreference),
1823            t_out.builtin_deref(true, ty::NoPreference)) {
1824         (Some(ty::TypeAndMut{ ty: t_in, .. }), Some(ty::TypeAndMut{ ty: t_out, .. })) => {
1825             t_in == t_out
1826         }
1827         _ => {
1828             // This condition isn't redundant with the check for CoercionCast:
1829             // different types can be substituted into the same type, and
1830             // == equality can be overconservative if there are regions.
1831             t_in == t_out
1832         }
1833     }
1834 }
1835
1836 fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1837                               expr: &hir::Expr,
1838                               id: ast::NodeId)
1839                               -> DatumBlock<'blk, 'tcx, Expr>
1840 {
1841     use rustc::ty::cast::CastTy::*;
1842     use rustc::ty::cast::IntTy::*;
1843
1844     fn int_cast(bcx: Block,
1845                 lldsttype: Type,
1846                 llsrctype: Type,
1847                 llsrc: ValueRef,
1848                 signed: bool)
1849                 -> ValueRef
1850     {
1851         let _icx = push_ctxt("int_cast");
1852         let srcsz = llsrctype.int_width();
1853         let dstsz = lldsttype.int_width();
1854         return if dstsz == srcsz {
1855             BitCast(bcx, llsrc, lldsttype)
1856         } else if srcsz > dstsz {
1857             TruncOrBitCast(bcx, llsrc, lldsttype)
1858         } else if signed {
1859             SExtOrBitCast(bcx, llsrc, lldsttype)
1860         } else {
1861             ZExtOrBitCast(bcx, llsrc, lldsttype)
1862         }
1863     }
1864
1865     fn float_cast(bcx: Block,
1866                   lldsttype: Type,
1867                   llsrctype: Type,
1868                   llsrc: ValueRef)
1869                   -> ValueRef
1870     {
1871         let _icx = push_ctxt("float_cast");
1872         let srcsz = llsrctype.float_width();
1873         let dstsz = lldsttype.float_width();
1874         return if dstsz > srcsz {
1875             FPExt(bcx, llsrc, lldsttype)
1876         } else if srcsz > dstsz {
1877             FPTrunc(bcx, llsrc, lldsttype)
1878         } else { llsrc };
1879     }
1880
1881     let _icx = push_ctxt("trans_cast");
1882     let mut bcx = bcx;
1883     let ccx = bcx.ccx();
1884
1885     let t_in = expr_ty_adjusted(bcx, expr);
1886     let t_out = node_id_type(bcx, id);
1887
1888     debug!("trans_cast({:?} as {:?})", t_in, t_out);
1889     let mut ll_t_in = type_of::immediate_type_of(ccx, t_in);
1890     let ll_t_out = type_of::immediate_type_of(ccx, t_out);
1891     // Convert the value to be cast into a ValueRef, either by-ref or
1892     // by-value as appropriate given its type:
1893     let mut datum = unpack_datum!(bcx, trans(bcx, expr));
1894
1895     let datum_ty = monomorphize_type(bcx, datum.ty);
1896
1897     if cast_is_noop(bcx.tcx(), expr, datum_ty, t_out) {
1898         datum.ty = t_out;
1899         return DatumBlock::new(bcx, datum);
1900     }
1901
1902     if type_is_fat_ptr(bcx.tcx(), t_in) {
1903         assert!(datum.kind.is_by_ref());
1904         if type_is_fat_ptr(bcx.tcx(), t_out) {
1905             return DatumBlock::new(bcx, Datum::new(
1906                 PointerCast(bcx, datum.val, ll_t_out.ptr_to()),
1907                 t_out,
1908                 Rvalue::new(ByRef)
1909             )).to_expr_datumblock();
1910         } else {
1911             // Return the address
1912             return immediate_rvalue_bcx(bcx,
1913                                         PointerCast(bcx,
1914                                                     Load(bcx, get_dataptr(bcx, datum.val)),
1915                                                     ll_t_out),
1916                                         t_out).to_expr_datumblock();
1917         }
1918     }
1919
1920     let r_t_in = CastTy::from_ty(t_in).expect("bad input type for cast");
1921     let r_t_out = CastTy::from_ty(t_out).expect("bad output type for cast");
1922
1923     let (llexpr, signed) = if let Int(CEnum) = r_t_in {
1924         let repr = adt::represent_type(ccx, t_in);
1925         let datum = unpack_datum!(
1926             bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
1927         let llexpr_ptr = datum.to_llref();
1928         let discr = adt::trans_get_discr(bcx, &repr, llexpr_ptr,
1929                                          Some(Type::i64(ccx)), true);
1930         ll_t_in = val_ty(discr);
1931         (discr, adt::is_discr_signed(&repr))
1932     } else {
1933         (datum.to_llscalarish(bcx), t_in.is_signed())
1934     };
1935
1936     let newval = match (r_t_in, r_t_out) {
1937         (Ptr(_), Ptr(_)) | (FnPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => {
1938             PointerCast(bcx, llexpr, ll_t_out)
1939         }
1940         (Ptr(_), Int(_)) | (FnPtr, Int(_)) => PtrToInt(bcx, llexpr, ll_t_out),
1941         (Int(_), Ptr(_)) => IntToPtr(bcx, llexpr, ll_t_out),
1942
1943         (Int(_), Int(_)) => int_cast(bcx, ll_t_out, ll_t_in, llexpr, signed),
1944         (Float, Float) => float_cast(bcx, ll_t_out, ll_t_in, llexpr),
1945         (Int(_), Float) if signed => SIToFP(bcx, llexpr, ll_t_out),
1946         (Int(_), Float) => UIToFP(bcx, llexpr, ll_t_out),
1947         (Float, Int(I)) => FPToSI(bcx, llexpr, ll_t_out),
1948         (Float, Int(_)) => FPToUI(bcx, llexpr, ll_t_out),
1949
1950         _ => span_bug!(expr.span,
1951                        "translating unsupported cast: \
1952                         {:?} -> {:?}",
1953                        t_in,
1954                        t_out)
1955     };
1956     return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
1957 }
1958
1959 fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1960                                expr: &hir::Expr,
1961                                op: hir::BinOp,
1962                                dst: &hir::Expr,
1963                                src: &hir::Expr)
1964                                -> Block<'blk, 'tcx> {
1965     let _icx = push_ctxt("trans_assign_op");
1966     let mut bcx = bcx;
1967
1968     debug!("trans_assign_op(expr={:?})", expr);
1969
1970     // User-defined operator methods cannot be used with `+=` etc right now
1971     assert!(!bcx.tcx().is_method_call(expr.id));
1972
1973     // Evaluate LHS (destination), which should be an lvalue
1974     let dst = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
1975     assert!(!bcx.fcx.type_needs_drop(dst.ty));
1976     let lhs = load_ty(bcx, dst.val, dst.ty);
1977     let lhs = immediate_rvalue(lhs, dst.ty);
1978
1979     // Evaluate RHS - FIXME(#28160) this sucks
1980     let rhs = unpack_datum!(bcx, trans(bcx, &src));
1981     let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "assign_op_rhs"));
1982
1983     // Perform computation and store the result
1984     let result_datum = unpack_datum!(
1985         bcx, trans_scalar_binop(bcx, expr, dst.ty, op, lhs, rhs));
1986     return result_datum.store_to(bcx, dst.val);
1987 }
1988
1989 fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1990                         datum: Datum<'tcx, Expr>,
1991                         expr: &hir::Expr)
1992                         -> DatumBlock<'blk, 'tcx, Expr> {
1993     let mut bcx = bcx;
1994
1995     // Ensure cleanup of `datum` if not already scheduled and obtain
1996     // a "by ref" pointer.
1997     let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id));
1998
1999     // Compute final type. Note that we are loose with the region and
2000     // mutability, since those things don't matter in trans.
2001     let referent_ty = lv_datum.ty;
2002     let ptr_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReErased), referent_ty);
2003
2004     // Construct the resulting datum. The right datum to return here would be an Lvalue datum,
2005     // because there is cleanup scheduled and the datum doesn't own the data, but for thin pointers
2006     // we microoptimize it to be an Rvalue datum to avoid the extra alloca and level of
2007     // indirection and for thin pointers, this has no ill effects.
2008     let kind  = if type_is_sized(bcx.tcx(), referent_ty) {
2009         RvalueExpr(Rvalue::new(ByValue))
2010     } else {
2011         LvalueExpr(lv_datum.kind)
2012     };
2013
2014     // Get the pointer.
2015     let llref = lv_datum.to_llref();
2016     DatumBlock::new(bcx, Datum::new(llref, ptr_ty, kind))
2017 }
2018
2019 fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2020                               expr: &hir::Expr,
2021                               datum: Datum<'tcx, Expr>,
2022                               times: usize)
2023                               -> DatumBlock<'blk, 'tcx, Expr> {
2024     let mut bcx = bcx;
2025     let mut datum = datum;
2026     for i in 0..times {
2027         let method_call = MethodCall::autoderef(expr.id, i as u32);
2028         datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call));
2029     }
2030     DatumBlock { bcx: bcx, datum: datum }
2031 }
2032
2033 fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2034                           expr: &hir::Expr,
2035                           datum: Datum<'tcx, Expr>,
2036                           method_call: MethodCall)
2037                           -> DatumBlock<'blk, 'tcx, Expr> {
2038     let ccx = bcx.ccx();
2039
2040     debug!("deref_once(expr={:?}, datum={:?}, method_call={:?})",
2041            expr, datum, method_call);
2042
2043     let mut bcx = bcx;
2044
2045     // Check for overloaded deref.
2046     let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned();
2047     let datum = match method {
2048         Some(method) => {
2049             let method_ty = monomorphize_type(bcx, method.ty);
2050
2051             // Overloaded. Invoke the deref() method, which basically
2052             // converts from the `Smaht<T>` pointer that we have into
2053             // a `&T` pointer.  We can then proceed down the normal
2054             // path (below) to dereference that `&T`.
2055             let datum = if method_call.autoderef == 0 {
2056                 datum
2057             } else {
2058                 // Always perform an AutoPtr when applying an overloaded auto-deref
2059                 unpack_datum!(bcx, auto_ref(bcx, datum, expr))
2060             };
2061
2062             let ref_ty = // invoked methods have their LB regions instantiated
2063                 ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
2064             let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
2065
2066             bcx = Callee::method(bcx, method)
2067                 .call(bcx, expr.debug_loc(),
2068                       ArgOverloadedOp(datum, None),
2069                       Some(SaveIn(scratch.val))).bcx;
2070             scratch.to_expr_datum()
2071         }
2072         None => {
2073             // Not overloaded. We already have a pointer we know how to deref.
2074             datum
2075         }
2076     };
2077
2078     let r = match datum.ty.sty {
2079         ty::TyBox(content_ty) => {
2080             // Make sure we have an lvalue datum here to get the
2081             // proper cleanups scheduled
2082             let datum = unpack_datum!(
2083                 bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
2084
2085             if type_is_sized(bcx.tcx(), content_ty) {
2086                 let ptr = load_ty(bcx, datum.val, datum.ty);
2087                 DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr(datum.kind)))
2088             } else {
2089                 // A fat pointer and a DST lvalue have the same representation
2090                 // just different types. Since there is no temporary for `*e`
2091                 // here (because it is unsized), we cannot emulate the sized
2092                 // object code path for running drop glue and free. Instead,
2093                 // we schedule cleanup for `e`, turning it into an lvalue.
2094
2095                 let lval = Lvalue::new("expr::deref_once ty_uniq");
2096                 let datum = Datum::new(datum.val, content_ty, LvalueExpr(lval));
2097                 DatumBlock::new(bcx, datum)
2098             }
2099         }
2100
2101         ty::TyRawPtr(ty::TypeAndMut { ty: content_ty, .. }) |
2102         ty::TyRef(_, ty::TypeAndMut { ty: content_ty, .. }) => {
2103             let lval = Lvalue::new("expr::deref_once ptr");
2104             if type_is_sized(bcx.tcx(), content_ty) {
2105                 let ptr = datum.to_llscalarish(bcx);
2106
2107                 // Always generate an lvalue datum, even if datum.mode is
2108                 // an rvalue.  This is because datum.mode is only an
2109                 // rvalue for non-owning pointers like &T or *T, in which
2110                 // case cleanup *is* scheduled elsewhere, by the true
2111                 // owner (or, in the case of *T, by the user).
2112                 DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr(lval)))
2113             } else {
2114                 // A fat pointer and a DST lvalue have the same representation
2115                 // just different types.
2116                 DatumBlock::new(bcx, Datum::new(datum.val, content_ty, LvalueExpr(lval)))
2117             }
2118         }
2119
2120         _ => {
2121             span_bug!(
2122                 expr.span,
2123                 "deref invoked on expr of invalid type {:?}",
2124                 datum.ty);
2125         }
2126     };
2127
2128     debug!("deref_once(expr={}, method_call={:?}, result={:?})",
2129            expr.id, method_call, r.datum);
2130
2131     return r;
2132 }
2133
2134 #[derive(Debug)]
2135 enum OverflowOp {
2136     Add,
2137     Sub,
2138     Mul,
2139     Shl,
2140     Shr,
2141 }
2142
2143 impl OverflowOp {
2144     fn codegen_strategy(&self) -> OverflowCodegen {
2145         use self::OverflowCodegen::{ViaIntrinsic, ViaInputCheck};
2146         match *self {
2147             OverflowOp::Add => ViaIntrinsic(OverflowOpViaIntrinsic::Add),
2148             OverflowOp::Sub => ViaIntrinsic(OverflowOpViaIntrinsic::Sub),
2149             OverflowOp::Mul => ViaIntrinsic(OverflowOpViaIntrinsic::Mul),
2150
2151             OverflowOp::Shl => ViaInputCheck(OverflowOpViaInputCheck::Shl),
2152             OverflowOp::Shr => ViaInputCheck(OverflowOpViaInputCheck::Shr),
2153         }
2154     }
2155 }
2156
2157 enum OverflowCodegen {
2158     ViaIntrinsic(OverflowOpViaIntrinsic),
2159     ViaInputCheck(OverflowOpViaInputCheck),
2160 }
2161
2162 enum OverflowOpViaInputCheck { Shl, Shr, }
2163
2164 #[derive(Debug)]
2165 enum OverflowOpViaIntrinsic { Add, Sub, Mul, }
2166
2167 impl OverflowOpViaIntrinsic {
2168     fn to_intrinsic<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>, lhs_ty: Ty) -> ValueRef {
2169         let name = self.to_intrinsic_name(bcx.tcx(), lhs_ty);
2170         bcx.ccx().get_intrinsic(&name)
2171     }
2172     fn to_intrinsic_name(&self, tcx: TyCtxt, ty: Ty) -> &'static str {
2173         use syntax::ast::IntTy::*;
2174         use syntax::ast::UintTy::*;
2175         use rustc::ty::{TyInt, TyUint};
2176
2177         let new_sty = match ty.sty {
2178             TyInt(Is) => match &tcx.sess.target.target.target_pointer_width[..] {
2179                 "16" => TyInt(I16),
2180                 "32" => TyInt(I32),
2181                 "64" => TyInt(I64),
2182                 _ => bug!("unsupported target word size")
2183             },
2184             TyUint(Us) => match &tcx.sess.target.target.target_pointer_width[..] {
2185                 "16" => TyUint(U16),
2186                 "32" => TyUint(U32),
2187                 "64" => TyUint(U64),
2188                 _ => bug!("unsupported target word size")
2189             },
2190             ref t @ TyUint(_) | ref t @ TyInt(_) => t.clone(),
2191             _ => bug!("tried to get overflow intrinsic for {:?} applied to non-int type",
2192                       *self)
2193         };
2194
2195         match *self {
2196             OverflowOpViaIntrinsic::Add => match new_sty {
2197                 TyInt(I8) => "llvm.sadd.with.overflow.i8",
2198                 TyInt(I16) => "llvm.sadd.with.overflow.i16",
2199                 TyInt(I32) => "llvm.sadd.with.overflow.i32",
2200                 TyInt(I64) => "llvm.sadd.with.overflow.i64",
2201
2202                 TyUint(U8) => "llvm.uadd.with.overflow.i8",
2203                 TyUint(U16) => "llvm.uadd.with.overflow.i16",
2204                 TyUint(U32) => "llvm.uadd.with.overflow.i32",
2205                 TyUint(U64) => "llvm.uadd.with.overflow.i64",
2206
2207                 _ => bug!(),
2208             },
2209             OverflowOpViaIntrinsic::Sub => match new_sty {
2210                 TyInt(I8) => "llvm.ssub.with.overflow.i8",
2211                 TyInt(I16) => "llvm.ssub.with.overflow.i16",
2212                 TyInt(I32) => "llvm.ssub.with.overflow.i32",
2213                 TyInt(I64) => "llvm.ssub.with.overflow.i64",
2214
2215                 TyUint(U8) => "llvm.usub.with.overflow.i8",
2216                 TyUint(U16) => "llvm.usub.with.overflow.i16",
2217                 TyUint(U32) => "llvm.usub.with.overflow.i32",
2218                 TyUint(U64) => "llvm.usub.with.overflow.i64",
2219
2220                 _ => bug!(),
2221             },
2222             OverflowOpViaIntrinsic::Mul => match new_sty {
2223                 TyInt(I8) => "llvm.smul.with.overflow.i8",
2224                 TyInt(I16) => "llvm.smul.with.overflow.i16",
2225                 TyInt(I32) => "llvm.smul.with.overflow.i32",
2226                 TyInt(I64) => "llvm.smul.with.overflow.i64",
2227
2228                 TyUint(U8) => "llvm.umul.with.overflow.i8",
2229                 TyUint(U16) => "llvm.umul.with.overflow.i16",
2230                 TyUint(U32) => "llvm.umul.with.overflow.i32",
2231                 TyUint(U64) => "llvm.umul.with.overflow.i64",
2232
2233                 _ => bug!(),
2234             },
2235         }
2236     }
2237
2238     fn build_intrinsic_call<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>,
2239                                         info: NodeIdAndSpan,
2240                                         lhs_t: Ty<'tcx>, lhs: ValueRef,
2241                                         rhs: ValueRef,
2242                                         binop_debug_loc: DebugLoc)
2243                                         -> (Block<'blk, 'tcx>, ValueRef) {
2244         use rustc_const_math::{ConstMathErr, Op};
2245
2246         let llfn = self.to_intrinsic(bcx, lhs_t);
2247
2248         let val = Call(bcx, llfn, &[lhs, rhs], binop_debug_loc);
2249         let result = ExtractValue(bcx, val, 0); // iN operation result
2250         let overflow = ExtractValue(bcx, val, 1); // i1 "did it overflow?"
2251
2252         let cond = ICmp(bcx, llvm::IntEQ, overflow, C_integral(Type::i1(bcx.ccx()), 1, false),
2253                         binop_debug_loc);
2254
2255         let expect = bcx.ccx().get_intrinsic(&"llvm.expect.i1");
2256         let expected = Call(bcx, expect, &[cond, C_bool(bcx.ccx(), false)],
2257                             binop_debug_loc);
2258
2259         let op = match *self {
2260             OverflowOpViaIntrinsic::Add => Op::Add,
2261             OverflowOpViaIntrinsic::Sub => Op::Sub,
2262             OverflowOpViaIntrinsic::Mul => Op::Mul
2263         };
2264
2265         let bcx =
2266             base::with_cond(bcx, expected, |bcx|
2267                 controlflow::trans_fail(bcx, info,
2268                     InternedString::new(ConstMathErr::Overflow(op).description())));
2269
2270         (bcx, result)
2271     }
2272 }
2273
2274 impl OverflowOpViaInputCheck {
2275     fn build_with_input_check<'blk, 'tcx>(&self,
2276                                           bcx: Block<'blk, 'tcx>,
2277                                           info: NodeIdAndSpan,
2278                                           lhs_t: Ty<'tcx>,
2279                                           lhs: ValueRef,
2280                                           rhs: ValueRef,
2281                                           binop_debug_loc: DebugLoc)
2282                                           -> (Block<'blk, 'tcx>, ValueRef)
2283     {
2284         use rustc_const_math::{ConstMathErr, Op};
2285
2286         let lhs_llty = val_ty(lhs);
2287         let rhs_llty = val_ty(rhs);
2288
2289         // Panic if any bits are set outside of bits that we always
2290         // mask in.
2291         //
2292         // Note that the mask's value is derived from the LHS type
2293         // (since that is where the 32/64 distinction is relevant) but
2294         // the mask's type must match the RHS type (since they will
2295         // both be fed into an and-binop)
2296         let invert_mask = shift_mask_val(bcx, lhs_llty, rhs_llty, true);
2297
2298         let outer_bits = And(bcx, rhs, invert_mask, binop_debug_loc);
2299         let cond = build_nonzero_check(bcx, outer_bits, binop_debug_loc);
2300         let (result, op) = match *self {
2301             OverflowOpViaInputCheck::Shl =>
2302                 (build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc), Op::Shl),
2303             OverflowOpViaInputCheck::Shr =>
2304                 (build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc), Op::Shr)
2305         };
2306         let bcx =
2307             base::with_cond(bcx, cond, |bcx|
2308                 controlflow::trans_fail(bcx, info,
2309                     InternedString::new(ConstMathErr::Overflow(op).description())));
2310
2311         (bcx, result)
2312     }
2313 }
2314
2315 // Check if an integer or vector contains a nonzero element.
2316 fn build_nonzero_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
2317                                    value: ValueRef,
2318                                    binop_debug_loc: DebugLoc) -> ValueRef {
2319     let llty = val_ty(value);
2320     let kind = llty.kind();
2321     match kind {
2322         TypeKind::Integer => ICmp(bcx, llvm::IntNE, value, C_null(llty), binop_debug_loc),
2323         TypeKind::Vector => {
2324             // Check if any elements of the vector are nonzero by treating
2325             // it as a wide integer and checking if the integer is nonzero.
2326             let width = llty.vector_length() as u64 * llty.element_type().int_width();
2327             let int_value = BitCast(bcx, value, Type::ix(bcx.ccx(), width));
2328             build_nonzero_check(bcx, int_value, binop_debug_loc)
2329         },
2330         _ => bug!("build_nonzero_check: expected Integer or Vector, found {:?}", kind),
2331     }
2332 }
2333
2334 fn with_overflow_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, oop: OverflowOp, info: NodeIdAndSpan,
2335                                    lhs_t: Ty<'tcx>, lhs: ValueRef,
2336                                    rhs: ValueRef,
2337                                    binop_debug_loc: DebugLoc)
2338                                    -> (Block<'blk, 'tcx>, ValueRef) {
2339     if bcx.unreachable.get() { return (bcx, _Undef(lhs)); }
2340     if bcx.ccx().check_overflow() {
2341
2342         match oop.codegen_strategy() {
2343             OverflowCodegen::ViaIntrinsic(oop) =>
2344                 oop.build_intrinsic_call(bcx, info, lhs_t, lhs, rhs, binop_debug_loc),
2345             OverflowCodegen::ViaInputCheck(oop) =>
2346                 oop.build_with_input_check(bcx, info, lhs_t, lhs, rhs, binop_debug_loc),
2347         }
2348     } else {
2349         let res = match oop {
2350             OverflowOp::Add => Add(bcx, lhs, rhs, binop_debug_loc),
2351             OverflowOp::Sub => Sub(bcx, lhs, rhs, binop_debug_loc),
2352             OverflowOp::Mul => Mul(bcx, lhs, rhs, binop_debug_loc),
2353
2354             OverflowOp::Shl =>
2355                 build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc),
2356             OverflowOp::Shr =>
2357                 build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc),
2358         };
2359         (bcx, res)
2360     }
2361 }
2362
2363 /// We categorize expressions into three kinds.  The distinction between
2364 /// lvalue/rvalue is fundamental to the language.  The distinction between the
2365 /// two kinds of rvalues is an artifact of trans which reflects how we will
2366 /// generate code for that kind of expression.  See trans/expr.rs for more
2367 /// information.
2368 #[derive(Copy, Clone)]
2369 enum ExprKind {
2370     Lvalue,
2371     RvalueDps,
2372     RvalueDatum,
2373     RvalueStmt
2374 }
2375
2376 fn expr_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, expr: &hir::Expr) -> ExprKind {
2377     if tcx.is_method_call(expr.id) {
2378         // Overloaded operations are generally calls, and hence they are
2379         // generated via DPS, but there are a few exceptions:
2380         return match expr.node {
2381             // `a += b` has a unit result.
2382             hir::ExprAssignOp(..) => ExprKind::RvalueStmt,
2383
2384             // the deref method invoked for `*a` always yields an `&T`
2385             hir::ExprUnary(hir::UnDeref, _) => ExprKind::Lvalue,
2386
2387             // the index method invoked for `a[i]` always yields an `&T`
2388             hir::ExprIndex(..) => ExprKind::Lvalue,
2389
2390             // in the general case, result could be any type, use DPS
2391             _ => ExprKind::RvalueDps
2392         };
2393     }
2394
2395     match expr.node {
2396         hir::ExprPath(..) => {
2397             match tcx.expect_def(expr.id) {
2398                 // Put functions and ctors with the ADTs, as they
2399                 // are zero-sized, so DPS is the cheapest option.
2400                 Def::Struct(..) | Def::Variant(..) |
2401                 Def::Fn(..) | Def::Method(..) => {
2402                     ExprKind::RvalueDps
2403                 }
2404
2405                 // Note: there is actually a good case to be made that
2406                 // DefArg's, particularly those of immediate type, ought to
2407                 // considered rvalues.
2408                 Def::Static(..) |
2409                 Def::Upvar(..) |
2410                 Def::Local(..) => ExprKind::Lvalue,
2411
2412                 Def::Const(..) |
2413                 Def::AssociatedConst(..) => ExprKind::RvalueDatum,
2414
2415                 def => {
2416                     span_bug!(
2417                         expr.span,
2418                         "uncategorized def for expr {}: {:?}",
2419                         expr.id,
2420                         def);
2421                 }
2422             }
2423         }
2424
2425         hir::ExprType(ref expr, _) => {
2426             expr_kind(tcx, expr)
2427         }
2428
2429         hir::ExprUnary(hir::UnDeref, _) |
2430         hir::ExprField(..) |
2431         hir::ExprTupField(..) |
2432         hir::ExprIndex(..) => {
2433             ExprKind::Lvalue
2434         }
2435
2436         hir::ExprCall(..) |
2437         hir::ExprMethodCall(..) |
2438         hir::ExprStruct(..) |
2439         hir::ExprTup(..) |
2440         hir::ExprIf(..) |
2441         hir::ExprMatch(..) |
2442         hir::ExprClosure(..) |
2443         hir::ExprBlock(..) |
2444         hir::ExprRepeat(..) |
2445         hir::ExprVec(..) => {
2446             ExprKind::RvalueDps
2447         }
2448
2449         hir::ExprLit(ref lit) if lit.node.is_str() => {
2450             ExprKind::RvalueDps
2451         }
2452
2453         hir::ExprBreak(..) |
2454         hir::ExprAgain(..) |
2455         hir::ExprRet(..) |
2456         hir::ExprWhile(..) |
2457         hir::ExprLoop(..) |
2458         hir::ExprAssign(..) |
2459         hir::ExprInlineAsm(..) |
2460         hir::ExprAssignOp(..) => {
2461             ExprKind::RvalueStmt
2462         }
2463
2464         hir::ExprLit(_) | // Note: LitStr is carved out above
2465         hir::ExprUnary(..) |
2466         hir::ExprBox(_) |
2467         hir::ExprAddrOf(..) |
2468         hir::ExprBinary(..) |
2469         hir::ExprCast(..) => {
2470             ExprKind::RvalueDatum
2471         }
2472     }
2473 }