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