]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/mir/constant.rs
Auto merge of #35856 - phimuemue:master, r=brson
[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, ConstIsize, ConstUsize, ConstMathErr};
17 use rustc::hir::def_id::DefId;
18 use rustc::infer::TransNormalize;
19 use rustc::mir::repr as mir;
20 use rustc::mir::tcx::LvalueTy;
21 use rustc::traits;
22 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
23 use rustc::ty::cast::{CastTy, IntTy};
24 use rustc::ty::subst::Substs;
25 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
26 use {abi, adt, base, Disr};
27 use callee::Callee;
28 use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty};
29 use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral};
30 use common::{C_null, C_struct, C_str_slice, C_undef, C_uint};
31 use common::{const_to_opt_int, const_to_opt_uint};
32 use consts;
33 use monomorphize::{self, Instance};
34 use type_of;
35 use type_::Type;
36 use value::Value;
37
38 use syntax::ast;
39 use syntax_pos::{Span, DUMMY_SP};
40
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(Isize(v)) => {
79                 let i = v.as_i64(ccx.tcx().sess.target.int_type);
80                 C_integral(Type::int(ccx), i as u64, true)
81             },
82             ConstVal::Integral(U8(v)) => C_integral(Type::i8(ccx), v as u64, false),
83             ConstVal::Integral(U16(v)) => C_integral(Type::i16(ccx), v as u64, false),
84             ConstVal::Integral(U32(v)) => C_integral(Type::i32(ccx), v as u64, false),
85             ConstVal::Integral(U64(v)) => C_integral(Type::i64(ccx), v, false),
86             ConstVal::Integral(Usize(v)) => {
87                 let u = v.as_u64(ccx.tcx().sess.target.uint_type);
88                 C_integral(Type::int(ccx), u, false)
89             },
90             ConstVal::Integral(Infer(_)) |
91             ConstVal::Integral(InferSigned(_)) => bug!("MIR must not use `{:?}`", cv),
92             ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
93             ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
94             ConstVal::Struct(_) | ConstVal::Tuple(_) |
95             ConstVal::Array(..) | ConstVal::Repeat(..) |
96             ConstVal::Function(_) => {
97                 bug!("MIR must not use `{:?}` (which refers to a local ID)", cv)
98             }
99             ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
100             ConstVal::Dummy => bug!(),
101         };
102
103         assert!(!ty.has_erasable_regions());
104
105         Const::new(val, ty)
106     }
107
108     fn get_pair(&self) -> (ValueRef, ValueRef) {
109         (const_get_elt(self.llval, &[0]),
110          const_get_elt(self.llval, &[1]))
111     }
112
113     fn get_fat_ptr(&self) -> (ValueRef, ValueRef) {
114         assert_eq!(abi::FAT_PTR_ADDR, 0);
115         assert_eq!(abi::FAT_PTR_EXTRA, 1);
116         self.get_pair()
117     }
118
119     fn as_lvalue(&self) -> ConstLvalue<'tcx> {
120         ConstLvalue {
121             base: Base::Value(self.llval),
122             llextra: ptr::null_mut(),
123             ty: self.ty
124         }
125     }
126
127     pub fn to_operand<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> {
128         let llty = type_of::immediate_type_of(ccx, self.ty);
129         let llvalty = val_ty(self.llval);
130
131         let val = if llty == llvalty && common::type_is_imm_pair(ccx, self.ty) {
132             let (a, b) = self.get_pair();
133             OperandValue::Pair(a, b)
134         } else if llty == llvalty && common::type_is_immediate(ccx, self.ty) {
135             // If the types match, we can use the value directly.
136             OperandValue::Immediate(self.llval)
137         } else {
138             // Otherwise, or if the value is not immediate, we create
139             // a constant LLVM global and cast its address if necessary.
140             let align = type_of::align_of(ccx, self.ty);
141             let ptr = consts::addr_of(ccx, self.llval, align, "const");
142             OperandValue::Ref(consts::ptrcast(ptr, llty.ptr_to()))
143         };
144
145         OperandRef {
146             val: val,
147             ty: self.ty
148         }
149     }
150 }
151
152 #[derive(Copy, Clone)]
153 enum Base {
154     /// A constant value without an unique address.
155     Value(ValueRef),
156
157     /// String literal base pointer (cast from array).
158     Str(ValueRef),
159
160     /// The address of a static.
161     Static(ValueRef)
162 }
163
164 /// An lvalue as seen from a constant.
165 #[derive(Copy, Clone)]
166 struct ConstLvalue<'tcx> {
167     base: Base,
168     llextra: ValueRef,
169     ty: Ty<'tcx>
170 }
171
172 impl<'tcx> ConstLvalue<'tcx> {
173     fn to_const(&self, span: Span) -> Const<'tcx> {
174         match self.base {
175             Base::Value(val) => Const::new(val, self.ty),
176             Base::Str(ptr) => {
177                 span_bug!(span, "loading from `str` ({:?}) in constant",
178                           Value(ptr))
179             }
180             Base::Static(val) => {
181                 span_bug!(span, "loading from `static` ({:?}) in constant",
182                           Value(val))
183             }
184         }
185     }
186
187     pub fn len<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
188         match self.ty.sty {
189             ty::TyArray(_, n) => C_uint(ccx, n),
190             ty::TySlice(_) | ty::TyStr => {
191                 assert!(self.llextra != ptr::null_mut());
192                 self.llextra
193             }
194             _ => bug!("unexpected type `{}` in ConstLvalue::len", self.ty)
195         }
196     }
197 }
198
199 /// Machinery for translating a constant's MIR to LLVM values.
200 /// FIXME(eddyb) use miri and lower its allocations to LLVM.
201 struct MirConstContext<'a, 'tcx: 'a> {
202     ccx: &'a CrateContext<'a, 'tcx>,
203     mir: &'a mir::Mir<'tcx>,
204
205     /// Type parameters for const fn and associated constants.
206     substs: &'tcx Substs<'tcx>,
207
208     /// Values of locals in a constant or const fn.
209     locals: IndexVec<mir::Local, Option<Const<'tcx>>>
210 }
211
212
213 impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
214     fn new(ccx: &'a CrateContext<'a, 'tcx>,
215            mir: &'a mir::Mir<'tcx>,
216            substs: &'tcx Substs<'tcx>,
217            args: IndexVec<mir::Arg, Const<'tcx>>)
218            -> MirConstContext<'a, 'tcx> {
219         let mut context = MirConstContext {
220             ccx: ccx,
221             mir: mir,
222             substs: substs,
223             locals: (0..mir.count_locals()).map(|_| None).collect(),
224         };
225         for (i, arg) in args.into_iter().enumerate() {
226             let index = mir.local_index(&mir::Lvalue::Arg(mir::Arg::new(i))).unwrap();
227             context.locals[index] = Some(arg);
228         }
229         context
230     }
231
232     fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
233                  mut instance: Instance<'tcx>,
234                  args: IndexVec<mir::Arg, Const<'tcx>>)
235                  -> Result<Const<'tcx>, ConstEvalErr> {
236         // Try to resolve associated constants.
237         if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) {
238             let trait_ref = ty::TraitRef::new(trait_id, instance.substs);
239             let trait_ref = ty::Binder(trait_ref);
240             let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref);
241             if let traits::VtableImpl(vtable_impl) = vtable {
242                 let name = ccx.tcx().item_name(instance.def);
243                 for ac in ccx.tcx().associated_consts(vtable_impl.impl_def_id) {
244                     if ac.name == name {
245                         instance = Instance::new(ac.def_id, vtable_impl.substs);
246                         break;
247                     }
248                 }
249             }
250         }
251
252         let mir = ccx.get_mir(instance.def).unwrap_or_else(|| {
253             bug!("missing constant MIR for {}", instance)
254         });
255         MirConstContext::new(ccx, &mir, instance.substs, args).trans()
256     }
257
258     fn monomorphize<T>(&self, value: &T) -> T
259         where T: TransNormalize<'tcx>
260     {
261         monomorphize::apply_param_substs(self.ccx.shared(),
262                                          self.substs,
263                                          value)
264     }
265
266     fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> {
267         let tcx = self.ccx.tcx();
268         let mut bb = mir::START_BLOCK;
269
270         // Make sure to evaluate all statemenets to
271         // report as many errors as we possibly can.
272         let mut failure = Ok(());
273
274         loop {
275             let data = &self.mir[bb];
276             for statement in &data.statements {
277                 let span = statement.source_info.span;
278                 match statement.kind {
279                     mir::StatementKind::Assign(ref dest, ref rvalue) => {
280                         let ty = dest.ty(self.mir, tcx);
281                         let ty = self.monomorphize(&ty).to_ty(tcx);
282                         match self.const_rvalue(rvalue, ty, span) {
283                             Ok(value) => self.store(dest, value, span),
284                             Err(err) => if failure.is_ok() { failure = Err(err); }
285                         }
286                     }
287                     mir::StatementKind::StorageLive(_) |
288                     mir::StatementKind::StorageDead(_) => {}
289                     mir::StatementKind::SetDiscriminant{ .. } => {
290                         span_bug!(span, "SetDiscriminant should not appear in constants?");
291                     }
292                 }
293             }
294
295             let terminator = data.terminator();
296             let span = terminator.source_info.span;
297             bb = match terminator.kind {
298                 mir::TerminatorKind::Drop { target, .. } | // No dropping.
299                 mir::TerminatorKind::Goto { target } => target,
300                 mir::TerminatorKind::Return => {
301                     failure?;
302                     let index = self.mir.local_index(&mir::Lvalue::ReturnPointer).unwrap();
303                     return Ok(self.locals[index].unwrap_or_else(|| {
304                         span_bug!(span, "no returned value in constant");
305                     }));
306                 }
307
308                 mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, .. } => {
309                     let cond = self.const_operand(cond, span)?;
310                     let cond_bool = common::const_to_uint(cond.llval) != 0;
311                     if cond_bool != expected {
312                         let err = match *msg {
313                             mir::AssertMessage::BoundsCheck { ref len, ref index } => {
314                                 let len = self.const_operand(len, span)?;
315                                 let index = self.const_operand(index, span)?;
316                                 ErrKind::IndexOutOfBounds {
317                                     len: common::const_to_uint(len.llval),
318                                     index: common::const_to_uint(index.llval)
319                                 }
320                             }
321                             mir::AssertMessage::Math(ref err) => {
322                                 ErrKind::Math(err.clone())
323                             }
324                         };
325
326                         let err = ConstEvalErr{ span: span, kind: err };
327                         report_const_eval_err(tcx, &err, span, "expression").emit();
328                         failure = Err(err);
329                     }
330                     target
331                 }
332
333                 mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
334                     let fn_ty = func.ty(self.mir, tcx);
335                     let fn_ty = self.monomorphize(&fn_ty);
336                     let instance = match fn_ty.sty {
337                         ty::TyFnDef(def_id, substs, _) => {
338                             Instance::new(def_id, substs)
339                         }
340                         _ => span_bug!(span, "calling {:?} (of type {}) in constant",
341                                        func, fn_ty)
342                     };
343
344                     let mut const_args = IndexVec::with_capacity(args.len());
345                     for arg in args {
346                         match self.const_operand(arg, span) {
347                             Ok(arg) => { const_args.push(arg); },
348                             Err(err) => if failure.is_ok() { failure = Err(err); }
349                         }
350                     }
351                     if let Some((ref dest, target)) = *destination {
352                         match MirConstContext::trans_def(self.ccx, instance, const_args) {
353                             Ok(value) => self.store(dest, value, span),
354                             Err(err) => if failure.is_ok() { failure = Err(err); }
355                         }
356                         target
357                     } else {
358                         span_bug!(span, "diverging {:?} in constant", terminator.kind);
359                     }
360                 }
361                 _ => span_bug!(span, "{:?} in constant", terminator.kind)
362             };
363         }
364     }
365
366     fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) {
367         if let Some(index) = self.mir.local_index(dest) {
368             self.locals[index] = Some(value);
369         } else {
370             span_bug!(span, "assignment to {:?} in constant", dest);
371         }
372     }
373
374     fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
375                     -> Result<ConstLvalue<'tcx>, ConstEvalErr> {
376         let tcx = self.ccx.tcx();
377
378         if let Some(index) = self.mir.local_index(lvalue) {
379             return Ok(self.locals[index].unwrap_or_else(|| {
380                 span_bug!(span, "{:?} not initialized", lvalue)
381             }).as_lvalue());
382         }
383
384         let lvalue = match *lvalue {
385             mir::Lvalue::Var(_) |
386             mir::Lvalue::Temp(_) |
387             mir::Lvalue::Arg(_) |
388             mir::Lvalue::ReturnPointer => bug!(), // handled above
389             mir::Lvalue::Static(def_id) => {
390                 ConstLvalue {
391                     base: Base::Static(consts::get_static(self.ccx, def_id)),
392                     llextra: ptr::null_mut(),
393                     ty: lvalue.ty(self.mir, tcx).to_ty(tcx)
394                 }
395             }
396             mir::Lvalue::Projection(ref projection) => {
397                 let tr_base = self.const_lvalue(&projection.base, span)?;
398                 let projected_ty = LvalueTy::Ty { ty: tr_base.ty }
399                     .projection_ty(tcx, &projection.elem);
400                 let base = tr_base.to_const(span);
401                 let projected_ty = self.monomorphize(&projected_ty).to_ty(tcx);
402                 let is_sized = common::type_is_sized(tcx, projected_ty);
403
404                 let (projected, llextra) = match projection.elem {
405                     mir::ProjectionElem::Deref => {
406                         let (base, extra) = if is_sized {
407                             (base.llval, ptr::null_mut())
408                         } else {
409                             base.get_fat_ptr()
410                         };
411                         if self.ccx.statics().borrow().contains_key(&base) {
412                             (Base::Static(base), extra)
413                         } else if let ty::TyStr = projected_ty.sty {
414                             (Base::Str(base), extra)
415                         } else {
416                             let v = base;
417                             let v = self.ccx.const_unsized().borrow().get(&v).map_or(v, |&v| v);
418                             let mut val = unsafe { llvm::LLVMGetInitializer(v) };
419                             if val.is_null() {
420                                 span_bug!(span, "dereference of non-constant pointer `{:?}`",
421                                           Value(base));
422                             }
423                             if projected_ty.is_bool() {
424                                 unsafe {
425                                     val = llvm::LLVMConstTrunc(val, Type::i1(self.ccx).to_ref());
426                                 }
427                             }
428                             (Base::Value(val), extra)
429                         }
430                     }
431                     mir::ProjectionElem::Field(ref field, _) => {
432                         let base_repr = adt::represent_type(self.ccx, tr_base.ty);
433                         let llprojected = adt::const_get_field(&base_repr, base.llval,
434                                                                Disr(0), field.index());
435                         let llextra = if is_sized {
436                             ptr::null_mut()
437                         } else {
438                             tr_base.llextra
439                         };
440                         (Base::Value(llprojected), llextra)
441                     }
442                     mir::ProjectionElem::Index(ref index) => {
443                         let llindex = self.const_operand(index, span)?.llval;
444
445                         let iv = if let Some(iv) = common::const_to_opt_uint(llindex) {
446                             iv
447                         } else {
448                             span_bug!(span, "index is not an integer-constant expression")
449                         };
450
451                         // Produce an undef instead of a LLVM assertion on OOB.
452                         let len = common::const_to_uint(tr_base.len(self.ccx));
453                         let llelem = if iv < len {
454                             const_get_elt(base.llval, &[iv as u32])
455                         } else {
456                             C_undef(type_of::type_of(self.ccx, projected_ty))
457                         };
458
459                         (Base::Value(llelem), ptr::null_mut())
460                     }
461                     _ => span_bug!(span, "{:?} in constant", projection.elem)
462                 };
463                 ConstLvalue {
464                     base: projected,
465                     llextra: llextra,
466                     ty: projected_ty
467                 }
468             }
469         };
470         Ok(lvalue)
471     }
472
473     fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
474                      -> Result<Const<'tcx>, ConstEvalErr> {
475         match *operand {
476             mir::Operand::Consume(ref lvalue) => {
477                 Ok(self.const_lvalue(lvalue, span)?.to_const(span))
478             }
479
480             mir::Operand::Constant(ref constant) => {
481                 let ty = self.monomorphize(&constant.ty);
482                 match constant.literal.clone() {
483                     mir::Literal::Item { def_id, substs } => {
484                         // Shortcut for zero-sized types, including function item
485                         // types, which would not work with MirConstContext.
486                         if common::type_is_zero_size(self.ccx, ty) {
487                             let llty = type_of::type_of(self.ccx, ty);
488                             return Ok(Const::new(C_null(llty), ty));
489                         }
490
491                         let substs = self.monomorphize(&substs);
492                         let instance = Instance::new(def_id, substs);
493                         MirConstContext::trans_def(self.ccx, instance, IndexVec::new())
494                     }
495                     mir::Literal::Promoted { index } => {
496                         let mir = &self.mir.promoted[index];
497                         MirConstContext::new(self.ccx, mir, self.substs, IndexVec::new()).trans()
498                     }
499                     mir::Literal::Value { value } => {
500                         Ok(Const::from_constval(self.ccx, value, ty))
501                     }
502                 }
503             }
504         }
505     }
506
507     fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
508                     dest_ty: Ty<'tcx>, span: Span)
509                     -> Result<Const<'tcx>, ConstEvalErr> {
510         let tcx = self.ccx.tcx();
511         let val = match *rvalue {
512             mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?,
513
514             mir::Rvalue::Repeat(ref elem, ref count) => {
515                 let elem = self.const_operand(elem, span)?;
516                 let size = count.value.as_u64(tcx.sess.target.uint_type);
517                 let fields = vec![elem.llval; size as usize];
518
519                 let llunitty = type_of::type_of(self.ccx, elem.ty);
520                 // If the array contains enums, an LLVM array won't work.
521                 let val = if val_ty(elem.llval) == llunitty {
522                     C_array(llunitty, &fields)
523                 } else {
524                     C_struct(self.ccx, &fields, false)
525                 };
526                 Const::new(val, dest_ty)
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                 // FIXME Shouldn't need to manually trigger closure instantiations.
543                 if let mir::AggregateKind::Closure(def_id, substs) = *kind {
544                     use closure;
545                     closure::trans_closure_body_via_mir(self.ccx,
546                                                         def_id,
547                                                         self.monomorphize(&substs));
548                 }
549
550                 let val = if let mir::AggregateKind::Adt(adt_def, index, _) = *kind {
551                     let repr = adt::represent_type(self.ccx, dest_ty);
552                     let disr = Disr::from(adt_def.variants[index].disr_val);
553                     adt::trans_const(self.ccx, &repr, disr, &fields)
554                 } else if let ty::TyArray(elem_ty, _) = dest_ty.sty {
555                     let llunitty = type_of::type_of(self.ccx, elem_ty);
556                     // If the array contains enums, an LLVM array won't work.
557                     if fields.iter().all(|&f| val_ty(f) == llunitty) {
558                         C_array(llunitty, &fields)
559                     } else {
560                         C_struct(self.ccx, &fields, false)
561                     }
562                 } else {
563                     C_struct(self.ccx, &fields, false)
564                 };
565                 Const::new(val, dest_ty)
566             }
567
568             mir::Rvalue::Cast(ref kind, ref source, cast_ty) => {
569                 let operand = self.const_operand(source, span)?;
570                 let cast_ty = self.monomorphize(&cast_ty);
571
572                 let val = match *kind {
573                     mir::CastKind::ReifyFnPointer => {
574                         match operand.ty.sty {
575                             ty::TyFnDef(def_id, substs, _) => {
576                                 Callee::def(self.ccx, def_id, substs)
577                                     .reify(self.ccx)
578                             }
579                             _ => {
580                                 span_bug!(span, "{} cannot be reified to a fn ptr",
581                                           operand.ty)
582                             }
583                         }
584                     }
585                     mir::CastKind::UnsafeFnPointer => {
586                         // this is a no-op at the LLVM level
587                         operand.llval
588                     }
589                     mir::CastKind::Unsize => {
590                         // unsize targets other than to a fat pointer currently
591                         // can't be in constants.
592                         assert!(common::type_is_fat_ptr(tcx, cast_ty));
593
594                         let pointee_ty = operand.ty.builtin_deref(true, ty::NoPreference)
595                             .expect("consts: unsizing got non-pointer type").ty;
596                         let (base, old_info) = if !common::type_is_sized(tcx, pointee_ty) {
597                             // Normally, the source is a thin pointer and we are
598                             // adding extra info to make a fat pointer. The exception
599                             // is when we are upcasting an existing object fat pointer
600                             // to use a different vtable. In that case, we want to
601                             // load out the original data pointer so we can repackage
602                             // it.
603                             let (base, extra) = operand.get_fat_ptr();
604                             (base, Some(extra))
605                         } else {
606                             (operand.llval, None)
607                         };
608
609                         let unsized_ty = cast_ty.builtin_deref(true, ty::NoPreference)
610                             .expect("consts: unsizing got non-pointer target type").ty;
611                         let ptr_ty = type_of::in_memory_type_of(self.ccx, unsized_ty).ptr_to();
612                         let base = consts::ptrcast(base, ptr_ty);
613                         let info = base::unsized_info(self.ccx, pointee_ty,
614                                                       unsized_ty, old_info);
615
616                         if old_info.is_none() {
617                             let prev_const = self.ccx.const_unsized().borrow_mut()
618                                                      .insert(base, operand.llval);
619                             assert!(prev_const.is_none() || prev_const == Some(operand.llval));
620                         }
621                         assert_eq!(abi::FAT_PTR_ADDR, 0);
622                         assert_eq!(abi::FAT_PTR_EXTRA, 1);
623                         C_struct(self.ccx, &[base, info], false)
624                     }
625                     mir::CastKind::Misc if common::type_is_immediate(self.ccx, operand.ty) => {
626                         debug_assert!(common::type_is_immediate(self.ccx, cast_ty));
627                         let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast");
628                         let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
629                         let ll_t_out = type_of::immediate_type_of(self.ccx, cast_ty);
630                         let llval = operand.llval;
631                         let signed = if let CastTy::Int(IntTy::CEnum) = r_t_in {
632                             let repr = adt::represent_type(self.ccx, operand.ty);
633                             adt::is_discr_signed(&repr)
634                         } else {
635                             operand.ty.is_signed()
636                         };
637
638                         unsafe {
639                             match (r_t_in, r_t_out) {
640                                 (CastTy::Int(_), CastTy::Int(_)) => {
641                                     let s = signed as llvm::Bool;
642                                     llvm::LLVMConstIntCast(llval, ll_t_out.to_ref(), s)
643                                 }
644                                 (CastTy::Int(_), CastTy::Float) => {
645                                     if signed {
646                                         llvm::LLVMConstSIToFP(llval, ll_t_out.to_ref())
647                                     } else {
648                                         llvm::LLVMConstUIToFP(llval, ll_t_out.to_ref())
649                                     }
650                                 }
651                                 (CastTy::Float, CastTy::Float) => {
652                                     llvm::LLVMConstFPCast(llval, ll_t_out.to_ref())
653                                 }
654                                 (CastTy::Float, CastTy::Int(IntTy::I)) => {
655                                     llvm::LLVMConstFPToSI(llval, ll_t_out.to_ref())
656                                 }
657                                 (CastTy::Float, CastTy::Int(_)) => {
658                                     llvm::LLVMConstFPToUI(llval, ll_t_out.to_ref())
659                                 }
660                                 (CastTy::Ptr(_), CastTy::Ptr(_)) |
661                                 (CastTy::FnPtr, CastTy::Ptr(_)) |
662                                 (CastTy::RPtr(_), CastTy::Ptr(_)) => {
663                                     consts::ptrcast(llval, ll_t_out)
664                                 }
665                                 (CastTy::Int(_), CastTy::Ptr(_)) => {
666                                     llvm::LLVMConstIntToPtr(llval, ll_t_out.to_ref())
667                                 }
668                                 (CastTy::Ptr(_), CastTy::Int(_)) |
669                                 (CastTy::FnPtr, CastTy::Int(_)) => {
670                                     llvm::LLVMConstPtrToInt(llval, ll_t_out.to_ref())
671                                 }
672                                 _ => bug!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty)
673                             }
674                         }
675                     }
676                     mir::CastKind::Misc => { // Casts from a fat-ptr.
677                         let ll_cast_ty = type_of::immediate_type_of(self.ccx, cast_ty);
678                         let ll_from_ty = type_of::immediate_type_of(self.ccx, operand.ty);
679                         if common::type_is_fat_ptr(tcx, operand.ty) {
680                             let (data_ptr, meta_ptr) = operand.get_fat_ptr();
681                             if common::type_is_fat_ptr(tcx, cast_ty) {
682                                 let ll_cft = ll_cast_ty.field_types();
683                                 let ll_fft = ll_from_ty.field_types();
684                                 let data_cast = consts::ptrcast(data_ptr, ll_cft[0]);
685                                 assert_eq!(ll_cft[1].kind(), ll_fft[1].kind());
686                                 C_struct(self.ccx, &[data_cast, meta_ptr], false)
687                             } else { // cast to thin-ptr
688                                 // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
689                                 // pointer-cast of that pointer to desired pointer type.
690                                 consts::ptrcast(data_ptr, ll_cast_ty)
691                             }
692                         } else {
693                             bug!("Unexpected non-fat-pointer operand")
694                         }
695                     }
696                 };
697                 Const::new(val, cast_ty)
698             }
699
700             mir::Rvalue::Ref(_, bk, ref lvalue) => {
701                 let tr_lvalue = self.const_lvalue(lvalue, span)?;
702
703                 let ty = tr_lvalue.ty;
704                 let ref_ty = tcx.mk_ref(tcx.mk_region(ty::ReErased),
705                     ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() });
706
707                 let base = match tr_lvalue.base {
708                     Base::Value(llval) => {
709                         let align = type_of::align_of(self.ccx, ty);
710                         if bk == mir::BorrowKind::Mut {
711                             consts::addr_of_mut(self.ccx, llval, align, "ref_mut")
712                         } else {
713                             consts::addr_of(self.ccx, llval, align, "ref")
714                         }
715                     }
716                     Base::Str(llval) |
717                     Base::Static(llval) => llval
718                 };
719
720                 let ptr = if common::type_is_sized(tcx, ty) {
721                     base
722                 } else {
723                     C_struct(self.ccx, &[base, tr_lvalue.llextra], false)
724                 };
725                 Const::new(ptr, ref_ty)
726             }
727
728             mir::Rvalue::Len(ref lvalue) => {
729                 let tr_lvalue = self.const_lvalue(lvalue, span)?;
730                 Const::new(tr_lvalue.len(self.ccx), tcx.types.usize)
731             }
732
733             mir::Rvalue::BinaryOp(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 binop_ty = op.ty(tcx, lhs.ty, rhs.ty);
738                 let (lhs, rhs) = (lhs.llval, rhs.llval);
739                 Const::new(const_scalar_binop(op, lhs, rhs, ty), binop_ty)
740             }
741
742             mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
743                 let lhs = self.const_operand(lhs, span)?;
744                 let rhs = self.const_operand(rhs, span)?;
745                 let ty = lhs.ty;
746                 let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
747                 let binop_ty = tcx.mk_tup(vec![val_ty, tcx.types.bool]);
748                 let (lhs, rhs) = (lhs.llval, rhs.llval);
749                 assert!(!ty.is_fp());
750
751                 match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) {
752                     Some((llval, of)) => {
753                         let llof = C_bool(self.ccx, of);
754                         Const::new(C_struct(self.ccx, &[llval, llof], false), binop_ty)
755                     }
756                     None => {
757                         span_bug!(span, "{:?} got non-integer operands: {:?} and {:?}",
758                                   rvalue, Value(lhs), Value(rhs));
759                     }
760                 }
761             }
762
763             mir::Rvalue::UnaryOp(op, ref operand) => {
764                 let operand = self.const_operand(operand, span)?;
765                 let lloperand = operand.llval;
766                 let llval = match op {
767                     mir::UnOp::Not => {
768                         unsafe {
769                             llvm::LLVMConstNot(lloperand)
770                         }
771                     }
772                     mir::UnOp::Neg => {
773                         let is_float = operand.ty.is_fp();
774                         unsafe {
775                             if is_float {
776                                 llvm::LLVMConstFNeg(lloperand)
777                             } else {
778                                 llvm::LLVMConstNeg(lloperand)
779                             }
780                         }
781                     }
782                 };
783                 Const::new(llval, operand.ty)
784             }
785
786             _ => span_bug!(span, "{:?} in constant", rvalue)
787         };
788
789         Ok(val)
790     }
791
792 }
793
794 fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
795     match t.sty {
796         ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type {
797             ast::IntTy::I8 => {
798                 assert_eq!(input as i8 as i64, input);
799                 Some(ConstInt::I8(input as i8))
800             },
801             ast::IntTy::I16 => {
802                 assert_eq!(input as i16 as i64, input);
803                 Some(ConstInt::I16(input as i16))
804             },
805             ast::IntTy::I32 => {
806                 assert_eq!(input as i32 as i64, input);
807                 Some(ConstInt::I32(input as i32))
808             },
809             ast::IntTy::I64 => {
810                 Some(ConstInt::I64(input))
811             },
812             ast::IntTy::Is => {
813                 ConstIsize::new(input, tcx.sess.target.int_type)
814                     .ok().map(ConstInt::Isize)
815             },
816         }),
817         ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type {
818             ast::UintTy::U8 => {
819                 assert_eq!(input as u8 as u64, input);
820                 Some(ConstInt::U8(input as u8))
821             },
822             ast::UintTy::U16 => {
823                 assert_eq!(input as u16 as u64, input);
824                 Some(ConstInt::U16(input as u16))
825             },
826             ast::UintTy::U32 => {
827                 assert_eq!(input as u32 as u64, input);
828                 Some(ConstInt::U32(input as u32))
829             },
830             ast::UintTy::U64 => {
831                 Some(ConstInt::U64(input))
832             },
833             ast::UintTy::Us => {
834                 ConstUsize::new(input, tcx.sess.target.uint_type)
835                     .ok().map(ConstInt::Usize)
836             },
837         }),
838         _ => None,
839     }
840 }
841
842 pub fn const_scalar_binop(op: mir::BinOp,
843                           lhs: ValueRef,
844                           rhs: ValueRef,
845                           input_ty: Ty) -> ValueRef {
846     assert!(!input_ty.is_simd());
847     let is_float = input_ty.is_fp();
848     let signed = input_ty.is_signed();
849
850     unsafe {
851         match op {
852             mir::BinOp::Add if is_float => llvm::LLVMConstFAdd(lhs, rhs),
853             mir::BinOp::Add             => llvm::LLVMConstAdd(lhs, rhs),
854
855             mir::BinOp::Sub if is_float => llvm::LLVMConstFSub(lhs, rhs),
856             mir::BinOp::Sub             => llvm::LLVMConstSub(lhs, rhs),
857
858             mir::BinOp::Mul if is_float => llvm::LLVMConstFMul(lhs, rhs),
859             mir::BinOp::Mul             => llvm::LLVMConstMul(lhs, rhs),
860
861             mir::BinOp::Div if is_float => llvm::LLVMConstFDiv(lhs, rhs),
862             mir::BinOp::Div if signed   => llvm::LLVMConstSDiv(lhs, rhs),
863             mir::BinOp::Div             => llvm::LLVMConstUDiv(lhs, rhs),
864
865             mir::BinOp::Rem if is_float => llvm::LLVMConstFRem(lhs, rhs),
866             mir::BinOp::Rem if signed   => llvm::LLVMConstSRem(lhs, rhs),
867             mir::BinOp::Rem             => llvm::LLVMConstURem(lhs, rhs),
868
869             mir::BinOp::BitXor => llvm::LLVMConstXor(lhs, rhs),
870             mir::BinOp::BitAnd => llvm::LLVMConstAnd(lhs, rhs),
871             mir::BinOp::BitOr  => llvm::LLVMConstOr(lhs, rhs),
872             mir::BinOp::Shl    => {
873                 let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
874                 llvm::LLVMConstShl(lhs, rhs)
875             }
876             mir::BinOp::Shr    => {
877                 let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
878                 if signed { llvm::LLVMConstAShr(lhs, rhs) }
879                 else      { llvm::LLVMConstLShr(lhs, rhs) }
880             }
881             mir::BinOp::Eq | mir::BinOp::Ne |
882             mir::BinOp::Lt | mir::BinOp::Le |
883             mir::BinOp::Gt | mir::BinOp::Ge => {
884                 if is_float {
885                     let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop());
886                     llvm::LLVMConstFCmp(cmp, lhs, rhs)
887                 } else {
888                     let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(),
889                                                                 signed);
890                     llvm::LLVMConstICmp(cmp, lhs, rhs)
891                 }
892             }
893         }
894     }
895 }
896
897 pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
898                                             op: mir::BinOp,
899                                             lllhs: ValueRef,
900                                             llrhs: ValueRef,
901                                             input_ty: Ty<'tcx>)
902                                             -> Option<(ValueRef, bool)> {
903     if let (Some(lhs), Some(rhs)) = (to_const_int(lllhs, input_ty, tcx),
904                                      to_const_int(llrhs, input_ty, tcx)) {
905         let result = match op {
906             mir::BinOp::Add => lhs + rhs,
907             mir::BinOp::Sub => lhs - rhs,
908             mir::BinOp::Mul => lhs * rhs,
909             mir::BinOp::Shl => lhs << rhs,
910             mir::BinOp::Shr => lhs >> rhs,
911             _ => {
912                 bug!("Operator `{:?}` is not a checkable operator", op)
913             }
914         };
915
916         let of = match result {
917             Ok(_) => false,
918             Err(ConstMathErr::Overflow(_)) |
919             Err(ConstMathErr::ShiftNegative) => true,
920             Err(err) => {
921                 bug!("Operator `{:?}` on `{:?}` and `{:?}` errored: {}",
922                      op, lhs, rhs, err.description());
923             }
924         };
925
926         Some((const_scalar_binop(op, lllhs, llrhs, input_ty), of))
927     } else {
928         None
929     }
930 }
931
932 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
933     pub fn trans_constant(&mut self,
934                           bcx: &BlockAndBuilder<'bcx, 'tcx>,
935                           constant: &mir::Constant<'tcx>)
936                           -> Const<'tcx>
937     {
938         let ty = bcx.monomorphize(&constant.ty);
939         let result = match constant.literal.clone() {
940             mir::Literal::Item { def_id, substs } => {
941                 // Shortcut for zero-sized types, including function item
942                 // types, which would not work with MirConstContext.
943                 if common::type_is_zero_size(bcx.ccx(), ty) {
944                     let llty = type_of::type_of(bcx.ccx(), ty);
945                     return Const::new(C_null(llty), ty);
946                 }
947
948                 let substs = bcx.monomorphize(&substs);
949                 let instance = Instance::new(def_id, substs);
950                 MirConstContext::trans_def(bcx.ccx(), instance, IndexVec::new())
951             }
952             mir::Literal::Promoted { index } => {
953                 let mir = &self.mir.promoted[index];
954                 MirConstContext::new(bcx.ccx(), mir, bcx.fcx().param_substs,
955                                      IndexVec::new()).trans()
956             }
957             mir::Literal::Value { value } => {
958                 Ok(Const::from_constval(bcx.ccx(), value, ty))
959             }
960         };
961
962         result.unwrap_or_else(|_| {
963             // We've errored, so we don't have to produce working code.
964             let llty = type_of::type_of(bcx.ccx(), ty);
965             Const::new(C_undef(llty), ty)
966         })
967     }
968 }
969
970
971 pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
972                                 -> Result<ValueRef, ConstEvalErr> {
973     let instance = Instance::mono(ccx.shared(), def_id);
974     MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)
975 }