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.
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.
11 use llvm::{self, ValueRef};
12 use rustc::middle::const_val::ConstVal;
13 use rustc_const_eval::{ErrKind, ConstEvalErr, report_const_eval_err};
14 use rustc_const_math::ConstInt::*;
15 use rustc_const_math::ConstFloat::*;
16 use rustc_const_math::{ConstInt, ConstMathErr};
17 use rustc::hir::def_id::DefId;
18 use rustc::infer::TransNormalize;
20 use rustc::mir::tcx::LvalueTy;
21 use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable};
22 use rustc::ty::cast::{CastTy, IntTy};
23 use rustc::ty::subst::Substs;
24 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
25 use {abi, adt, base, Disr, machine};
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;
33 use monomorphize::{self, Instance};
43 use super::lvalue::Alignment;
44 use super::operand::{OperandRef, OperandValue};
45 use super::MirContext;
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> {
56 impl<'tcx> Const<'tcx> {
57 pub fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> {
64 /// Translate ConstVal into a LLVM constant value.
65 pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
69 let llty = type_of::type_of(ccx, ty);
71 ConstVal::Float(F32(v)) => C_floating_f64(v as f64, llty),
72 ConstVal::Float(F64(v)) => C_floating_f64(v, llty),
73 ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv),
74 ConstVal::Bool(v) => C_bool(ccx, v),
75 ConstVal::Integral(I8(v)) => C_integral(Type::i8(ccx), v as u64, true),
76 ConstVal::Integral(I16(v)) => C_integral(Type::i16(ccx), v as u64, true),
77 ConstVal::Integral(I32(v)) => C_integral(Type::i32(ccx), v as u64, true),
78 ConstVal::Integral(I64(v)) => C_integral(Type::i64(ccx), v as u64, true),
79 ConstVal::Integral(I128(v)) => C_big_integral(Type::i128(ccx), v as u128),
80 ConstVal::Integral(Isize(v)) => {
81 let i = v.as_i64(ccx.tcx().sess.target.int_type);
82 C_integral(Type::int(ccx), i as u64, true)
84 ConstVal::Integral(U8(v)) => C_integral(Type::i8(ccx), v as u64, false),
85 ConstVal::Integral(U16(v)) => C_integral(Type::i16(ccx), v as u64, false),
86 ConstVal::Integral(U32(v)) => C_integral(Type::i32(ccx), v as u64, false),
87 ConstVal::Integral(U64(v)) => C_integral(Type::i64(ccx), v, false),
88 ConstVal::Integral(U128(v)) => C_big_integral(Type::i128(ccx), v),
89 ConstVal::Integral(Usize(v)) => {
90 let u = v.as_u64(ccx.tcx().sess.target.uint_type);
91 C_integral(Type::int(ccx), u, false)
93 ConstVal::Integral(Infer(_)) |
94 ConstVal::Integral(InferSigned(_)) => bug!("MIR must not use `{:?}`", cv),
95 ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
96 ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
97 ConstVal::Struct(_) | ConstVal::Tuple(_) |
98 ConstVal::Array(..) | ConstVal::Repeat(..) |
99 ConstVal::Function(_) => {
100 bug!("MIR must not use `{:?}` (which refers to a local ID)", cv)
102 ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
105 assert!(!ty.has_erasable_regions());
110 fn get_pair(&self) -> (ValueRef, ValueRef) {
111 (const_get_elt(self.llval, &[0]),
112 const_get_elt(self.llval, &[1]))
115 fn get_fat_ptr(&self) -> (ValueRef, ValueRef) {
116 assert_eq!(abi::FAT_PTR_ADDR, 0);
117 assert_eq!(abi::FAT_PTR_EXTRA, 1);
121 fn as_lvalue(&self) -> ConstLvalue<'tcx> {
123 base: Base::Value(self.llval),
124 llextra: ptr::null_mut(),
129 pub fn to_operand<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> {
130 let llty = type_of::immediate_type_of(ccx, self.ty);
131 let llvalty = val_ty(self.llval);
133 let val = if llty == llvalty && common::type_is_imm_pair(ccx, self.ty) {
134 let (a, b) = self.get_pair();
135 OperandValue::Pair(a, b)
136 } else if llty == llvalty && common::type_is_immediate(ccx, self.ty) {
137 // If the types match, we can use the value directly.
138 OperandValue::Immediate(self.llval)
140 // Otherwise, or if the value is not immediate, we create
141 // a constant LLVM global and cast its address if necessary.
142 let align = type_of::align_of(ccx, self.ty);
143 let ptr = consts::addr_of(ccx, self.llval, align, "const");
144 OperandValue::Ref(consts::ptrcast(ptr, llty.ptr_to()), Alignment::AbiAligned)
154 impl<'tcx> fmt::Debug for Const<'tcx> {
155 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156 write!(f, "Const({:?}: {:?})", Value(self.llval), self.ty)
160 #[derive(Copy, Clone)]
162 /// A constant value without an unique address.
165 /// String literal base pointer (cast from array).
168 /// The address of a static.
172 /// An lvalue as seen from a constant.
173 #[derive(Copy, Clone)]
174 struct ConstLvalue<'tcx> {
180 impl<'tcx> ConstLvalue<'tcx> {
181 fn to_const(&self, span: Span) -> Const<'tcx> {
183 Base::Value(val) => Const::new(val, self.ty),
185 span_bug!(span, "loading from `str` ({:?}) in constant",
188 Base::Static(val) => {
189 span_bug!(span, "loading from `static` ({:?}) in constant",
195 pub fn len<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
197 ty::TyArray(_, n) => C_uint(ccx, n),
198 ty::TySlice(_) | ty::TyStr => {
199 assert!(self.llextra != ptr::null_mut());
202 _ => bug!("unexpected type `{}` in ConstLvalue::len", self.ty)
207 /// Machinery for translating a constant's MIR to LLVM values.
208 /// FIXME(eddyb) use miri and lower its allocations to LLVM.
209 struct MirConstContext<'a, 'tcx: 'a> {
210 ccx: &'a CrateContext<'a, 'tcx>,
211 mir: &'a mir::Mir<'tcx>,
213 /// Type parameters for const fn and associated constants.
214 substs: &'tcx Substs<'tcx>,
216 /// Values of locals in a constant or const fn.
217 locals: IndexVec<mir::Local, Option<Const<'tcx>>>
221 impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
222 fn new(ccx: &'a CrateContext<'a, 'tcx>,
223 mir: &'a mir::Mir<'tcx>,
224 substs: &'tcx Substs<'tcx>,
225 args: IndexVec<mir::Local, Const<'tcx>>)
226 -> MirConstContext<'a, 'tcx> {
227 let mut context = MirConstContext {
231 locals: (0..mir.local_decls.len()).map(|_| None).collect(),
233 for (i, arg) in args.into_iter().enumerate() {
234 // Locals after local 0 are the function arguments
235 let index = mir::Local::new(i + 1);
236 context.locals[index] = Some(arg);
241 fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
242 instance: Instance<'tcx>,
243 args: IndexVec<mir::Local, Const<'tcx>>)
244 -> Result<Const<'tcx>, ConstEvalErr> {
245 let instance = instance.resolve_const(ccx.shared());
246 let mir = ccx.tcx().item_mir(instance.def);
247 MirConstContext::new(ccx, &mir, instance.substs, args).trans()
250 fn monomorphize<T>(&self, value: &T) -> T
251 where T: TransNormalize<'tcx>
253 monomorphize::apply_param_substs(self.ccx.shared(),
258 fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> {
259 let tcx = self.ccx.tcx();
260 let mut bb = mir::START_BLOCK;
262 // Make sure to evaluate all statemenets to
263 // report as many errors as we possibly can.
264 let mut failure = Ok(());
267 let data = &self.mir[bb];
268 for statement in &data.statements {
269 let span = statement.source_info.span;
270 match statement.kind {
271 mir::StatementKind::Assign(ref dest, ref rvalue) => {
272 let ty = dest.ty(self.mir, tcx);
273 let ty = self.monomorphize(&ty).to_ty(tcx);
274 match self.const_rvalue(rvalue, ty, span) {
275 Ok(value) => self.store(dest, value, span),
276 Err(err) => if failure.is_ok() { failure = Err(err); }
279 mir::StatementKind::StorageLive(_) |
280 mir::StatementKind::StorageDead(_) |
281 mir::StatementKind::Nop => {}
282 mir::StatementKind::SetDiscriminant{ .. } => {
283 span_bug!(span, "SetDiscriminant should not appear in constants?");
288 let terminator = data.terminator();
289 let span = terminator.source_info.span;
290 bb = match terminator.kind {
291 mir::TerminatorKind::Drop { target, .. } | // No dropping.
292 mir::TerminatorKind::Goto { target } => target,
293 mir::TerminatorKind::Return => {
295 return Ok(self.locals[mir::RETURN_POINTER].unwrap_or_else(|| {
296 span_bug!(span, "no returned value in constant");
300 mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, .. } => {
301 let cond = self.const_operand(cond, span)?;
302 let cond_bool = common::const_to_uint(cond.llval) != 0;
303 if cond_bool != expected {
304 let err = match *msg {
305 mir::AssertMessage::BoundsCheck { ref len, ref index } => {
306 let len = self.const_operand(len, span)?;
307 let index = self.const_operand(index, span)?;
308 ErrKind::IndexOutOfBounds {
309 len: common::const_to_uint(len.llval),
310 index: common::const_to_uint(index.llval)
313 mir::AssertMessage::Math(ref err) => {
314 ErrKind::Math(err.clone())
318 let err = ConstEvalErr{ span: span, kind: err };
319 report_const_eval_err(tcx, &err, span, "expression").emit();
325 mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
326 let fn_ty = func.ty(self.mir, tcx);
327 let fn_ty = self.monomorphize(&fn_ty);
328 let instance = match fn_ty.sty {
329 ty::TyFnDef(def_id, substs, _) => {
330 Instance::new(def_id, substs)
332 _ => span_bug!(span, "calling {:?} (of type {}) in constant",
336 let mut const_args = IndexVec::with_capacity(args.len());
338 match self.const_operand(arg, span) {
339 Ok(arg) => { const_args.push(arg); },
340 Err(err) => if failure.is_ok() { failure = Err(err); }
343 if let Some((ref dest, target)) = *destination {
344 match MirConstContext::trans_def(self.ccx, instance, const_args) {
345 Ok(value) => self.store(dest, value, span),
346 Err(err) => if failure.is_ok() { failure = Err(err); }
350 span_bug!(span, "diverging {:?} in constant", terminator.kind);
353 _ => span_bug!(span, "{:?} in constant", terminator.kind)
358 fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) {
359 if let mir::Lvalue::Local(index) = *dest {
360 self.locals[index] = Some(value);
362 span_bug!(span, "assignment to {:?} in constant", dest);
366 fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
367 -> Result<ConstLvalue<'tcx>, ConstEvalErr> {
368 let tcx = self.ccx.tcx();
370 if let mir::Lvalue::Local(index) = *lvalue {
371 return Ok(self.locals[index].unwrap_or_else(|| {
372 span_bug!(span, "{:?} not initialized", lvalue)
376 let lvalue = match *lvalue {
377 mir::Lvalue::Local(_) => bug!(), // handled above
378 mir::Lvalue::Static(def_id) => {
380 base: Base::Static(consts::get_static(self.ccx, def_id)),
381 llextra: ptr::null_mut(),
382 ty: lvalue.ty(self.mir, tcx).to_ty(tcx)
385 mir::Lvalue::Projection(ref projection) => {
386 let tr_base = self.const_lvalue(&projection.base, span)?;
387 let projected_ty = LvalueTy::Ty { ty: tr_base.ty }
388 .projection_ty(tcx, &projection.elem);
389 let base = tr_base.to_const(span);
390 let projected_ty = self.monomorphize(&projected_ty).to_ty(tcx);
391 let is_sized = self.ccx.shared().type_is_sized(projected_ty);
393 let (projected, llextra) = match projection.elem {
394 mir::ProjectionElem::Deref => {
395 let (base, extra) = if is_sized {
396 (base.llval, ptr::null_mut())
400 if self.ccx.statics().borrow().contains_key(&base) {
401 (Base::Static(base), extra)
402 } else if let ty::TyStr = projected_ty.sty {
403 (Base::Str(base), extra)
406 let v = self.ccx.const_unsized().borrow().get(&v).map_or(v, |&v| v);
407 let mut val = unsafe { llvm::LLVMGetInitializer(v) };
409 span_bug!(span, "dereference of non-constant pointer `{:?}`",
412 if projected_ty.is_bool() {
414 val = llvm::LLVMConstTrunc(val, Type::i1(self.ccx).to_ref());
417 (Base::Value(val), extra)
420 mir::ProjectionElem::Field(ref field, _) => {
421 let llprojected = adt::const_get_field(self.ccx, tr_base.ty, base.llval,
422 Disr(0), field.index());
423 let llextra = if is_sized {
428 (Base::Value(llprojected), llextra)
430 mir::ProjectionElem::Index(ref index) => {
431 let llindex = self.const_operand(index, span)?.llval;
433 let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) {
436 span_bug!(span, "index is not an integer-constant expression")
439 // Produce an undef instead of a LLVM assertion on OOB.
440 let len = common::const_to_uint(tr_base.len(self.ccx));
441 let llelem = if iv < len as u128 {
442 const_get_elt(base.llval, &[iv as u32])
444 C_undef(type_of::type_of(self.ccx, projected_ty))
447 (Base::Value(llelem), ptr::null_mut())
449 _ => span_bug!(span, "{:?} in constant", projection.elem)
461 fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
462 -> Result<Const<'tcx>, ConstEvalErr> {
463 debug!("const_operand({:?} @ {:?})", operand, span);
464 let result = match *operand {
465 mir::Operand::Consume(ref lvalue) => {
466 Ok(self.const_lvalue(lvalue, span)?.to_const(span))
469 mir::Operand::Constant(ref constant) => {
470 let ty = self.monomorphize(&constant.ty);
471 match constant.literal.clone() {
472 mir::Literal::Item { def_id, substs } => {
473 // Shortcut for zero-sized types, including function item
474 // types, which would not work with MirConstContext.
475 if common::type_is_zero_size(self.ccx, ty) {
476 let llty = type_of::type_of(self.ccx, ty);
477 return Ok(Const::new(C_null(llty), ty));
480 let substs = self.monomorphize(&substs);
481 let instance = Instance::new(def_id, substs);
482 MirConstContext::trans_def(self.ccx, instance, IndexVec::new())
484 mir::Literal::Promoted { index } => {
485 let mir = &self.mir.promoted[index];
486 MirConstContext::new(self.ccx, mir, self.substs, IndexVec::new()).trans()
488 mir::Literal::Value { value } => {
489 Ok(Const::from_constval(self.ccx, value, ty))
494 debug!("const_operand({:?} @ {:?}) = {:?}", operand, span,
495 result.as_ref().ok());
499 fn const_array(&self, array_ty: Ty<'tcx>, fields: &[ValueRef])
502 let elem_ty = array_ty.builtin_index().unwrap_or_else(|| {
503 bug!("bad array type {:?}", array_ty)
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)
510 C_struct(self.ccx, fields, false)
512 Const::new(val, array_ty)
515 fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
516 dest_ty: Ty<'tcx>, span: Span)
517 -> Result<Const<'tcx>, ConstEvalErr> {
518 let tcx = self.ccx.tcx();
519 debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span);
520 let val = match *rvalue {
521 mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?,
523 mir::Rvalue::Repeat(ref elem, ref count) => {
524 let elem = self.const_operand(elem, span)?;
525 let size = count.value.as_u64(tcx.sess.target.uint_type);
526 let fields = vec![elem.llval; size as usize];
527 self.const_array(dest_ty, &fields)
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); }
544 mir::AggregateKind::Array => {
545 self.const_array(dest_ty, &fields)
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)
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);
559 let val = match *kind {
560 mir::CastKind::ReifyFnPointer => {
561 match operand.ty.sty {
562 ty::TyFnDef(def_id, substs, _) => {
563 Callee::def(self.ccx, def_id, substs)
567 span_bug!(span, "{} cannot be reified to a fn ptr",
572 mir::CastKind::UnsafeFnPointer => {
573 // this is a no-op at the LLVM level
576 mir::CastKind::Unsize => {
577 // unsize targets other than to a fat pointer currently
578 // can't be in constants.
579 assert!(common::type_is_fat_ptr(self.ccx, cast_ty));
581 let pointee_ty = operand.ty.builtin_deref(true, ty::NoPreference)
582 .expect("consts: unsizing got non-pointer type").ty;
583 let (base, old_info) = if !self.ccx.shared().type_is_sized(pointee_ty) {
584 // Normally, the source is a thin pointer and we are
585 // adding extra info to make a fat pointer. The exception
586 // is when we are upcasting an existing object fat pointer
587 // to use a different vtable. In that case, we want to
588 // load out the original data pointer so we can repackage
590 let (base, extra) = operand.get_fat_ptr();
593 (operand.llval, None)
596 let unsized_ty = cast_ty.builtin_deref(true, ty::NoPreference)
597 .expect("consts: unsizing got non-pointer target type").ty;
598 let ptr_ty = type_of::in_memory_type_of(self.ccx, unsized_ty).ptr_to();
599 let base = consts::ptrcast(base, ptr_ty);
600 let info = base::unsized_info(self.ccx, pointee_ty,
601 unsized_ty, old_info);
603 if old_info.is_none() {
604 let prev_const = self.ccx.const_unsized().borrow_mut()
605 .insert(base, operand.llval);
606 assert!(prev_const.is_none() || prev_const == Some(operand.llval));
608 assert_eq!(abi::FAT_PTR_ADDR, 0);
609 assert_eq!(abi::FAT_PTR_EXTRA, 1);
610 C_struct(self.ccx, &[base, info], false)
612 mir::CastKind::Misc if common::type_is_immediate(self.ccx, operand.ty) => {
613 debug_assert!(common::type_is_immediate(self.ccx, cast_ty));
614 let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast");
615 let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
616 let ll_t_out = type_of::immediate_type_of(self.ccx, cast_ty);
617 let llval = operand.llval;
618 let signed = if let CastTy::Int(IntTy::CEnum) = r_t_in {
619 let l = self.ccx.layout_of(operand.ty);
620 adt::is_discr_signed(&l)
622 operand.ty.is_signed()
626 match (r_t_in, r_t_out) {
627 (CastTy::Int(_), CastTy::Int(_)) => {
628 let s = signed as llvm::Bool;
629 llvm::LLVMConstIntCast(llval, ll_t_out.to_ref(), s)
631 (CastTy::Int(_), CastTy::Float) => {
633 llvm::LLVMConstSIToFP(llval, ll_t_out.to_ref())
635 llvm::LLVMConstUIToFP(llval, ll_t_out.to_ref())
638 (CastTy::Float, CastTy::Float) => {
639 llvm::LLVMConstFPCast(llval, ll_t_out.to_ref())
641 (CastTy::Float, CastTy::Int(IntTy::I)) => {
642 llvm::LLVMConstFPToSI(llval, ll_t_out.to_ref())
644 (CastTy::Float, CastTy::Int(_)) => {
645 llvm::LLVMConstFPToUI(llval, ll_t_out.to_ref())
647 (CastTy::Ptr(_), CastTy::Ptr(_)) |
648 (CastTy::FnPtr, CastTy::Ptr(_)) |
649 (CastTy::RPtr(_), CastTy::Ptr(_)) => {
650 consts::ptrcast(llval, ll_t_out)
652 (CastTy::Int(_), CastTy::Ptr(_)) => {
653 llvm::LLVMConstIntToPtr(llval, ll_t_out.to_ref())
655 (CastTy::Ptr(_), CastTy::Int(_)) |
656 (CastTy::FnPtr, CastTy::Int(_)) => {
657 llvm::LLVMConstPtrToInt(llval, ll_t_out.to_ref())
659 _ => bug!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty)
663 mir::CastKind::Misc => { // Casts from a fat-ptr.
664 let ll_cast_ty = type_of::immediate_type_of(self.ccx, cast_ty);
665 let ll_from_ty = type_of::immediate_type_of(self.ccx, operand.ty);
666 if common::type_is_fat_ptr(self.ccx, operand.ty) {
667 let (data_ptr, meta_ptr) = operand.get_fat_ptr();
668 if common::type_is_fat_ptr(self.ccx, cast_ty) {
669 let ll_cft = ll_cast_ty.field_types();
670 let ll_fft = ll_from_ty.field_types();
671 let data_cast = consts::ptrcast(data_ptr, ll_cft[0]);
672 assert_eq!(ll_cft[1].kind(), ll_fft[1].kind());
673 C_struct(self.ccx, &[data_cast, meta_ptr], false)
674 } else { // cast to thin-ptr
675 // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
676 // pointer-cast of that pointer to desired pointer type.
677 consts::ptrcast(data_ptr, ll_cast_ty)
680 bug!("Unexpected non-fat-pointer operand")
684 Const::new(val, cast_ty)
687 mir::Rvalue::Ref(_, bk, ref lvalue) => {
688 let tr_lvalue = self.const_lvalue(lvalue, span)?;
690 let ty = tr_lvalue.ty;
691 let ref_ty = tcx.mk_ref(tcx.mk_region(ty::ReErased),
692 ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() });
694 let base = match tr_lvalue.base {
695 Base::Value(llval) => {
696 // FIXME: may be wrong for &*(&simd_vec as &fmt::Debug)
697 let align = if self.ccx.shared().type_is_sized(ty) {
698 type_of::align_of(self.ccx, ty)
700 self.ccx.tcx().data_layout.pointer_align.abi() as machine::llalign
702 if bk == mir::BorrowKind::Mut {
703 consts::addr_of_mut(self.ccx, llval, align, "ref_mut")
705 consts::addr_of(self.ccx, llval, align, "ref")
709 Base::Static(llval) => llval
712 let ptr = if self.ccx.shared().type_is_sized(ty) {
715 C_struct(self.ccx, &[base, tr_lvalue.llextra], false)
717 Const::new(ptr, ref_ty)
720 mir::Rvalue::Len(ref lvalue) => {
721 let tr_lvalue = self.const_lvalue(lvalue, span)?;
722 Const::new(tr_lvalue.len(self.ccx), tcx.types.usize)
725 mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
726 let lhs = self.const_operand(lhs, span)?;
727 let rhs = self.const_operand(rhs, span)?;
729 let binop_ty = op.ty(tcx, lhs.ty, rhs.ty);
730 let (lhs, rhs) = (lhs.llval, rhs.llval);
731 Const::new(const_scalar_binop(op, lhs, rhs, ty), binop_ty)
734 mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
735 let lhs = self.const_operand(lhs, span)?;
736 let rhs = self.const_operand(rhs, span)?;
738 let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
739 let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool], false);
740 let (lhs, rhs) = (lhs.llval, rhs.llval);
741 assert!(!ty.is_fp());
743 match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) {
744 Some((llval, of)) => {
745 let llof = C_bool(self.ccx, of);
746 Const::new(C_struct(self.ccx, &[llval, llof], false), binop_ty)
749 span_bug!(span, "{:?} got non-integer operands: {:?} and {:?}",
750 rvalue, Value(lhs), Value(rhs));
755 mir::Rvalue::UnaryOp(op, ref operand) => {
756 let operand = self.const_operand(operand, span)?;
757 let lloperand = operand.llval;
758 let llval = match op {
761 llvm::LLVMConstNot(lloperand)
765 let is_float = operand.ty.is_fp();
768 llvm::LLVMConstFNeg(lloperand)
770 llvm::LLVMConstNeg(lloperand)
775 Const::new(llval, operand.ty)
778 _ => span_bug!(span, "{:?} in constant", rvalue)
781 debug!("const_rvalue({:?}: {:?} @ {:?}) = {:?}", rvalue, dest_ty, span, val);
788 fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
790 ty::TyInt(int_type) => const_to_opt_u128(value, true)
791 .and_then(|input| ConstInt::new_signed(input as i128, int_type,
792 tcx.sess.target.int_type)),
793 ty::TyUint(uint_type) => const_to_opt_u128(value, false)
794 .and_then(|input| ConstInt::new_unsigned(input, uint_type,
795 tcx.sess.target.uint_type)),
801 pub fn const_scalar_binop(op: mir::BinOp,
804 input_ty: Ty) -> ValueRef {
805 assert!(!input_ty.is_simd());
806 let is_float = input_ty.is_fp();
807 let signed = input_ty.is_signed();
811 mir::BinOp::Add if is_float => llvm::LLVMConstFAdd(lhs, rhs),
812 mir::BinOp::Add => llvm::LLVMConstAdd(lhs, rhs),
814 mir::BinOp::Sub if is_float => llvm::LLVMConstFSub(lhs, rhs),
815 mir::BinOp::Sub => llvm::LLVMConstSub(lhs, rhs),
817 mir::BinOp::Mul if is_float => llvm::LLVMConstFMul(lhs, rhs),
818 mir::BinOp::Mul => llvm::LLVMConstMul(lhs, rhs),
820 mir::BinOp::Div if is_float => llvm::LLVMConstFDiv(lhs, rhs),
821 mir::BinOp::Div if signed => llvm::LLVMConstSDiv(lhs, rhs),
822 mir::BinOp::Div => llvm::LLVMConstUDiv(lhs, rhs),
824 mir::BinOp::Rem if is_float => llvm::LLVMConstFRem(lhs, rhs),
825 mir::BinOp::Rem if signed => llvm::LLVMConstSRem(lhs, rhs),
826 mir::BinOp::Rem => llvm::LLVMConstURem(lhs, rhs),
828 mir::BinOp::BitXor => llvm::LLVMConstXor(lhs, rhs),
829 mir::BinOp::BitAnd => llvm::LLVMConstAnd(lhs, rhs),
830 mir::BinOp::BitOr => llvm::LLVMConstOr(lhs, rhs),
832 let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
833 llvm::LLVMConstShl(lhs, rhs)
836 let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
837 if signed { llvm::LLVMConstAShr(lhs, rhs) }
838 else { llvm::LLVMConstLShr(lhs, rhs) }
840 mir::BinOp::Eq | mir::BinOp::Ne |
841 mir::BinOp::Lt | mir::BinOp::Le |
842 mir::BinOp::Gt | mir::BinOp::Ge => {
844 let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop());
845 llvm::LLVMConstFCmp(cmp, lhs, rhs)
847 let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(),
849 llvm::LLVMConstICmp(cmp, lhs, rhs)
856 pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
861 -> Option<(ValueRef, bool)> {
862 if let (Some(lhs), Some(rhs)) = (to_const_int(lllhs, input_ty, tcx),
863 to_const_int(llrhs, input_ty, tcx)) {
864 let result = match op {
865 mir::BinOp::Add => lhs + rhs,
866 mir::BinOp::Sub => lhs - rhs,
867 mir::BinOp::Mul => lhs * rhs,
868 mir::BinOp::Shl => lhs << rhs,
869 mir::BinOp::Shr => lhs >> rhs,
871 bug!("Operator `{:?}` is not a checkable operator", op)
875 let of = match result {
877 Err(ConstMathErr::Overflow(_)) |
878 Err(ConstMathErr::ShiftNegative) => true,
880 bug!("Operator `{:?}` on `{:?}` and `{:?}` errored: {}",
881 op, lhs, rhs, err.description());
885 Some((const_scalar_binop(op, lllhs, llrhs, input_ty), of))
891 impl<'a, 'tcx> MirContext<'a, 'tcx> {
892 pub fn trans_constant(&mut self,
893 bcx: &Builder<'a, 'tcx>,
894 constant: &mir::Constant<'tcx>)
897 debug!("trans_constant({:?})", constant);
898 let ty = self.monomorphize(&constant.ty);
899 let result = match constant.literal.clone() {
900 mir::Literal::Item { def_id, substs } => {
901 // Shortcut for zero-sized types, including function item
902 // types, which would not work with MirConstContext.
903 if common::type_is_zero_size(bcx.ccx, ty) {
904 let llty = type_of::type_of(bcx.ccx, ty);
905 return Const::new(C_null(llty), ty);
908 let substs = self.monomorphize(&substs);
909 let instance = Instance::new(def_id, substs);
910 MirConstContext::trans_def(bcx.ccx, instance, IndexVec::new())
912 mir::Literal::Promoted { index } => {
913 let mir = &self.mir.promoted[index];
914 MirConstContext::new(bcx.ccx, mir, self.param_substs, IndexVec::new()).trans()
916 mir::Literal::Value { value } => {
917 Ok(Const::from_constval(bcx.ccx, value, ty))
921 let result = result.unwrap_or_else(|_| {
922 // We've errored, so we don't have to produce working code.
923 let llty = type_of::type_of(bcx.ccx, ty);
924 Const::new(C_undef(llty), ty)
927 debug!("trans_constant({:?}) = {:?}", constant, result);
933 pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
934 -> Result<ValueRef, ConstEvalErr> {
935 let instance = Instance::mono(ccx.shared(), def_id);
936 MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)
939 /// Construct a constant value, suitable for initializing a
940 /// GlobalVariable, given a case and constant values for its fields.
941 /// Note that this may have a different LLVM type (and different
942 /// alignment!) from the representation's `type_of`, so it needs a
943 /// pointer cast before use.
945 /// The LLVM type system does not directly support unions, and only
946 /// pointers can be bitcast, so a constant (and, by extension, the
947 /// GlobalVariable initialized by it) will have a type that can vary
948 /// depending on which case of an enum it is.
950 /// To understand the alignment situation, consider `enum E { V64(u64),
951 /// V32(u32, u32) }` on Windows. The type has 8-byte alignment to
952 /// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
953 /// i32, i32}`, which is 4-byte aligned.
955 /// Currently the returned value has the same size as the type, but
956 /// this could be changed in the future to avoid allocating unnecessary
957 /// space after values of shorter-than-maximum cases.
958 fn trans_const<'a, 'tcx>(
959 ccx: &CrateContext<'a, 'tcx>,
961 kind: &mir::AggregateKind,
964 let l = ccx.layout_of(t);
965 let dl = &ccx.tcx().data_layout;
966 let variant_index = match *kind {
967 mir::AggregateKind::Adt(_, index, _, _) => index,
971 layout::CEnum { discr: d, min, max, .. } => {
972 let discr = match *kind {
973 mir::AggregateKind::Adt(adt_def, _, _, _) => {
974 Disr::from(adt_def.variants[variant_index].disr_val)
978 assert_eq!(vals.len(), 0);
979 adt::assert_discr_in_range(Disr(min), Disr(max), discr);
980 C_integral(Type::from_integer(ccx, d), discr.0, true)
982 layout::General { discr: d, ref variants, .. } => {
983 let variant = &variants[variant_index];
984 let lldiscr = C_integral(Type::from_integer(ccx, d), variant_index as u64, true);
985 let mut vals_with_discr = vec![lldiscr];
986 vals_with_discr.extend_from_slice(vals);
987 let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
988 let needed_padding = l.size(dl).bytes() - variant.stride().bytes();
989 if needed_padding > 0 {
990 contents.push(padding(ccx, needed_padding));
992 C_struct(ccx, &contents[..], false)
994 layout::UntaggedUnion { ref variants, .. }=> {
995 assert_eq!(variant_index, 0);
996 let contents = build_const_union(ccx, variants, vals[0]);
997 C_struct(ccx, &contents, variants.packed)
999 layout::Univariant { ref variant, .. } => {
1000 assert_eq!(variant_index, 0);
1001 let contents = build_const_struct(ccx, &variant, vals);
1002 C_struct(ccx, &contents[..], variant.packed)
1004 layout::Vector { .. } => {
1007 layout::RawNullablePointer { nndiscr, .. } => {
1008 let nnty = adt::compute_fields(ccx, t, nndiscr as usize, false)[0];
1009 if variant_index as u64 == nndiscr {
1010 assert_eq!(vals.len(), 1);
1013 C_null(type_of::sizing_type_of(ccx, nnty))
1016 layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
1017 if variant_index as u64 == nndiscr {
1018 C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false)
1020 let fields = adt::compute_fields(ccx, t, nndiscr as usize, false);
1021 let vals = fields.iter().map(|&ty| {
1022 // Always use null even if it's not the `discrfield`th
1023 // field; see #8506.
1024 C_null(type_of::sizing_type_of(ccx, ty))
1025 }).collect::<Vec<ValueRef>>();
1026 C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false)
1029 _ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l)
1033 /// Building structs is a little complicated, because we might need to
1034 /// insert padding if a field's value is less aligned than its type.
1036 /// Continuing the example from `trans_const`, a value of type `(u32,
1037 /// E)` should have the `E` at offset 8, but if that field's
1038 /// initializer is 4-byte aligned then simply translating the tuple as
1039 /// a two-element struct will locate it at offset 4, and accesses to it
1040 /// will read the wrong memory.
1041 fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1042 st: &layout::Struct,
1045 assert_eq!(vals.len(), st.offsets.len());
1047 if vals.len() == 0 {
1051 // offset of current value
1053 let mut cfields = Vec::new();
1054 cfields.reserve(st.offsets.len()*2);
1056 let parts = st.field_index_by_increasing_offset().map(|i| {
1057 (&vals[i], st.offsets[i].bytes())
1059 for (&val, target_offset) in parts {
1060 if offset < target_offset {
1061 cfields.push(padding(ccx, target_offset - offset));
1062 offset = target_offset;
1064 assert!(!is_undef(val));
1066 offset += machine::llsize_of_alloc(ccx, val_ty(val));
1069 if offset < st.stride().bytes() {
1070 cfields.push(padding(ccx, st.stride().bytes() - offset));
1076 fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1078 field_val: ValueRef)
1080 let mut cfields = vec![field_val];
1082 let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
1083 let size = un.stride().bytes();
1085 cfields.push(padding(ccx, size - offset));
1091 fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
1092 C_undef(Type::array(&Type::i8(ccx), size))