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, ConstIsize, ConstUsize, ConstMathErr};
17 use rustc::hir::def_id::DefId;
18 use rustc::infer::TransNormalize;
19 use rustc::mir::repr as mir;
20 use rustc::mir::tcx::LvalueTy;
22 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
23 use rustc::ty::cast::{CastTy, IntTy};
24 use rustc::ty::subst::Substs;
25 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
26 use {abi, adt, base, Disr};
28 use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty};
29 use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral};
30 use common::{C_null, C_struct, C_str_slice, C_undef, C_uint};
31 use common::{const_to_opt_int, const_to_opt_uint};
33 use monomorphize::{self, Instance};
39 use syntax_pos::{Span, DUMMY_SP};
43 use super::operand::{OperandRef, OperandValue};
44 use super::MirContext;
46 /// A sized constant rvalue.
47 /// The LLVM type might not be the same for a single Rust type,
48 /// e.g. each enum variant would have its own LLVM struct type.
49 #[derive(Copy, Clone)]
50 pub struct Const<'tcx> {
55 impl<'tcx> Const<'tcx> {
56 pub fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> {
63 /// Translate ConstVal into a LLVM constant value.
64 pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
68 let llty = type_of::type_of(ccx, ty);
70 ConstVal::Float(F32(v)) => C_floating_f64(v as f64, llty),
71 ConstVal::Float(F64(v)) => C_floating_f64(v, llty),
72 ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv),
73 ConstVal::Bool(v) => C_bool(ccx, v),
74 ConstVal::Integral(I8(v)) => C_integral(Type::i8(ccx), v as u64, true),
75 ConstVal::Integral(I16(v)) => C_integral(Type::i16(ccx), v as u64, true),
76 ConstVal::Integral(I32(v)) => C_integral(Type::i32(ccx), v as u64, true),
77 ConstVal::Integral(I64(v)) => C_integral(Type::i64(ccx), v as u64, true),
78 ConstVal::Integral(Isize(v)) => {
79 let i = v.as_i64(ccx.tcx().sess.target.int_type);
80 C_integral(Type::int(ccx), i as u64, true)
82 ConstVal::Integral(U8(v)) => C_integral(Type::i8(ccx), v as u64, false),
83 ConstVal::Integral(U16(v)) => C_integral(Type::i16(ccx), v as u64, false),
84 ConstVal::Integral(U32(v)) => C_integral(Type::i32(ccx), v as u64, false),
85 ConstVal::Integral(U64(v)) => C_integral(Type::i64(ccx), v, false),
86 ConstVal::Integral(Usize(v)) => {
87 let u = v.as_u64(ccx.tcx().sess.target.uint_type);
88 C_integral(Type::int(ccx), u, false)
90 ConstVal::Integral(Infer(_)) |
91 ConstVal::Integral(InferSigned(_)) => bug!("MIR must not use `{:?}`", cv),
92 ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
93 ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
94 ConstVal::Struct(_) | ConstVal::Tuple(_) |
95 ConstVal::Array(..) | ConstVal::Repeat(..) |
96 ConstVal::Function(_) => {
97 bug!("MIR must not use `{:?}` (which refers to a local ID)", cv)
99 ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
100 ConstVal::Dummy => bug!(),
103 assert!(!ty.has_erasable_regions());
108 fn get_pair(&self) -> (ValueRef, ValueRef) {
109 (const_get_elt(self.llval, &[0]),
110 const_get_elt(self.llval, &[1]))
113 fn get_fat_ptr(&self) -> (ValueRef, ValueRef) {
114 assert_eq!(abi::FAT_PTR_ADDR, 0);
115 assert_eq!(abi::FAT_PTR_EXTRA, 1);
119 fn as_lvalue(&self) -> ConstLvalue<'tcx> {
121 base: Base::Value(self.llval),
122 llextra: ptr::null_mut(),
127 pub fn to_operand<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> {
128 let llty = type_of::immediate_type_of(ccx, self.ty);
129 let llvalty = val_ty(self.llval);
131 let val = if llty == llvalty && common::type_is_imm_pair(ccx, self.ty) {
132 let (a, b) = self.get_pair();
133 OperandValue::Pair(a, b)
134 } else if llty == llvalty && common::type_is_immediate(ccx, self.ty) {
135 // If the types match, we can use the value directly.
136 OperandValue::Immediate(self.llval)
138 // Otherwise, or if the value is not immediate, we create
139 // a constant LLVM global and cast its address if necessary.
140 let align = type_of::align_of(ccx, self.ty);
141 let ptr = consts::addr_of(ccx, self.llval, align, "const");
142 OperandValue::Ref(consts::ptrcast(ptr, llty.ptr_to()))
152 #[derive(Copy, Clone)]
154 /// A constant value without an unique address.
157 /// String literal base pointer (cast from array).
160 /// The address of a static.
164 /// An lvalue as seen from a constant.
165 #[derive(Copy, Clone)]
166 struct ConstLvalue<'tcx> {
172 impl<'tcx> ConstLvalue<'tcx> {
173 fn to_const(&self, span: Span) -> Const<'tcx> {
175 Base::Value(val) => Const::new(val, self.ty),
177 span_bug!(span, "loading from `str` ({:?}) in constant",
180 Base::Static(val) => {
181 span_bug!(span, "loading from `static` ({:?}) in constant",
187 pub fn len<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
189 ty::TyArray(_, n) => C_uint(ccx, n),
190 ty::TySlice(_) | ty::TyStr => {
191 assert!(self.llextra != ptr::null_mut());
194 _ => bug!("unexpected type `{}` in ConstLvalue::len", self.ty)
199 /// Machinery for translating a constant's MIR to LLVM values.
200 /// FIXME(eddyb) use miri and lower its allocations to LLVM.
201 struct MirConstContext<'a, 'tcx: 'a> {
202 ccx: &'a CrateContext<'a, 'tcx>,
203 mir: &'a mir::Mir<'tcx>,
205 /// Type parameters for const fn and associated constants.
206 substs: &'tcx Substs<'tcx>,
208 /// Values of locals in a constant or const fn.
209 locals: IndexVec<mir::Local, Option<Const<'tcx>>>
213 impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
214 fn new(ccx: &'a CrateContext<'a, 'tcx>,
215 mir: &'a mir::Mir<'tcx>,
216 substs: &'tcx Substs<'tcx>,
217 args: IndexVec<mir::Arg, Const<'tcx>>)
218 -> MirConstContext<'a, 'tcx> {
219 let mut context = MirConstContext {
223 locals: (0..mir.count_locals()).map(|_| None).collect(),
225 for (i, arg) in args.into_iter().enumerate() {
226 let index = mir.local_index(&mir::Lvalue::Arg(mir::Arg::new(i))).unwrap();
227 context.locals[index] = Some(arg);
232 fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
233 mut instance: Instance<'tcx>,
234 args: IndexVec<mir::Arg, Const<'tcx>>)
235 -> Result<Const<'tcx>, ConstEvalErr> {
236 // Try to resolve associated constants.
237 if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) {
238 let trait_ref = ty::TraitRef::new(trait_id, instance.substs);
239 let trait_ref = ty::Binder(trait_ref);
240 let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref);
241 if let traits::VtableImpl(vtable_impl) = vtable {
242 let name = ccx.tcx().item_name(instance.def);
243 for ac in ccx.tcx().associated_consts(vtable_impl.impl_def_id) {
245 instance = Instance::new(ac.def_id, vtable_impl.substs);
252 let mir = ccx.get_mir(instance.def).unwrap_or_else(|| {
253 bug!("missing constant MIR for {}", instance)
255 MirConstContext::new(ccx, &mir, instance.substs, args).trans()
258 fn monomorphize<T>(&self, value: &T) -> T
259 where T: TransNormalize<'tcx>
261 monomorphize::apply_param_substs(self.ccx.shared(),
266 fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> {
267 let tcx = self.ccx.tcx();
268 let mut bb = mir::START_BLOCK;
270 // Make sure to evaluate all statemenets to
271 // report as many errors as we possibly can.
272 let mut failure = Ok(());
275 let data = &self.mir[bb];
276 for statement in &data.statements {
277 let span = statement.source_info.span;
278 match statement.kind {
279 mir::StatementKind::Assign(ref dest, ref rvalue) => {
280 let ty = dest.ty(self.mir, tcx);
281 let ty = self.monomorphize(&ty).to_ty(tcx);
282 match self.const_rvalue(rvalue, ty, span) {
283 Ok(value) => self.store(dest, value, span),
284 Err(err) => if failure.is_ok() { failure = Err(err); }
287 mir::StatementKind::StorageLive(_) |
288 mir::StatementKind::StorageDead(_) => {}
289 mir::StatementKind::SetDiscriminant{ .. } => {
290 span_bug!(span, "SetDiscriminant should not appear in constants?");
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 => {
302 let index = self.mir.local_index(&mir::Lvalue::ReturnPointer).unwrap();
303 return Ok(self.locals[index].unwrap_or_else(|| {
304 span_bug!(span, "no returned value in constant");
308 mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, .. } => {
309 let cond = self.const_operand(cond, span)?;
310 let cond_bool = common::const_to_uint(cond.llval) != 0;
311 if cond_bool != expected {
312 let err = match *msg {
313 mir::AssertMessage::BoundsCheck { ref len, ref index } => {
314 let len = self.const_operand(len, span)?;
315 let index = self.const_operand(index, span)?;
316 ErrKind::IndexOutOfBounds {
317 len: common::const_to_uint(len.llval),
318 index: common::const_to_uint(index.llval)
321 mir::AssertMessage::Math(ref err) => {
322 ErrKind::Math(err.clone())
326 let err = ConstEvalErr{ span: span, kind: err };
327 report_const_eval_err(tcx, &err, span, "expression").emit();
333 mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
334 let fn_ty = func.ty(self.mir, tcx);
335 let fn_ty = self.monomorphize(&fn_ty);
336 let instance = match fn_ty.sty {
337 ty::TyFnDef(def_id, substs, _) => {
338 Instance::new(def_id, substs)
340 _ => span_bug!(span, "calling {:?} (of type {}) in constant",
344 let mut const_args = IndexVec::with_capacity(args.len());
346 match self.const_operand(arg, span) {
347 Ok(arg) => { const_args.push(arg); },
348 Err(err) => if failure.is_ok() { failure = Err(err); }
351 if let Some((ref dest, target)) = *destination {
352 match MirConstContext::trans_def(self.ccx, instance, const_args) {
353 Ok(value) => self.store(dest, value, span),
354 Err(err) => if failure.is_ok() { failure = Err(err); }
358 span_bug!(span, "diverging {:?} in constant", terminator.kind);
361 _ => span_bug!(span, "{:?} in constant", terminator.kind)
366 fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) {
367 if let Some(index) = self.mir.local_index(dest) {
368 self.locals[index] = Some(value);
370 span_bug!(span, "assignment to {:?} in constant", dest);
374 fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
375 -> Result<ConstLvalue<'tcx>, ConstEvalErr> {
376 let tcx = self.ccx.tcx();
378 if let Some(index) = self.mir.local_index(lvalue) {
379 return Ok(self.locals[index].unwrap_or_else(|| {
380 span_bug!(span, "{:?} not initialized", lvalue)
384 let lvalue = match *lvalue {
385 mir::Lvalue::Var(_) |
386 mir::Lvalue::Temp(_) |
387 mir::Lvalue::Arg(_) |
388 mir::Lvalue::ReturnPointer => bug!(), // handled above
389 mir::Lvalue::Static(def_id) => {
391 base: Base::Static(consts::get_static(self.ccx, def_id)),
392 llextra: ptr::null_mut(),
393 ty: lvalue.ty(self.mir, tcx).to_ty(tcx)
396 mir::Lvalue::Projection(ref projection) => {
397 let tr_base = self.const_lvalue(&projection.base, span)?;
398 let projected_ty = LvalueTy::Ty { ty: tr_base.ty }
399 .projection_ty(tcx, &projection.elem);
400 let base = tr_base.to_const(span);
401 let projected_ty = self.monomorphize(&projected_ty).to_ty(tcx);
402 let is_sized = common::type_is_sized(tcx, projected_ty);
404 let (projected, llextra) = match projection.elem {
405 mir::ProjectionElem::Deref => {
406 let (base, extra) = if is_sized {
407 (base.llval, ptr::null_mut())
411 if self.ccx.statics().borrow().contains_key(&base) {
412 (Base::Static(base), extra)
413 } else if let ty::TyStr = projected_ty.sty {
414 (Base::Str(base), extra)
417 let v = self.ccx.const_unsized().borrow().get(&v).map_or(v, |&v| v);
418 let mut val = unsafe { llvm::LLVMGetInitializer(v) };
420 span_bug!(span, "dereference of non-constant pointer `{:?}`",
423 if projected_ty.is_bool() {
425 val = llvm::LLVMConstTrunc(val, Type::i1(self.ccx).to_ref());
428 (Base::Value(val), extra)
431 mir::ProjectionElem::Field(ref field, _) => {
432 let base_repr = adt::represent_type(self.ccx, tr_base.ty);
433 let llprojected = adt::const_get_field(&base_repr, base.llval,
434 Disr(0), field.index());
435 let llextra = if is_sized {
440 (Base::Value(llprojected), llextra)
442 mir::ProjectionElem::Index(ref index) => {
443 let llindex = self.const_operand(index, span)?.llval;
445 let iv = if let Some(iv) = common::const_to_opt_uint(llindex) {
448 span_bug!(span, "index is not an integer-constant expression")
451 // Produce an undef instead of a LLVM assertion on OOB.
452 let len = common::const_to_uint(tr_base.len(self.ccx));
453 let llelem = if iv < len {
454 const_get_elt(base.llval, &[iv as u32])
456 C_undef(type_of::type_of(self.ccx, projected_ty))
459 (Base::Value(llelem), ptr::null_mut())
461 _ => span_bug!(span, "{:?} in constant", projection.elem)
473 fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
474 -> Result<Const<'tcx>, ConstEvalErr> {
476 mir::Operand::Consume(ref lvalue) => {
477 Ok(self.const_lvalue(lvalue, span)?.to_const(span))
480 mir::Operand::Constant(ref constant) => {
481 let ty = self.monomorphize(&constant.ty);
482 match constant.literal.clone() {
483 mir::Literal::Item { def_id, substs } => {
484 // Shortcut for zero-sized types, including function item
485 // types, which would not work with MirConstContext.
486 if common::type_is_zero_size(self.ccx, ty) {
487 let llty = type_of::type_of(self.ccx, ty);
488 return Ok(Const::new(C_null(llty), ty));
491 let substs = self.monomorphize(&substs);
492 let instance = Instance::new(def_id, substs);
493 MirConstContext::trans_def(self.ccx, instance, IndexVec::new())
495 mir::Literal::Promoted { index } => {
496 let mir = &self.mir.promoted[index];
497 MirConstContext::new(self.ccx, mir, self.substs, IndexVec::new()).trans()
499 mir::Literal::Value { value } => {
500 Ok(Const::from_constval(self.ccx, value, ty))
507 fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
508 dest_ty: Ty<'tcx>, span: Span)
509 -> Result<Const<'tcx>, ConstEvalErr> {
510 let tcx = self.ccx.tcx();
511 let val = match *rvalue {
512 mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?,
514 mir::Rvalue::Repeat(ref elem, ref count) => {
515 let elem = self.const_operand(elem, span)?;
516 let size = count.value.as_u64(tcx.sess.target.uint_type);
517 let fields = vec![elem.llval; size as usize];
519 let llunitty = type_of::type_of(self.ccx, elem.ty);
520 // If the array contains enums, an LLVM array won't work.
521 let val = if val_ty(elem.llval) == llunitty {
522 C_array(llunitty, &fields)
524 C_struct(self.ccx, &fields, false)
526 Const::new(val, dest_ty)
529 mir::Rvalue::Aggregate(ref kind, ref operands) => {
530 // Make sure to evaluate all operands to
531 // report as many errors as we possibly can.
532 let mut fields = Vec::with_capacity(operands.len());
533 let mut failure = Ok(());
534 for operand in operands {
535 match self.const_operand(operand, span) {
536 Ok(val) => fields.push(val.llval),
537 Err(err) => if failure.is_ok() { failure = Err(err); }
542 // FIXME Shouldn't need to manually trigger closure instantiations.
543 if let mir::AggregateKind::Closure(def_id, substs) = *kind {
545 closure::trans_closure_body_via_mir(self.ccx,
547 self.monomorphize(&substs));
550 let val = if let mir::AggregateKind::Adt(adt_def, index, _) = *kind {
551 let repr = adt::represent_type(self.ccx, dest_ty);
552 let disr = Disr::from(adt_def.variants[index].disr_val);
553 adt::trans_const(self.ccx, &repr, disr, &fields)
554 } else if let ty::TyArray(elem_ty, _) = dest_ty.sty {
555 let llunitty = type_of::type_of(self.ccx, elem_ty);
556 // If the array contains enums, an LLVM array won't work.
557 if fields.iter().all(|&f| val_ty(f) == llunitty) {
558 C_array(llunitty, &fields)
560 C_struct(self.ccx, &fields, false)
563 C_struct(self.ccx, &fields, false)
565 Const::new(val, dest_ty)
568 mir::Rvalue::Cast(ref kind, ref source, cast_ty) => {
569 let operand = self.const_operand(source, span)?;
570 let cast_ty = self.monomorphize(&cast_ty);
572 let val = match *kind {
573 mir::CastKind::ReifyFnPointer => {
574 match operand.ty.sty {
575 ty::TyFnDef(def_id, substs, _) => {
576 Callee::def(self.ccx, def_id, substs)
580 span_bug!(span, "{} cannot be reified to a fn ptr",
585 mir::CastKind::UnsafeFnPointer => {
586 // this is a no-op at the LLVM level
589 mir::CastKind::Unsize => {
590 // unsize targets other than to a fat pointer currently
591 // can't be in constants.
592 assert!(common::type_is_fat_ptr(tcx, cast_ty));
594 let pointee_ty = operand.ty.builtin_deref(true, ty::NoPreference)
595 .expect("consts: unsizing got non-pointer type").ty;
596 let (base, old_info) = if !common::type_is_sized(tcx, pointee_ty) {
597 // Normally, the source is a thin pointer and we are
598 // adding extra info to make a fat pointer. The exception
599 // is when we are upcasting an existing object fat pointer
600 // to use a different vtable. In that case, we want to
601 // load out the original data pointer so we can repackage
603 let (base, extra) = operand.get_fat_ptr();
606 (operand.llval, None)
609 let unsized_ty = cast_ty.builtin_deref(true, ty::NoPreference)
610 .expect("consts: unsizing got non-pointer target type").ty;
611 let ptr_ty = type_of::in_memory_type_of(self.ccx, unsized_ty).ptr_to();
612 let base = consts::ptrcast(base, ptr_ty);
613 let info = base::unsized_info(self.ccx, pointee_ty,
614 unsized_ty, old_info);
616 if old_info.is_none() {
617 let prev_const = self.ccx.const_unsized().borrow_mut()
618 .insert(base, operand.llval);
619 assert!(prev_const.is_none() || prev_const == Some(operand.llval));
621 assert_eq!(abi::FAT_PTR_ADDR, 0);
622 assert_eq!(abi::FAT_PTR_EXTRA, 1);
623 C_struct(self.ccx, &[base, info], false)
625 mir::CastKind::Misc if common::type_is_immediate(self.ccx, operand.ty) => {
626 debug_assert!(common::type_is_immediate(self.ccx, cast_ty));
627 let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast");
628 let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
629 let ll_t_out = type_of::immediate_type_of(self.ccx, cast_ty);
630 let llval = operand.llval;
631 let signed = if let CastTy::Int(IntTy::CEnum) = r_t_in {
632 let repr = adt::represent_type(self.ccx, operand.ty);
633 adt::is_discr_signed(&repr)
635 operand.ty.is_signed()
639 match (r_t_in, r_t_out) {
640 (CastTy::Int(_), CastTy::Int(_)) => {
641 let s = signed as llvm::Bool;
642 llvm::LLVMConstIntCast(llval, ll_t_out.to_ref(), s)
644 (CastTy::Int(_), CastTy::Float) => {
646 llvm::LLVMConstSIToFP(llval, ll_t_out.to_ref())
648 llvm::LLVMConstUIToFP(llval, ll_t_out.to_ref())
651 (CastTy::Float, CastTy::Float) => {
652 llvm::LLVMConstFPCast(llval, ll_t_out.to_ref())
654 (CastTy::Float, CastTy::Int(IntTy::I)) => {
655 llvm::LLVMConstFPToSI(llval, ll_t_out.to_ref())
657 (CastTy::Float, CastTy::Int(_)) => {
658 llvm::LLVMConstFPToUI(llval, ll_t_out.to_ref())
660 (CastTy::Ptr(_), CastTy::Ptr(_)) |
661 (CastTy::FnPtr, CastTy::Ptr(_)) |
662 (CastTy::RPtr(_), CastTy::Ptr(_)) => {
663 consts::ptrcast(llval, ll_t_out)
665 (CastTy::Int(_), CastTy::Ptr(_)) => {
666 llvm::LLVMConstIntToPtr(llval, ll_t_out.to_ref())
668 (CastTy::Ptr(_), CastTy::Int(_)) |
669 (CastTy::FnPtr, CastTy::Int(_)) => {
670 llvm::LLVMConstPtrToInt(llval, ll_t_out.to_ref())
672 _ => bug!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty)
676 mir::CastKind::Misc => { // Casts from a fat-ptr.
677 let ll_cast_ty = type_of::immediate_type_of(self.ccx, cast_ty);
678 let ll_from_ty = type_of::immediate_type_of(self.ccx, operand.ty);
679 if common::type_is_fat_ptr(tcx, operand.ty) {
680 let (data_ptr, meta_ptr) = operand.get_fat_ptr();
681 if common::type_is_fat_ptr(tcx, cast_ty) {
682 let ll_cft = ll_cast_ty.field_types();
683 let ll_fft = ll_from_ty.field_types();
684 let data_cast = consts::ptrcast(data_ptr, ll_cft[0]);
685 assert_eq!(ll_cft[1].kind(), ll_fft[1].kind());
686 C_struct(self.ccx, &[data_cast, meta_ptr], false)
687 } else { // cast to thin-ptr
688 // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
689 // pointer-cast of that pointer to desired pointer type.
690 consts::ptrcast(data_ptr, ll_cast_ty)
693 bug!("Unexpected non-fat-pointer operand")
697 Const::new(val, cast_ty)
700 mir::Rvalue::Ref(_, bk, ref lvalue) => {
701 let tr_lvalue = self.const_lvalue(lvalue, span)?;
703 let ty = tr_lvalue.ty;
704 let ref_ty = tcx.mk_ref(tcx.mk_region(ty::ReErased),
705 ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() });
707 let base = match tr_lvalue.base {
708 Base::Value(llval) => {
709 let align = type_of::align_of(self.ccx, ty);
710 if bk == mir::BorrowKind::Mut {
711 consts::addr_of_mut(self.ccx, llval, align, "ref_mut")
713 consts::addr_of(self.ccx, llval, align, "ref")
717 Base::Static(llval) => llval
720 let ptr = if common::type_is_sized(tcx, ty) {
723 C_struct(self.ccx, &[base, tr_lvalue.llextra], false)
725 Const::new(ptr, ref_ty)
728 mir::Rvalue::Len(ref lvalue) => {
729 let tr_lvalue = self.const_lvalue(lvalue, span)?;
730 Const::new(tr_lvalue.len(self.ccx), tcx.types.usize)
733 mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
734 let lhs = self.const_operand(lhs, span)?;
735 let rhs = self.const_operand(rhs, span)?;
737 let binop_ty = op.ty(tcx, lhs.ty, rhs.ty);
738 let (lhs, rhs) = (lhs.llval, rhs.llval);
739 Const::new(const_scalar_binop(op, lhs, rhs, ty), binop_ty)
742 mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
743 let lhs = self.const_operand(lhs, span)?;
744 let rhs = self.const_operand(rhs, span)?;
746 let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
747 let binop_ty = tcx.mk_tup(vec![val_ty, tcx.types.bool]);
748 let (lhs, rhs) = (lhs.llval, rhs.llval);
749 assert!(!ty.is_fp());
751 match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) {
752 Some((llval, of)) => {
753 let llof = C_bool(self.ccx, of);
754 Const::new(C_struct(self.ccx, &[llval, llof], false), binop_ty)
757 span_bug!(span, "{:?} got non-integer operands: {:?} and {:?}",
758 rvalue, Value(lhs), Value(rhs));
763 mir::Rvalue::UnaryOp(op, ref operand) => {
764 let operand = self.const_operand(operand, span)?;
765 let lloperand = operand.llval;
766 let llval = match op {
769 llvm::LLVMConstNot(lloperand)
773 let is_float = operand.ty.is_fp();
776 llvm::LLVMConstFNeg(lloperand)
778 llvm::LLVMConstNeg(lloperand)
783 Const::new(llval, operand.ty)
786 _ => span_bug!(span, "{:?} in constant", rvalue)
794 fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
796 ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type {
798 assert_eq!(input as i8 as i64, input);
799 Some(ConstInt::I8(input as i8))
802 assert_eq!(input as i16 as i64, input);
803 Some(ConstInt::I16(input as i16))
806 assert_eq!(input as i32 as i64, input);
807 Some(ConstInt::I32(input as i32))
810 Some(ConstInt::I64(input))
813 ConstIsize::new(input, tcx.sess.target.int_type)
814 .ok().map(ConstInt::Isize)
817 ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type {
819 assert_eq!(input as u8 as u64, input);
820 Some(ConstInt::U8(input as u8))
822 ast::UintTy::U16 => {
823 assert_eq!(input as u16 as u64, input);
824 Some(ConstInt::U16(input as u16))
826 ast::UintTy::U32 => {
827 assert_eq!(input as u32 as u64, input);
828 Some(ConstInt::U32(input as u32))
830 ast::UintTy::U64 => {
831 Some(ConstInt::U64(input))
834 ConstUsize::new(input, tcx.sess.target.uint_type)
835 .ok().map(ConstInt::Usize)
842 pub fn const_scalar_binop(op: mir::BinOp,
845 input_ty: Ty) -> ValueRef {
846 assert!(!input_ty.is_simd());
847 let is_float = input_ty.is_fp();
848 let signed = input_ty.is_signed();
852 mir::BinOp::Add if is_float => llvm::LLVMConstFAdd(lhs, rhs),
853 mir::BinOp::Add => llvm::LLVMConstAdd(lhs, rhs),
855 mir::BinOp::Sub if is_float => llvm::LLVMConstFSub(lhs, rhs),
856 mir::BinOp::Sub => llvm::LLVMConstSub(lhs, rhs),
858 mir::BinOp::Mul if is_float => llvm::LLVMConstFMul(lhs, rhs),
859 mir::BinOp::Mul => llvm::LLVMConstMul(lhs, rhs),
861 mir::BinOp::Div if is_float => llvm::LLVMConstFDiv(lhs, rhs),
862 mir::BinOp::Div if signed => llvm::LLVMConstSDiv(lhs, rhs),
863 mir::BinOp::Div => llvm::LLVMConstUDiv(lhs, rhs),
865 mir::BinOp::Rem if is_float => llvm::LLVMConstFRem(lhs, rhs),
866 mir::BinOp::Rem if signed => llvm::LLVMConstSRem(lhs, rhs),
867 mir::BinOp::Rem => llvm::LLVMConstURem(lhs, rhs),
869 mir::BinOp::BitXor => llvm::LLVMConstXor(lhs, rhs),
870 mir::BinOp::BitAnd => llvm::LLVMConstAnd(lhs, rhs),
871 mir::BinOp::BitOr => llvm::LLVMConstOr(lhs, rhs),
873 let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
874 llvm::LLVMConstShl(lhs, rhs)
877 let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
878 if signed { llvm::LLVMConstAShr(lhs, rhs) }
879 else { llvm::LLVMConstLShr(lhs, rhs) }
881 mir::BinOp::Eq | mir::BinOp::Ne |
882 mir::BinOp::Lt | mir::BinOp::Le |
883 mir::BinOp::Gt | mir::BinOp::Ge => {
885 let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop());
886 llvm::LLVMConstFCmp(cmp, lhs, rhs)
888 let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(),
890 llvm::LLVMConstICmp(cmp, lhs, rhs)
897 pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
902 -> Option<(ValueRef, bool)> {
903 if let (Some(lhs), Some(rhs)) = (to_const_int(lllhs, input_ty, tcx),
904 to_const_int(llrhs, input_ty, tcx)) {
905 let result = match op {
906 mir::BinOp::Add => lhs + rhs,
907 mir::BinOp::Sub => lhs - rhs,
908 mir::BinOp::Mul => lhs * rhs,
909 mir::BinOp::Shl => lhs << rhs,
910 mir::BinOp::Shr => lhs >> rhs,
912 bug!("Operator `{:?}` is not a checkable operator", op)
916 let of = match result {
918 Err(ConstMathErr::Overflow(_)) |
919 Err(ConstMathErr::ShiftNegative) => true,
921 bug!("Operator `{:?}` on `{:?}` and `{:?}` errored: {}",
922 op, lhs, rhs, err.description());
926 Some((const_scalar_binop(op, lllhs, llrhs, input_ty), of))
932 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
933 pub fn trans_constant(&mut self,
934 bcx: &BlockAndBuilder<'bcx, 'tcx>,
935 constant: &mir::Constant<'tcx>)
938 let ty = bcx.monomorphize(&constant.ty);
939 let result = match constant.literal.clone() {
940 mir::Literal::Item { def_id, substs } => {
941 // Shortcut for zero-sized types, including function item
942 // types, which would not work with MirConstContext.
943 if common::type_is_zero_size(bcx.ccx(), ty) {
944 let llty = type_of::type_of(bcx.ccx(), ty);
945 return Const::new(C_null(llty), ty);
948 let substs = bcx.monomorphize(&substs);
949 let instance = Instance::new(def_id, substs);
950 MirConstContext::trans_def(bcx.ccx(), instance, IndexVec::new())
952 mir::Literal::Promoted { index } => {
953 let mir = &self.mir.promoted[index];
954 MirConstContext::new(bcx.ccx(), mir, bcx.fcx().param_substs,
955 IndexVec::new()).trans()
957 mir::Literal::Value { value } => {
958 Ok(Const::from_constval(bcx.ccx(), value, ty))
962 result.unwrap_or_else(|_| {
963 // We've errored, so we don't have to produce working code.
964 let llty = type_of::type_of(bcx.ccx(), ty);
965 Const::new(C_undef(llty), ty)
971 pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
972 -> Result<ValueRef, ConstEvalErr> {
973 let instance = Instance::mono(ccx.shared(), def_id);
974 MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)