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