]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/mir/constant.rs
Unignore u128 test for stage 0,1
[rust.git] / src / librustc_trans / mir / constant.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 use llvm::{self, ValueRef};
12 use rustc::middle::const_val::ConstVal;
13 use rustc_const_eval::{ErrKind, ConstEvalErr, report_const_eval_err};
14 use rustc_const_math::ConstInt::*;
15 use rustc_const_math::ConstFloat::*;
16 use rustc_const_math::{ConstInt, ConstMathErr};
17 use rustc::hir::def_id::DefId;
18 use rustc::infer::TransNormalize;
19 use rustc::mir;
20 use rustc::mir::tcx::LvalueTy;
21 use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable};
22 use rustc::ty::cast::{CastTy, IntTy};
23 use rustc::ty::subst::Substs;
24 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
25 use {abi, adt, base, Disr, machine};
26 use callee::Callee;
27 use builder::Builder;
28 use common::{self, CrateContext, const_get_elt, val_ty};
29 use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integral};
30 use common::{C_null, C_struct, C_str_slice, C_undef, C_uint, C_vector, is_undef};
31 use common::const_to_opt_u128;
32 use consts;
33 use monomorphize::{self, Instance};
34 use type_of;
35 use type_::Type;
36 use value::Value;
37
38 use syntax_pos::Span;
39
40 use std::fmt;
41 use std::ptr;
42
43 use super::operand::{OperandRef, OperandValue};
44 use super::MirContext;
45
46 /// A sized constant rvalue.
47 /// The LLVM type might not be the same for a single Rust type,
48 /// e.g. each enum variant would have its own LLVM struct type.
49 #[derive(Copy, Clone)]
50 pub struct Const<'tcx> {
51     pub llval: ValueRef,
52     pub ty: Ty<'tcx>
53 }
54
55 impl<'tcx> Const<'tcx> {
56     pub fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> {
57         Const {
58             llval: llval,
59             ty: ty
60         }
61     }
62
63     /// Translate ConstVal into a LLVM constant value.
64     pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
65                              cv: ConstVal,
66                              ty: Ty<'tcx>)
67                              -> Const<'tcx> {
68         let llty = type_of::type_of(ccx, ty);
69         let val = match cv {
70             ConstVal::Float(F32(v)) => C_floating_f64(v as f64, llty),
71             ConstVal::Float(F64(v)) => C_floating_f64(v, llty),
72             ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv),
73             ConstVal::Bool(v) => C_bool(ccx, v),
74             ConstVal::Integral(I8(v)) => C_integral(Type::i8(ccx), v as u64, true),
75             ConstVal::Integral(I16(v)) => C_integral(Type::i16(ccx), v as u64, true),
76             ConstVal::Integral(I32(v)) => C_integral(Type::i32(ccx), v as u64, true),
77             ConstVal::Integral(I64(v)) => C_integral(Type::i64(ccx), v as u64, true),
78             ConstVal::Integral(I128(v)) => C_big_integral(Type::i128(ccx), v as u128),
79             ConstVal::Integral(Isize(v)) => {
80                 let i = v.as_i64(ccx.tcx().sess.target.int_type);
81                 C_integral(Type::int(ccx), i as u64, true)
82             },
83             ConstVal::Integral(U8(v)) => C_integral(Type::i8(ccx), v as u64, false),
84             ConstVal::Integral(U16(v)) => C_integral(Type::i16(ccx), v as u64, false),
85             ConstVal::Integral(U32(v)) => C_integral(Type::i32(ccx), v as u64, false),
86             ConstVal::Integral(U64(v)) => C_integral(Type::i64(ccx), v, false),
87             ConstVal::Integral(U128(v)) => C_big_integral(Type::i128(ccx), v),
88             ConstVal::Integral(Usize(v)) => {
89                 let u = v.as_u64(ccx.tcx().sess.target.uint_type);
90                 C_integral(Type::int(ccx), u, false)
91             },
92             ConstVal::Integral(Infer(_)) |
93             ConstVal::Integral(InferSigned(_)) => bug!("MIR must not use `{:?}`", cv),
94             ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
95             ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
96             ConstVal::Struct(_) | ConstVal::Tuple(_) |
97             ConstVal::Array(..) | ConstVal::Repeat(..) |
98             ConstVal::Function(_) => {
99                 bug!("MIR must not use `{:?}` (which refers to a local ID)", cv)
100             }
101             ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
102         };
103
104         assert!(!ty.has_erasable_regions());
105
106         Const::new(val, ty)
107     }
108
109     fn get_pair(&self) -> (ValueRef, ValueRef) {
110         (const_get_elt(self.llval, &[0]),
111          const_get_elt(self.llval, &[1]))
112     }
113
114     fn get_fat_ptr(&self) -> (ValueRef, ValueRef) {
115         assert_eq!(abi::FAT_PTR_ADDR, 0);
116         assert_eq!(abi::FAT_PTR_EXTRA, 1);
117         self.get_pair()
118     }
119
120     fn as_lvalue(&self) -> ConstLvalue<'tcx> {
121         ConstLvalue {
122             base: Base::Value(self.llval),
123             llextra: ptr::null_mut(),
124             ty: self.ty
125         }
126     }
127
128     pub fn to_operand<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> {
129         let llty = type_of::immediate_type_of(ccx, self.ty);
130         let llvalty = val_ty(self.llval);
131
132         let val = if llty == llvalty && common::type_is_imm_pair(ccx, self.ty) {
133             let (a, b) = self.get_pair();
134             OperandValue::Pair(a, b)
135         } else if llty == llvalty && common::type_is_immediate(ccx, self.ty) {
136             // If the types match, we can use the value directly.
137             OperandValue::Immediate(self.llval)
138         } else {
139             // Otherwise, or if the value is not immediate, we create
140             // a constant LLVM global and cast its address if necessary.
141             let align = type_of::align_of(ccx, self.ty);
142             let ptr = consts::addr_of(ccx, self.llval, align, "const");
143             OperandValue::Ref(consts::ptrcast(ptr, llty.ptr_to()))
144         };
145
146         OperandRef {
147             val: val,
148             ty: self.ty
149         }
150     }
151 }
152
153 impl<'tcx> fmt::Debug for Const<'tcx> {
154     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155         write!(f, "Const({:?}: {:?})", Value(self.llval), self.ty)
156     }
157 }
158
159 #[derive(Copy, Clone)]
160 enum Base {
161     /// A constant value without an unique address.
162     Value(ValueRef),
163
164     /// String literal base pointer (cast from array).
165     Str(ValueRef),
166
167     /// The address of a static.
168     Static(ValueRef)
169 }
170
171 /// An lvalue as seen from a constant.
172 #[derive(Copy, Clone)]
173 struct ConstLvalue<'tcx> {
174     base: Base,
175     llextra: ValueRef,
176     ty: Ty<'tcx>
177 }
178
179 impl<'tcx> ConstLvalue<'tcx> {
180     fn to_const(&self, span: Span) -> Const<'tcx> {
181         match self.base {
182             Base::Value(val) => Const::new(val, self.ty),
183             Base::Str(ptr) => {
184                 span_bug!(span, "loading from `str` ({:?}) in constant",
185                           Value(ptr))
186             }
187             Base::Static(val) => {
188                 span_bug!(span, "loading from `static` ({:?}) in constant",
189                           Value(val))
190             }
191         }
192     }
193
194     pub fn len<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
195         match self.ty.sty {
196             ty::TyArray(_, n) => C_uint(ccx, n),
197             ty::TySlice(_) | ty::TyStr => {
198                 assert!(self.llextra != ptr::null_mut());
199                 self.llextra
200             }
201             _ => bug!("unexpected type `{}` in ConstLvalue::len", self.ty)
202         }
203     }
204 }
205
206 /// Machinery for translating a constant's MIR to LLVM values.
207 /// FIXME(eddyb) use miri and lower its allocations to LLVM.
208 struct MirConstContext<'a, 'tcx: 'a> {
209     ccx: &'a CrateContext<'a, 'tcx>,
210     mir: &'a mir::Mir<'tcx>,
211
212     /// Type parameters for const fn and associated constants.
213     substs: &'tcx Substs<'tcx>,
214
215     /// Values of locals in a constant or const fn.
216     locals: IndexVec<mir::Local, Option<Const<'tcx>>>
217 }
218
219
220 impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
221     fn new(ccx: &'a CrateContext<'a, 'tcx>,
222            mir: &'a mir::Mir<'tcx>,
223            substs: &'tcx Substs<'tcx>,
224            args: IndexVec<mir::Local, Const<'tcx>>)
225            -> MirConstContext<'a, 'tcx> {
226         let mut context = MirConstContext {
227             ccx: ccx,
228             mir: mir,
229             substs: substs,
230             locals: (0..mir.local_decls.len()).map(|_| None).collect(),
231         };
232         for (i, arg) in args.into_iter().enumerate() {
233             // Locals after local 0 are the function arguments
234             let index = mir::Local::new(i + 1);
235             context.locals[index] = Some(arg);
236         }
237         context
238     }
239
240     fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
241                  instance: Instance<'tcx>,
242                  args: IndexVec<mir::Local, Const<'tcx>>)
243                  -> Result<Const<'tcx>, ConstEvalErr> {
244         let instance = instance.resolve_const(ccx.shared());
245         let mir = ccx.tcx().item_mir(instance.def);
246         MirConstContext::new(ccx, &mir, instance.substs, args).trans()
247     }
248
249     fn monomorphize<T>(&self, value: &T) -> T
250         where T: TransNormalize<'tcx>
251     {
252         monomorphize::apply_param_substs(self.ccx.shared(),
253                                          self.substs,
254                                          value)
255     }
256
257     fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> {
258         let tcx = self.ccx.tcx();
259         let mut bb = mir::START_BLOCK;
260
261         // Make sure to evaluate all statemenets to
262         // report as many errors as we possibly can.
263         let mut failure = Ok(());
264
265         loop {
266             let data = &self.mir[bb];
267             for statement in &data.statements {
268                 let span = statement.source_info.span;
269                 match statement.kind {
270                     mir::StatementKind::Assign(ref dest, ref rvalue) => {
271                         let ty = dest.ty(self.mir, tcx);
272                         let ty = self.monomorphize(&ty).to_ty(tcx);
273                         match self.const_rvalue(rvalue, ty, span) {
274                             Ok(value) => self.store(dest, value, span),
275                             Err(err) => if failure.is_ok() { failure = Err(err); }
276                         }
277                     }
278                     mir::StatementKind::StorageLive(_) |
279                     mir::StatementKind::StorageDead(_) |
280                     mir::StatementKind::Nop => {}
281                     mir::StatementKind::SetDiscriminant{ .. } => {
282                         span_bug!(span, "SetDiscriminant should not appear in constants?");
283                     }
284                 }
285             }
286
287             let terminator = data.terminator();
288             let span = terminator.source_info.span;
289             bb = match terminator.kind {
290                 mir::TerminatorKind::Drop { target, .. } | // No dropping.
291                 mir::TerminatorKind::Goto { target } => target,
292                 mir::TerminatorKind::Return => {
293                     failure?;
294                     return Ok(self.locals[mir::RETURN_POINTER].unwrap_or_else(|| {
295                         span_bug!(span, "no returned value in constant");
296                     }));
297                 }
298
299                 mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, .. } => {
300                     let cond = self.const_operand(cond, span)?;
301                     let cond_bool = common::const_to_uint(cond.llval) != 0;
302                     if cond_bool != expected {
303                         let err = match *msg {
304                             mir::AssertMessage::BoundsCheck { ref len, ref index } => {
305                                 let len = self.const_operand(len, span)?;
306                                 let index = self.const_operand(index, span)?;
307                                 ErrKind::IndexOutOfBounds {
308                                     len: common::const_to_uint(len.llval),
309                                     index: common::const_to_uint(index.llval)
310                                 }
311                             }
312                             mir::AssertMessage::Math(ref err) => {
313                                 ErrKind::Math(err.clone())
314                             }
315                         };
316
317                         let err = ConstEvalErr{ span: span, kind: err };
318                         report_const_eval_err(tcx, &err, span, "expression").emit();
319                         failure = Err(err);
320                     }
321                     target
322                 }
323
324                 mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
325                     let fn_ty = func.ty(self.mir, tcx);
326                     let fn_ty = self.monomorphize(&fn_ty);
327                     let instance = match fn_ty.sty {
328                         ty::TyFnDef(def_id, substs, _) => {
329                             Instance::new(def_id, substs)
330                         }
331                         _ => span_bug!(span, "calling {:?} (of type {}) in constant",
332                                        func, fn_ty)
333                     };
334
335                     let mut const_args = IndexVec::with_capacity(args.len());
336                     for arg in args {
337                         match self.const_operand(arg, span) {
338                             Ok(arg) => { const_args.push(arg); },
339                             Err(err) => if failure.is_ok() { failure = Err(err); }
340                         }
341                     }
342                     if let Some((ref dest, target)) = *destination {
343                         match MirConstContext::trans_def(self.ccx, instance, const_args) {
344                             Ok(value) => self.store(dest, value, span),
345                             Err(err) => if failure.is_ok() { failure = Err(err); }
346                         }
347                         target
348                     } else {
349                         span_bug!(span, "diverging {:?} in constant", terminator.kind);
350                     }
351                 }
352                 _ => span_bug!(span, "{:?} in constant", terminator.kind)
353             };
354         }
355     }
356
357     fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) {
358         if let mir::Lvalue::Local(index) = *dest {
359             self.locals[index] = Some(value);
360         } else {
361             span_bug!(span, "assignment to {:?} in constant", dest);
362         }
363     }
364
365     fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
366                     -> Result<ConstLvalue<'tcx>, ConstEvalErr> {
367         let tcx = self.ccx.tcx();
368
369         if let mir::Lvalue::Local(index) = *lvalue {
370             return Ok(self.locals[index].unwrap_or_else(|| {
371                 span_bug!(span, "{:?} not initialized", lvalue)
372             }).as_lvalue());
373         }
374
375         let lvalue = match *lvalue {
376             mir::Lvalue::Local(_)  => bug!(), // handled above
377             mir::Lvalue::Static(def_id) => {
378                 ConstLvalue {
379                     base: Base::Static(consts::get_static(self.ccx, def_id)),
380                     llextra: ptr::null_mut(),
381                     ty: lvalue.ty(self.mir, tcx).to_ty(tcx)
382                 }
383             }
384             mir::Lvalue::Projection(ref projection) => {
385                 let tr_base = self.const_lvalue(&projection.base, span)?;
386                 let projected_ty = LvalueTy::Ty { ty: tr_base.ty }
387                     .projection_ty(tcx, &projection.elem);
388                 let base = tr_base.to_const(span);
389                 let projected_ty = self.monomorphize(&projected_ty).to_ty(tcx);
390                 let is_sized = self.ccx.shared().type_is_sized(projected_ty);
391
392                 let (projected, llextra) = match projection.elem {
393                     mir::ProjectionElem::Deref => {
394                         let (base, extra) = if is_sized {
395                             (base.llval, ptr::null_mut())
396                         } else {
397                             base.get_fat_ptr()
398                         };
399                         if self.ccx.statics().borrow().contains_key(&base) {
400                             (Base::Static(base), extra)
401                         } else if let ty::TyStr = projected_ty.sty {
402                             (Base::Str(base), extra)
403                         } else {
404                             let v = base;
405                             let v = self.ccx.const_unsized().borrow().get(&v).map_or(v, |&v| v);
406                             let mut val = unsafe { llvm::LLVMGetInitializer(v) };
407                             if val.is_null() {
408                                 span_bug!(span, "dereference of non-constant pointer `{:?}`",
409                                           Value(base));
410                             }
411                             if projected_ty.is_bool() {
412                                 unsafe {
413                                     val = llvm::LLVMConstTrunc(val, Type::i1(self.ccx).to_ref());
414                                 }
415                             }
416                             (Base::Value(val), extra)
417                         }
418                     }
419                     mir::ProjectionElem::Field(ref field, _) => {
420                         let llprojected = adt::const_get_field(self.ccx, tr_base.ty, base.llval,
421                                                                Disr(0), field.index());
422                         let llextra = if is_sized {
423                             ptr::null_mut()
424                         } else {
425                             tr_base.llextra
426                         };
427                         (Base::Value(llprojected), llextra)
428                     }
429                     mir::ProjectionElem::Index(ref index) => {
430                         let llindex = self.const_operand(index, span)?.llval;
431
432                         let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) {
433                             iv
434                         } else {
435                             span_bug!(span, "index is not an integer-constant expression")
436                         };
437
438                         // Produce an undef instead of a LLVM assertion on OOB.
439                         let len = common::const_to_uint(tr_base.len(self.ccx));
440                         let llelem = if iv < len as u128 {
441                             const_get_elt(base.llval, &[iv as u32])
442                         } else {
443                             C_undef(type_of::type_of(self.ccx, projected_ty))
444                         };
445
446                         (Base::Value(llelem), ptr::null_mut())
447                     }
448                     _ => span_bug!(span, "{:?} in constant", projection.elem)
449                 };
450                 ConstLvalue {
451                     base: projected,
452                     llextra: llextra,
453                     ty: projected_ty
454                 }
455             }
456         };
457         Ok(lvalue)
458     }
459
460     fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
461                      -> Result<Const<'tcx>, ConstEvalErr> {
462         debug!("const_operand({:?} @ {:?})", operand, span);
463         let result = match *operand {
464             mir::Operand::Consume(ref lvalue) => {
465                 Ok(self.const_lvalue(lvalue, span)?.to_const(span))
466             }
467
468             mir::Operand::Constant(ref constant) => {
469                 let ty = self.monomorphize(&constant.ty);
470                 match constant.literal.clone() {
471                     mir::Literal::Item { def_id, substs } => {
472                         // Shortcut for zero-sized types, including function item
473                         // types, which would not work with MirConstContext.
474                         if common::type_is_zero_size(self.ccx, ty) {
475                             let llty = type_of::type_of(self.ccx, ty);
476                             return Ok(Const::new(C_null(llty), ty));
477                         }
478
479                         let substs = self.monomorphize(&substs);
480                         let instance = Instance::new(def_id, substs);
481                         MirConstContext::trans_def(self.ccx, instance, IndexVec::new())
482                     }
483                     mir::Literal::Promoted { index } => {
484                         let mir = &self.mir.promoted[index];
485                         MirConstContext::new(self.ccx, mir, self.substs, IndexVec::new()).trans()
486                     }
487                     mir::Literal::Value { value } => {
488                         Ok(Const::from_constval(self.ccx, value, ty))
489                     }
490                 }
491             }
492         };
493         debug!("const_operand({:?} @ {:?}) = {:?}", operand, span,
494                result.as_ref().ok());
495         result
496     }
497
498     fn const_array(&self, array_ty: Ty<'tcx>, fields: &[ValueRef])
499                    -> Const<'tcx>
500     {
501         let elem_ty = array_ty.builtin_index().unwrap_or_else(|| {
502             bug!("bad array type {:?}", array_ty)
503         });
504         let llunitty = type_of::type_of(self.ccx, elem_ty);
505         // If the array contains enums, an LLVM array won't work.
506         let val = if fields.iter().all(|&f| val_ty(f) == llunitty) {
507             C_array(llunitty, fields)
508         } else {
509             C_struct(self.ccx, fields, false)
510         };
511         Const::new(val, array_ty)
512     }
513
514     fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
515                     dest_ty: Ty<'tcx>, span: Span)
516                     -> Result<Const<'tcx>, ConstEvalErr> {
517         let tcx = self.ccx.tcx();
518         debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span);
519         let val = match *rvalue {
520             mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?,
521
522             mir::Rvalue::Repeat(ref elem, ref count) => {
523                 let elem = self.const_operand(elem, span)?;
524                 let size = count.value.as_u64(tcx.sess.target.uint_type);
525                 let fields = vec![elem.llval; size as usize];
526                 self.const_array(dest_ty, &fields)
527             }
528
529             mir::Rvalue::Aggregate(ref kind, ref operands) => {
530                 // Make sure to evaluate all operands to
531                 // report as many errors as we possibly can.
532                 let mut fields = Vec::with_capacity(operands.len());
533                 let mut failure = Ok(());
534                 for operand in operands {
535                     match self.const_operand(operand, span) {
536                         Ok(val) => fields.push(val.llval),
537                         Err(err) => if failure.is_ok() { failure = Err(err); }
538                     }
539                 }
540                 failure?;
541
542                 match *kind {
543                     mir::AggregateKind::Array => {
544                         self.const_array(dest_ty, &fields)
545                     }
546                     mir::AggregateKind::Adt(..) |
547                     mir::AggregateKind::Closure(..) |
548                     mir::AggregateKind::Tuple => {
549                         Const::new(trans_const(self.ccx, dest_ty, kind, &fields), dest_ty)
550                     }
551                 }
552             }
553
554             mir::Rvalue::Cast(ref kind, ref source, cast_ty) => {
555                 let operand = self.const_operand(source, span)?;
556                 let cast_ty = self.monomorphize(&cast_ty);
557
558                 let val = match *kind {
559                     mir::CastKind::ReifyFnPointer => {
560                         match operand.ty.sty {
561                             ty::TyFnDef(def_id, substs, _) => {
562                                 Callee::def(self.ccx, def_id, substs)
563                                     .reify(self.ccx)
564                             }
565                             _ => {
566                                 span_bug!(span, "{} cannot be reified to a fn ptr",
567                                           operand.ty)
568                             }
569                         }
570                     }
571                     mir::CastKind::UnsafeFnPointer => {
572                         // this is a no-op at the LLVM level
573                         operand.llval
574                     }
575                     mir::CastKind::Unsize => {
576                         // unsize targets other than to a fat pointer currently
577                         // can't be in constants.
578                         assert!(common::type_is_fat_ptr(self.ccx, cast_ty));
579
580                         let pointee_ty = operand.ty.builtin_deref(true, ty::NoPreference)
581                             .expect("consts: unsizing got non-pointer type").ty;
582                         let (base, old_info) = if !self.ccx.shared().type_is_sized(pointee_ty) {
583                             // Normally, the source is a thin pointer and we are
584                             // adding extra info to make a fat pointer. The exception
585                             // is when we are upcasting an existing object fat pointer
586                             // to use a different vtable. In that case, we want to
587                             // load out the original data pointer so we can repackage
588                             // it.
589                             let (base, extra) = operand.get_fat_ptr();
590                             (base, Some(extra))
591                         } else {
592                             (operand.llval, None)
593                         };
594
595                         let unsized_ty = cast_ty.builtin_deref(true, ty::NoPreference)
596                             .expect("consts: unsizing got non-pointer target type").ty;
597                         let ptr_ty = type_of::in_memory_type_of(self.ccx, unsized_ty).ptr_to();
598                         let base = consts::ptrcast(base, ptr_ty);
599                         let info = base::unsized_info(self.ccx, pointee_ty,
600                                                       unsized_ty, old_info);
601
602                         if old_info.is_none() {
603                             let prev_const = self.ccx.const_unsized().borrow_mut()
604                                                      .insert(base, operand.llval);
605                             assert!(prev_const.is_none() || prev_const == Some(operand.llval));
606                         }
607                         assert_eq!(abi::FAT_PTR_ADDR, 0);
608                         assert_eq!(abi::FAT_PTR_EXTRA, 1);
609                         C_struct(self.ccx, &[base, info], false)
610                     }
611                     mir::CastKind::Misc if common::type_is_immediate(self.ccx, operand.ty) => {
612                         debug_assert!(common::type_is_immediate(self.ccx, cast_ty));
613                         let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast");
614                         let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
615                         let ll_t_out = type_of::immediate_type_of(self.ccx, cast_ty);
616                         let llval = operand.llval;
617                         let signed = if let CastTy::Int(IntTy::CEnum) = r_t_in {
618                             let l = self.ccx.layout_of(operand.ty);
619                             adt::is_discr_signed(&l)
620                         } else {
621                             operand.ty.is_signed()
622                         };
623
624                         unsafe {
625                             match (r_t_in, r_t_out) {
626                                 (CastTy::Int(_), CastTy::Int(_)) => {
627                                     let s = signed as llvm::Bool;
628                                     llvm::LLVMConstIntCast(llval, ll_t_out.to_ref(), s)
629                                 }
630                                 (CastTy::Int(_), CastTy::Float) => {
631                                     if signed {
632                                         llvm::LLVMConstSIToFP(llval, ll_t_out.to_ref())
633                                     } else {
634                                         llvm::LLVMConstUIToFP(llval, ll_t_out.to_ref())
635                                     }
636                                 }
637                                 (CastTy::Float, CastTy::Float) => {
638                                     llvm::LLVMConstFPCast(llval, ll_t_out.to_ref())
639                                 }
640                                 (CastTy::Float, CastTy::Int(IntTy::I)) => {
641                                     llvm::LLVMConstFPToSI(llval, ll_t_out.to_ref())
642                                 }
643                                 (CastTy::Float, CastTy::Int(_)) => {
644                                     llvm::LLVMConstFPToUI(llval, ll_t_out.to_ref())
645                                 }
646                                 (CastTy::Ptr(_), CastTy::Ptr(_)) |
647                                 (CastTy::FnPtr, CastTy::Ptr(_)) |
648                                 (CastTy::RPtr(_), CastTy::Ptr(_)) => {
649                                     consts::ptrcast(llval, ll_t_out)
650                                 }
651                                 (CastTy::Int(_), CastTy::Ptr(_)) => {
652                                     llvm::LLVMConstIntToPtr(llval, ll_t_out.to_ref())
653                                 }
654                                 (CastTy::Ptr(_), CastTy::Int(_)) |
655                                 (CastTy::FnPtr, CastTy::Int(_)) => {
656                                     llvm::LLVMConstPtrToInt(llval, ll_t_out.to_ref())
657                                 }
658                                 _ => bug!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty)
659                             }
660                         }
661                     }
662                     mir::CastKind::Misc => { // Casts from a fat-ptr.
663                         let ll_cast_ty = type_of::immediate_type_of(self.ccx, cast_ty);
664                         let ll_from_ty = type_of::immediate_type_of(self.ccx, operand.ty);
665                         if common::type_is_fat_ptr(self.ccx, operand.ty) {
666                             let (data_ptr, meta_ptr) = operand.get_fat_ptr();
667                             if common::type_is_fat_ptr(self.ccx, cast_ty) {
668                                 let ll_cft = ll_cast_ty.field_types();
669                                 let ll_fft = ll_from_ty.field_types();
670                                 let data_cast = consts::ptrcast(data_ptr, ll_cft[0]);
671                                 assert_eq!(ll_cft[1].kind(), ll_fft[1].kind());
672                                 C_struct(self.ccx, &[data_cast, meta_ptr], false)
673                             } else { // cast to thin-ptr
674                                 // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
675                                 // pointer-cast of that pointer to desired pointer type.
676                                 consts::ptrcast(data_ptr, ll_cast_ty)
677                             }
678                         } else {
679                             bug!("Unexpected non-fat-pointer operand")
680                         }
681                     }
682                 };
683                 Const::new(val, cast_ty)
684             }
685
686             mir::Rvalue::Ref(_, bk, ref lvalue) => {
687                 let tr_lvalue = self.const_lvalue(lvalue, span)?;
688
689                 let ty = tr_lvalue.ty;
690                 let ref_ty = tcx.mk_ref(tcx.mk_region(ty::ReErased),
691                     ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() });
692
693                 let base = match tr_lvalue.base {
694                     Base::Value(llval) => {
695                         // FIXME: may be wrong for &*(&simd_vec as &fmt::Debug)
696                         let align = if self.ccx.shared().type_is_sized(ty) {
697                             type_of::align_of(self.ccx, ty)
698                         } else {
699                             self.ccx.tcx().data_layout.pointer_align.abi() as machine::llalign
700                         };
701                         if bk == mir::BorrowKind::Mut {
702                             consts::addr_of_mut(self.ccx, llval, align, "ref_mut")
703                         } else {
704                             consts::addr_of(self.ccx, llval, align, "ref")
705                         }
706                     }
707                     Base::Str(llval) |
708                     Base::Static(llval) => llval
709                 };
710
711                 let ptr = if self.ccx.shared().type_is_sized(ty) {
712                     base
713                 } else {
714                     C_struct(self.ccx, &[base, tr_lvalue.llextra], false)
715                 };
716                 Const::new(ptr, ref_ty)
717             }
718
719             mir::Rvalue::Len(ref lvalue) => {
720                 let tr_lvalue = self.const_lvalue(lvalue, span)?;
721                 Const::new(tr_lvalue.len(self.ccx), tcx.types.usize)
722             }
723
724             mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
725                 let lhs = self.const_operand(lhs, span)?;
726                 let rhs = self.const_operand(rhs, span)?;
727                 let ty = lhs.ty;
728                 let binop_ty = op.ty(tcx, lhs.ty, rhs.ty);
729                 let (lhs, rhs) = (lhs.llval, rhs.llval);
730                 Const::new(const_scalar_binop(op, lhs, rhs, ty), binop_ty)
731             }
732
733             mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
734                 let lhs = self.const_operand(lhs, span)?;
735                 let rhs = self.const_operand(rhs, span)?;
736                 let ty = lhs.ty;
737                 let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
738                 let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool], false);
739                 let (lhs, rhs) = (lhs.llval, rhs.llval);
740                 assert!(!ty.is_fp());
741
742                 match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) {
743                     Some((llval, of)) => {
744                         let llof = C_bool(self.ccx, of);
745                         Const::new(C_struct(self.ccx, &[llval, llof], false), binop_ty)
746                     }
747                     None => {
748                         span_bug!(span, "{:?} got non-integer operands: {:?} and {:?}",
749                                   rvalue, Value(lhs), Value(rhs));
750                     }
751                 }
752             }
753
754             mir::Rvalue::UnaryOp(op, ref operand) => {
755                 let operand = self.const_operand(operand, span)?;
756                 let lloperand = operand.llval;
757                 let llval = match op {
758                     mir::UnOp::Not => {
759                         unsafe {
760                             llvm::LLVMConstNot(lloperand)
761                         }
762                     }
763                     mir::UnOp::Neg => {
764                         let is_float = operand.ty.is_fp();
765                         unsafe {
766                             if is_float {
767                                 llvm::LLVMConstFNeg(lloperand)
768                             } else {
769                                 llvm::LLVMConstNeg(lloperand)
770                             }
771                         }
772                     }
773                 };
774                 Const::new(llval, operand.ty)
775             }
776
777             _ => span_bug!(span, "{:?} in constant", rvalue)
778         };
779
780         debug!("const_rvalue({:?}: {:?} @ {:?}) = {:?}", rvalue, dest_ty, span, val);
781
782         Ok(val)
783     }
784
785 }
786
787 fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
788     match t.sty {
789         ty::TyInt(int_type) => const_to_opt_u128(value, true)
790             .and_then(|input| ConstInt::new_signed(input as i128, int_type,
791                                                    tcx.sess.target.int_type)),
792         ty::TyUint(uint_type) => const_to_opt_u128(value, false)
793             .and_then(|input| ConstInt::new_unsigned(input, uint_type,
794                                                      tcx.sess.target.uint_type)),
795         _ => None
796
797     }
798 }
799
800 pub fn const_scalar_binop(op: mir::BinOp,
801                           lhs: ValueRef,
802                           rhs: ValueRef,
803                           input_ty: Ty) -> ValueRef {
804     assert!(!input_ty.is_simd());
805     let is_float = input_ty.is_fp();
806     let signed = input_ty.is_signed();
807
808     unsafe {
809         match op {
810             mir::BinOp::Add if is_float => llvm::LLVMConstFAdd(lhs, rhs),
811             mir::BinOp::Add             => llvm::LLVMConstAdd(lhs, rhs),
812
813             mir::BinOp::Sub if is_float => llvm::LLVMConstFSub(lhs, rhs),
814             mir::BinOp::Sub             => llvm::LLVMConstSub(lhs, rhs),
815
816             mir::BinOp::Mul if is_float => llvm::LLVMConstFMul(lhs, rhs),
817             mir::BinOp::Mul             => llvm::LLVMConstMul(lhs, rhs),
818
819             mir::BinOp::Div if is_float => llvm::LLVMConstFDiv(lhs, rhs),
820             mir::BinOp::Div if signed   => llvm::LLVMConstSDiv(lhs, rhs),
821             mir::BinOp::Div             => llvm::LLVMConstUDiv(lhs, rhs),
822
823             mir::BinOp::Rem if is_float => llvm::LLVMConstFRem(lhs, rhs),
824             mir::BinOp::Rem if signed   => llvm::LLVMConstSRem(lhs, rhs),
825             mir::BinOp::Rem             => llvm::LLVMConstURem(lhs, rhs),
826
827             mir::BinOp::BitXor => llvm::LLVMConstXor(lhs, rhs),
828             mir::BinOp::BitAnd => llvm::LLVMConstAnd(lhs, rhs),
829             mir::BinOp::BitOr  => llvm::LLVMConstOr(lhs, rhs),
830             mir::BinOp::Shl    => {
831                 let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
832                 llvm::LLVMConstShl(lhs, rhs)
833             }
834             mir::BinOp::Shr    => {
835                 let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
836                 if signed { llvm::LLVMConstAShr(lhs, rhs) }
837                 else      { llvm::LLVMConstLShr(lhs, rhs) }
838             }
839             mir::BinOp::Eq | mir::BinOp::Ne |
840             mir::BinOp::Lt | mir::BinOp::Le |
841             mir::BinOp::Gt | mir::BinOp::Ge => {
842                 if is_float {
843                     let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop());
844                     llvm::LLVMConstFCmp(cmp, lhs, rhs)
845                 } else {
846                     let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(),
847                                                                 signed);
848                     llvm::LLVMConstICmp(cmp, lhs, rhs)
849                 }
850             }
851         }
852     }
853 }
854
855 pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
856                                             op: mir::BinOp,
857                                             lllhs: ValueRef,
858                                             llrhs: ValueRef,
859                                             input_ty: Ty<'tcx>)
860                                             -> Option<(ValueRef, bool)> {
861     if let (Some(lhs), Some(rhs)) = (to_const_int(lllhs, input_ty, tcx),
862                                      to_const_int(llrhs, input_ty, tcx)) {
863         let result = match op {
864             mir::BinOp::Add => lhs + rhs,
865             mir::BinOp::Sub => lhs - rhs,
866             mir::BinOp::Mul => lhs * rhs,
867             mir::BinOp::Shl => lhs << rhs,
868             mir::BinOp::Shr => lhs >> rhs,
869             _ => {
870                 bug!("Operator `{:?}` is not a checkable operator", op)
871             }
872         };
873
874         let of = match result {
875             Ok(_) => false,
876             Err(ConstMathErr::Overflow(_)) |
877             Err(ConstMathErr::ShiftNegative) => true,
878             Err(err) => {
879                 bug!("Operator `{:?}` on `{:?}` and `{:?}` errored: {}",
880                      op, lhs, rhs, err.description());
881             }
882         };
883
884         Some((const_scalar_binop(op, lllhs, llrhs, input_ty), of))
885     } else {
886         None
887     }
888 }
889
890 impl<'a, 'tcx> MirContext<'a, 'tcx> {
891     pub fn trans_constant(&mut self,
892                           bcx: &Builder<'a, 'tcx>,
893                           constant: &mir::Constant<'tcx>)
894                           -> Const<'tcx>
895     {
896         debug!("trans_constant({:?})", constant);
897         let ty = self.monomorphize(&constant.ty);
898         let result = match constant.literal.clone() {
899             mir::Literal::Item { def_id, substs } => {
900                 // Shortcut for zero-sized types, including function item
901                 // types, which would not work with MirConstContext.
902                 if common::type_is_zero_size(bcx.ccx, ty) {
903                     let llty = type_of::type_of(bcx.ccx, ty);
904                     return Const::new(C_null(llty), ty);
905                 }
906
907                 let substs = self.monomorphize(&substs);
908                 let instance = Instance::new(def_id, substs);
909                 MirConstContext::trans_def(bcx.ccx, instance, IndexVec::new())
910             }
911             mir::Literal::Promoted { index } => {
912                 let mir = &self.mir.promoted[index];
913                 MirConstContext::new(bcx.ccx, mir, self.param_substs, IndexVec::new()).trans()
914             }
915             mir::Literal::Value { value } => {
916                 Ok(Const::from_constval(bcx.ccx, value, ty))
917             }
918         };
919
920         let result = result.unwrap_or_else(|_| {
921             // We've errored, so we don't have to produce working code.
922             let llty = type_of::type_of(bcx.ccx, ty);
923             Const::new(C_undef(llty), ty)
924         });
925
926         debug!("trans_constant({:?}) = {:?}", constant, result);
927         result
928     }
929 }
930
931
932 pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
933                                 -> Result<ValueRef, ConstEvalErr> {
934     let instance = Instance::mono(ccx.shared(), def_id);
935     MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)
936 }
937
938 /// Construct a constant value, suitable for initializing a
939 /// GlobalVariable, given a case and constant values for its fields.
940 /// Note that this may have a different LLVM type (and different
941 /// alignment!) from the representation's `type_of`, so it needs a
942 /// pointer cast before use.
943 ///
944 /// The LLVM type system does not directly support unions, and only
945 /// pointers can be bitcast, so a constant (and, by extension, the
946 /// GlobalVariable initialized by it) will have a type that can vary
947 /// depending on which case of an enum it is.
948 ///
949 /// To understand the alignment situation, consider `enum E { V64(u64),
950 /// V32(u32, u32) }` on Windows.  The type has 8-byte alignment to
951 /// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
952 /// i32, i32}`, which is 4-byte aligned.
953 ///
954 /// Currently the returned value has the same size as the type, but
955 /// this could be changed in the future to avoid allocating unnecessary
956 /// space after values of shorter-than-maximum cases.
957 fn trans_const<'a, 'tcx>(
958     ccx: &CrateContext<'a, 'tcx>,
959     t: Ty<'tcx>,
960     kind: &mir::AggregateKind,
961     vals: &[ValueRef]
962 ) -> ValueRef {
963     let l = ccx.layout_of(t);
964     let dl = &ccx.tcx().data_layout;
965     let variant_index = match *kind {
966         mir::AggregateKind::Adt(_, index, _, _) => index,
967         _ => 0,
968     };
969     match *l {
970         layout::CEnum { discr: d, min, max, .. } => {
971             let discr = match *kind {
972                 mir::AggregateKind::Adt(adt_def, _, _, _) => {
973                     Disr::from(adt_def.variants[variant_index].disr_val)
974                 },
975                 _ => Disr(0),
976             };
977             assert_eq!(vals.len(), 0);
978             adt::assert_discr_in_range(Disr(min), Disr(max), discr);
979             C_integral(Type::from_integer(ccx, d), discr.0, true)
980         }
981         layout::General { discr: d, ref variants, .. } => {
982             let variant = &variants[variant_index];
983             let lldiscr = C_integral(Type::from_integer(ccx, d), variant_index as u64, true);
984             let mut vals_with_discr = vec![lldiscr];
985             vals_with_discr.extend_from_slice(vals);
986             let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
987             let needed_padding = l.size(dl).bytes() - variant.stride().bytes();
988             if needed_padding > 0 {
989                 contents.push(padding(ccx, needed_padding));
990             }
991             C_struct(ccx, &contents[..], false)
992         }
993         layout::UntaggedUnion { ref variants, .. }=> {
994             assert_eq!(variant_index, 0);
995             let contents = build_const_union(ccx, variants, vals[0]);
996             C_struct(ccx, &contents, variants.packed)
997         }
998         layout::Univariant { ref variant, .. } => {
999             assert_eq!(variant_index, 0);
1000             let contents = build_const_struct(ccx, &variant, vals);
1001             C_struct(ccx, &contents[..], variant.packed)
1002         }
1003         layout::Vector { .. } => {
1004             C_vector(vals)
1005         }
1006         layout::RawNullablePointer { nndiscr, .. } => {
1007             let nnty = adt::compute_fields(ccx, t, nndiscr as usize, false)[0];
1008             if variant_index as u64 == nndiscr {
1009                 assert_eq!(vals.len(), 1);
1010                 vals[0]
1011             } else {
1012                 C_null(type_of::sizing_type_of(ccx, nnty))
1013             }
1014         }
1015         layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
1016             if variant_index as u64 == nndiscr {
1017                 C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false)
1018             } else {
1019                 let fields = adt::compute_fields(ccx, t, nndiscr as usize, false);
1020                 let vals = fields.iter().map(|&ty| {
1021                     // Always use null even if it's not the `discrfield`th
1022                     // field; see #8506.
1023                     C_null(type_of::sizing_type_of(ccx, ty))
1024                 }).collect::<Vec<ValueRef>>();
1025                 C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false)
1026             }
1027         }
1028         _ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l)
1029     }
1030 }
1031
1032 /// Building structs is a little complicated, because we might need to
1033 /// insert padding if a field's value is less aligned than its type.
1034 ///
1035 /// Continuing the example from `trans_const`, a value of type `(u32,
1036 /// E)` should have the `E` at offset 8, but if that field's
1037 /// initializer is 4-byte aligned then simply translating the tuple as
1038 /// a two-element struct will locate it at offset 4, and accesses to it
1039 /// will read the wrong memory.
1040 fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1041                                 st: &layout::Struct,
1042                                 vals: &[ValueRef])
1043                                 -> Vec<ValueRef> {
1044     assert_eq!(vals.len(), st.offsets.len());
1045
1046     if vals.len() == 0 {
1047         return Vec::new();
1048     }
1049
1050     // offset of current value
1051     let mut offset = 0;
1052     let mut cfields = Vec::new();
1053     cfields.reserve(st.offsets.len()*2);
1054
1055     let parts = st.field_index_by_increasing_offset().map(|i| {
1056         (&vals[i], st.offsets[i].bytes())
1057     });
1058     for (&val, target_offset) in parts {
1059         if offset < target_offset {
1060             cfields.push(padding(ccx, target_offset - offset));
1061             offset = target_offset;
1062         }
1063         assert!(!is_undef(val));
1064         cfields.push(val);
1065         offset += machine::llsize_of_alloc(ccx, val_ty(val));
1066     }
1067
1068     if offset < st.stride().bytes() {
1069         cfields.push(padding(ccx, st.stride().bytes() - offset));
1070     }
1071
1072     cfields
1073 }
1074
1075 fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1076                                un: &layout::Union,
1077                                field_val: ValueRef)
1078                                -> Vec<ValueRef> {
1079     let mut cfields = vec![field_val];
1080
1081     let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
1082     let size = un.stride().bytes();
1083     if offset != size {
1084         cfields.push(padding(ccx, size - offset));
1085     }
1086
1087     cfields
1088 }
1089
1090 fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
1091     C_undef(Type::array(&Type::i8(ccx), size))
1092 }