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