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
;
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
;
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 consts
::{self, ConstEvalFailure, TrueConst, to_const_int}
;
32 use monomorphize
::{self, Instance}
;
37 use syntax_pos
::{Span, DUMMY_SP}
;
42 use super::operand
::{OperandRef, OperandValue}
;
43 use super::MirContext
;
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
> {
54 impl<'tcx
> Const
<'tcx
> {
55 pub fn new(llval
: ValueRef
, ty
: Ty
<'tcx
>) -> Const
<'tcx
> {
62 /// Translate ConstVal into a LLVM constant value.
63 pub fn from_constval
<'a
>(ccx
: &CrateContext
<'a
, 'tcx
>,
67 let llty
= type_of
::type_of(ccx
, ty
);
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)
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)
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
)
98 ConstVal
::Char(c
) => C_integral(Type
::char(ccx
), c
as u64, false),
99 ConstVal
::Dummy
=> bug
!(),
102 assert
!(!ty
.has_erasable_regions());
107 fn get_pair(&self) -> (ValueRef
, ValueRef
) {
108 (const_get_elt(self.llval
, &[0]),
109 const_get_elt(self.llval
, &[1]))
112 fn get_fat_ptr(&self) -> (ValueRef
, ValueRef
) {
113 assert_eq
!(abi
::FAT_PTR_ADDR
, 0);
114 assert_eq
!(abi
::FAT_PTR_EXTRA
, 1);
118 fn as_lvalue(&self) -> ConstLvalue
<'tcx
> {
120 base
: Base
::Value(self.llval
),
121 llextra
: ptr
::null_mut(),
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
);
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
)
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()))
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
)
157 #[derive(Copy, Clone)]
159 /// A constant value without an unique address.
162 /// String literal base pointer (cast from array).
165 /// The address of a static.
169 /// An lvalue as seen from a constant.
170 #[derive(Copy, Clone)]
171 struct ConstLvalue
<'tcx
> {
177 impl<'tcx
> ConstLvalue
<'tcx
> {
178 fn to_const(&self, span
: Span
) -> Const
<'tcx
> {
180 Base
::Value(val
) => Const
::new(val
, self.ty
),
182 span_bug
!(span
, "loading from `str` ({:?}) in constant",
185 Base
::Static(val
) => {
186 span_bug
!(span
, "loading from `static` ({:?}) in constant",
192 pub fn len
<'a
>(&self, ccx
: &CrateContext
<'a
, 'tcx
>) -> ValueRef
{
194 ty
::TyArray(_
, n
) => C_uint(ccx
, n
),
195 ty
::TySlice(_
) | ty
::TyStr
=> {
196 assert
!(self.llextra
!= ptr
::null_mut());
199 _
=> bug
!("unexpected type `{}` in ConstLvalue::len", self.ty
)
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
>,
210 /// Type parameters for const fn and associated constants.
211 substs
: &'tcx Substs
<'tcx
>,
213 /// Values of locals in a constant or const fn.
214 locals
: IndexVec
<mir
::Local
, Option
<Const
<'tcx
>>>
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
{
228 locals
: (0..mir
.count_locals()).map(|_
| None
).collect(),
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
);
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
) {
253 instance
= Instance
::new(ac
.def_id
, vtable_impl
.substs
);
260 let mir
= ccx
.get_mir(instance
.def
).unwrap_or_else(|| {
261 bug
!("missing constant MIR for {}", instance
)
263 MirConstContext
::new(ccx
, &mir
, instance
.substs
, args
).trans()
266 fn monomorphize
<T
>(&self, value
: &T
) -> T
267 where T
: TransNormalize
<'tcx
>
269 monomorphize
::apply_param_substs(self.ccx
.tcx(),
274 fn trans(&mut self) -> Result
<Const
<'tcx
>, ConstEvalFailure
> {
275 let tcx
= self.ccx
.tcx();
276 let mut bb
= mir
::START_BLOCK
;
278 // Make sure to evaluate all statemenets to
279 // report as many errors as we possibly can.
280 let mut failure
= Ok(());
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); }
295 mir
::StatementKind
::StorageLive(_
) |
296 mir
::StatementKind
::StorageDead(_
) => {}
297 mir
::StatementKind
::SetDiscriminant{ .. }
=> {
298 span_bug
!(span
, "SetDiscriminant should not appear in constants?");
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
=> {
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");
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
)
329 mir
::AssertMessage
::Math(ref err
) => {
330 ErrKind
::Math(err
.clone())
333 match consts
::const_err(self.ccx
, span
, Err(err
), TrueConst
::Yes
) {
335 Err(err
) => if failure
.is_ok() { failure = Err(err); }
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
)
348 _
=> span_bug
!(span
, "calling {:?} (of type {}) in constant",
352 let mut const_args
= IndexVec
::with_capacity(args
.len());
354 match self.const_operand(arg
, span
) {
355 Ok(arg
) => { const_args.push(arg); }
,
356 Err(err
) => if failure
.is_ok() { failure = Err(err); }
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); }
366 span_bug
!(span
, "diverging {:?} in constant", terminator
.kind
);
369 _
=> span_bug
!(span
, "{:?} in constant", terminator
.kind
)
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
);
378 span_bug
!(span
, "assignment to {:?} in constant", dest
);
382 fn const_lvalue(&self, lvalue
: &mir
::Lvalue
<'tcx
>, span
: Span
)
383 -> Result
<ConstLvalue
<'tcx
>, ConstEvalFailure
> {
384 let tcx
= self.ccx
.tcx();
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
)
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
) => {
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
)
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
);
412 let (projected
, llextra
) = match projection
.elem
{
413 mir
::ProjectionElem
::Deref
=> {
414 let (base
, extra
) = if is_sized
{
415 (base
.llval
, ptr
::null_mut())
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
)
424 let val
= consts
::load_const(self.ccx
, base
, projected_ty
);
426 span_bug
!(span
, "dereference of non-constant pointer `{:?}`",
429 (Base
::Value(val
), extra
)
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
{
441 (Base
::Value(llprojected
), llextra
)
443 mir
::ProjectionElem
::Index(ref index
) => {
444 let llindex
= self.const_operand(index
, span
)?
.llval
;
446 let iv
= if let Some(iv
) = common
::const_to_opt_uint(llindex
) {
449 span_bug
!(span
, "index is not an integer-constant expression")
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])
457 C_undef(type_of
::type_of(self.ccx
, projected_ty
))
460 (Base
::Value(llelem
), ptr
::null_mut())
462 _
=> span_bug
!(span
, "{:?} in constant", projection
.elem
)
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
))
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
));
493 let substs
= self.monomorphize(&substs
);
494 let instance
= Instance
::new(def_id
, substs
);
495 MirConstContext
::trans_def(self.ccx
, instance
, IndexVec
::new())
497 mir
::Literal
::Promoted { index }
=> {
498 let mir
= &self.mir
.promoted
[index
];
499 MirConstContext
::new(self.ccx
, mir
, self.substs
, IndexVec
::new()).trans()
501 mir
::Literal
::Value { value }
=> {
502 Ok(Const
::from_constval(self.ccx
, value
, ty
))
507 debug
!("const_operand({:?} @ {:?}) = {:?}", operand
, span
,
508 result
.as_ref().ok());
512 fn const_array(&self, array_ty
: Ty
<'tcx
>, fields
: &[ValueRef
])
515 let elem_ty
= array_ty
.builtin_index().unwrap_or_else(|| {
516 bug
!("bad array type {:?}", array_ty
)
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
)
523 C_struct(self.ccx
, fields
, false)
525 Const
::new(val
, array_ty
)
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
)?
,
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
)
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); }
556 // FIXME Shouldn't need to manually trigger closure instantiations.
557 if let mir
::AggregateKind
::Closure(def_id
, substs
) = *kind
{
559 closure
::trans_closure_body_via_mir(self.ccx
,
561 self.monomorphize(&substs
));
565 mir
::AggregateKind
::Vec
=> {
566 self.const_array(dest_ty
, &fields
)
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
)
577 let repr
= adt
::represent_type(self.ccx
, dest_ty
);
579 adt
::trans_const(self.ccx
, &repr
, disr
, &fields
),
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
);
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
)
598 span_bug
!(span
, "{} cannot be reified to a fn ptr",
603 mir
::CastKind
::UnsafeFnPointer
=> {
604 // this is a no-op at the LLVM level
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
));
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
621 let (base
, extra
) = operand
.get_fat_ptr();
624 (operand
.llval
, None
)
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
);
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
));
639 assert_eq
!(abi
::FAT_PTR_ADDR
, 0);
640 assert_eq
!(abi
::FAT_PTR_EXTRA
, 1);
641 C_struct(self.ccx
, &[base
, info
], false)
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
)
653 operand
.ty
.is_signed()
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
)
662 (CastTy
::Int(_
), CastTy
::Float
) => {
664 llvm
::LLVMConstSIToFP(llval
, ll_t_out
.to_ref())
666 llvm
::LLVMConstUIToFP(llval
, ll_t_out
.to_ref())
669 (CastTy
::Float
, CastTy
::Float
) => {
670 llvm
::LLVMConstFPCast(llval
, ll_t_out
.to_ref())
672 (CastTy
::Float
, CastTy
::Int(IntTy
::I
)) => {
673 llvm
::LLVMConstFPToSI(llval
, ll_t_out
.to_ref())
675 (CastTy
::Float
, CastTy
::Int(_
)) => {
676 llvm
::LLVMConstFPToUI(llval
, ll_t_out
.to_ref())
678 (CastTy
::Ptr(_
), CastTy
::Ptr(_
)) |
679 (CastTy
::FnPtr
, CastTy
::Ptr(_
)) |
680 (CastTy
::RPtr(_
), CastTy
::Ptr(_
)) => {
681 consts
::ptrcast(llval
, ll_t_out
)
683 (CastTy
::Int(_
), CastTy
::Ptr(_
)) => {
684 llvm
::LLVMConstIntToPtr(llval
, ll_t_out
.to_ref())
686 (CastTy
::Ptr(_
), CastTy
::Int(_
)) |
687 (CastTy
::FnPtr
, CastTy
::Int(_
)) => {
688 llvm
::LLVMConstPtrToInt(llval
, ll_t_out
.to_ref())
690 _
=> bug
!("unsupported cast: {:?} to {:?}", operand
.ty
, cast_ty
)
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
)
711 bug
!("Unexpected non-fat-pointer operand")
715 Const
::new(val
, cast_ty
)
718 mir
::Rvalue
::Ref(_
, bk
, ref lvalue
) => {
719 let tr_lvalue
= self.const_lvalue(lvalue
, span
)?
;
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() }
);
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")
731 consts
::addr_of(self.ccx
, llval
, align
, "ref")
735 Base
::Static(llval
) => llval
738 let ptr
= if common
::type_is_sized(tcx
, ty
) {
741 C_struct(self.ccx
, &[base
, tr_lvalue
.llextra
], false)
743 Const
::new(ptr
, ref_ty
)
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)
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
)?
;
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
)
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
)?
;
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());
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
)
775 span_bug
!(span
, "{:?} got non-integer operands: {:?} and {:?}",
776 rvalue
, Value(lhs
), Value(rhs
));
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
{
787 llvm
::LLVMConstNot(lloperand
)
791 let is_float
= operand
.ty
.is_fp();
794 llvm
::LLVMConstFNeg(lloperand
)
796 llvm
::LLVMConstNeg(lloperand
)
801 Const
::new(llval
, operand
.ty
)
804 _
=> span_bug
!(span
, "{:?} in constant", rvalue
)
807 debug
!("const_rvalue({:?}: {:?} @ {:?}) = {:?}", rvalue
, dest_ty
, span
, val
);
814 pub fn const_scalar_binop(op
: mir
::BinOp
,
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();
824 mir
::BinOp
::Add
if is_float
=> llvm
::LLVMConstFAdd(lhs
, rhs
),
825 mir
::BinOp
::Add
=> llvm
::LLVMConstAdd(lhs
, rhs
),
827 mir
::BinOp
::Sub
if is_float
=> llvm
::LLVMConstFSub(lhs
, rhs
),
828 mir
::BinOp
::Sub
=> llvm
::LLVMConstSub(lhs
, rhs
),
830 mir
::BinOp
::Mul
if is_float
=> llvm
::LLVMConstFMul(lhs
, rhs
),
831 mir
::BinOp
::Mul
=> llvm
::LLVMConstMul(lhs
, rhs
),
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
),
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
),
841 mir
::BinOp
::BitXor
=> llvm
::LLVMConstXor(lhs
, rhs
),
842 mir
::BinOp
::BitAnd
=> llvm
::LLVMConstAnd(lhs
, rhs
),
843 mir
::BinOp
::BitOr
=> llvm
::LLVMConstOr(lhs
, rhs
),
845 let rhs
= base
::cast_shift_const_rhs(op
.to_hir_binop(), lhs
, rhs
);
846 llvm
::LLVMConstShl(lhs
, rhs
)
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) }
853 mir
::BinOp
::Eq
| mir
::BinOp
::Ne
|
854 mir
::BinOp
::Lt
| mir
::BinOp
::Le
|
855 mir
::BinOp
::Gt
| mir
::BinOp
::Ge
=> {
857 let cmp
= base
::bin_op_to_fcmp_predicate(op
.to_hir_binop());
858 llvm
::LLVMConstFCmp(cmp
, lhs
, rhs
)
860 let cmp
= base
::bin_op_to_icmp_predicate(op
.to_hir_binop(),
862 llvm
::LLVMConstICmp(cmp
, lhs
, rhs
)
869 pub fn const_scalar_checked_binop
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, '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
,
884 bug
!("Operator `{:?}` is not a checkable operator", op
)
888 let of
= match result
{
890 Err(ConstMathErr
::Overflow(_
)) |
891 Err(ConstMathErr
::ShiftNegative
) => true,
893 bug
!("Operator `{:?}` on `{:?}` and `{:?}` errored: {}",
894 op
, lhs
, rhs
, err
.description());
898 Some((const_scalar_binop(op
, lllhs
, llrhs
, input_ty
), of
))
904 impl<'bcx
, 'tcx
> MirContext
<'bcx
, 'tcx
> {
905 pub fn trans_constant(&mut self,
906 bcx
: &BlockAndBuilder
<'bcx
, 'tcx
>,
907 constant
: &mir
::Constant
<'tcx
>)
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
);
921 let substs
= bcx
.monomorphize(&substs
);
922 let instance
= Instance
::new(def_id
, substs
);
923 MirConstContext
::trans_def(bcx
.ccx(), instance
, IndexVec
::new())
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()
930 mir
::Literal
::Value { value }
=> {
931 Ok(Const
::from_constval(bcx
.ccx(), value
, ty
))
935 let result
= match result
{
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
)
942 Err(ConstEvalFailure
::Runtime(err
)) => {
943 span_bug
!(constant
.span
,
944 "MIR constant {:?} results in runtime panic: {:?}",
945 constant
, err
.description())
949 debug
!("trans_constant({:?}) = {:?}", constant
, result
);
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
)