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