1 // Copyright 2012 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.
13 use llvm
::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr}
;
14 use llvm
::{InternalLinkage, ValueRef, Bool, True}
;
15 use middle
::const_qualif
::ConstQualif
;
16 use rustc_const_eval
::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind}
;
17 use rustc_const_eval
::eval_repeat_count
;
18 use rustc
::hir
::def
::Def
;
19 use rustc
::hir
::def_id
::DefId
;
20 use rustc
::hir
::map
as hir_map
;
21 use {abi, adt, closure, debuginfo, expr, machine}
;
22 use base
::{self, exported_name, imported_name, push_ctxt}
;
24 use collector
::{self, TransItem}
;
25 use common
::{type_is_sized, C_nil, const_get_elt}
;
26 use common
::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty}
;
27 use common
::{C_struct, C_undef, const_to_opt_int, const_to_opt_uint, VariantInfo, C_uint}
;
28 use common
::{type_is_fat_ptr, Field, C_vector, C_array, C_null}
;
29 use datum
::{Datum, Lvalue}
;
31 use monomorphize
::{self, Instance}
;
36 use rustc
::ty
::subst
::Substs
;
37 use rustc
::ty
::adjustment
::{AdjustDerefRef, AdjustReifyFnPointer}
;
38 use rustc
::ty
::adjustment
::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}
;
39 use rustc
::ty
::{self, Ty, TyCtxt}
;
40 use rustc
::ty
::cast
::{CastTy,IntTy}
;
41 use util
::nodemap
::NodeMap
;
42 use rustc_const_math
::{ConstInt, ConstMathErr, ConstUsize, ConstIsize}
;
46 use std
::ffi
::{CStr, CString}
;
49 use syntax
::ast
::{self, LitKind}
;
50 use syntax
::attr
::{self, AttrMetaMethods}
;
51 use syntax
::parse
::token
;
54 pub type FnArgMap
<'a
> = Option
<&'a NodeMap
<ValueRef
>>;
56 pub fn const_lit(cx
: &CrateContext
, e
: &hir
::Expr
, lit
: &ast
::Lit
)
58 let _icx
= push_ctxt("trans_lit");
59 debug
!("const_lit: {:?}", lit
);
61 LitKind
::Byte(b
) => C_integral(Type
::uint_from_ty(cx
, ast
::UintTy
::U8
), b
as u64, false),
62 LitKind
::Char(i
) => C_integral(Type
::char(cx
), i
as u64, false),
63 LitKind
::Int(i
, ast
::LitIntType
::Signed(t
)) => {
64 C_integral(Type
::int_from_ty(cx
, t
), i
, true)
66 LitKind
::Int(u
, ast
::LitIntType
::Unsigned(t
)) => {
67 C_integral(Type
::uint_from_ty(cx
, t
), u
, false)
69 LitKind
::Int(i
, ast
::LitIntType
::Unsuffixed
) => {
70 let lit_int_ty
= cx
.tcx().node_id_to_type(e
.id
);
71 match lit_int_ty
.sty
{
73 C_integral(Type
::int_from_ty(cx
, t
), i
as u64, true)
76 C_integral(Type
::uint_from_ty(cx
, t
), i
as u64, false)
78 _
=> span_bug
!(lit
.span
,
79 "integer literal has type {:?} (expected int \
84 LitKind
::Float(ref fs
, t
) => {
85 C_floating(&fs
, Type
::float_from_ty(cx
, t
))
87 LitKind
::FloatUnsuffixed(ref fs
) => {
88 let lit_float_ty
= cx
.tcx().node_id_to_type(e
.id
);
89 match lit_float_ty
.sty
{
91 C_floating(&fs
, Type
::float_from_ty(cx
, t
))
95 "floating point literal doesn't have the right type");
99 LitKind
::Bool(b
) => C_bool(cx
, b
),
100 LitKind
::Str(ref s
, _
) => C_str_slice(cx
, (*s
).clone()),
101 LitKind
::ByteStr(ref data
) => {
102 addr_of(cx
, C_bytes(cx
, &data
[..]), 1, "byte_str")
107 pub fn ptrcast(val
: ValueRef
, ty
: Type
) -> ValueRef
{
109 llvm
::LLVMConstPointerCast(val
, ty
.to_ref())
113 fn addr_of_mut(ccx
: &CrateContext
,
115 align
: machine
::llalign
,
119 // FIXME: this totally needs a better name generation scheme, perhaps a simple global
120 // counter? Also most other uses of gensym in trans.
121 let gsym
= token
::gensym("_");
122 let name
= format
!("{}{}", kind
, gsym
.0);
123 let gv
= declare
::define_global(ccx
, &name
[..], val_ty(cv
)).unwrap_or_else(||{
124 bug
!("symbol `{}` is already defined", name
);
126 llvm
::LLVMSetInitializer(gv
, cv
);
127 llvm
::LLVMSetAlignment(gv
, align
);
128 SetLinkage(gv
, InternalLinkage
);
129 SetUnnamedAddr(gv
, true);
134 pub fn addr_of(ccx
: &CrateContext
,
136 align
: machine
::llalign
,
139 match ccx
.const_globals().borrow().get(&cv
) {
142 // Upgrade the alignment in cases where the same constant is used with different
143 // alignment requirements
144 if align
> llvm
::LLVMGetAlignment(gv
) {
145 llvm
::LLVMSetAlignment(gv
, align
);
152 let gv
= addr_of_mut(ccx
, cv
, align
, kind
);
154 llvm
::LLVMSetGlobalConstant(gv
, True
);
156 ccx
.const_globals().borrow_mut().insert(cv
, gv
);
160 /// Deref a constant pointer
161 fn load_const(cx
: &CrateContext
, v
: ValueRef
, t
: Ty
) -> ValueRef
{
162 let v
= match cx
.const_unsized().borrow().get(&v
) {
166 let d
= unsafe { llvm::LLVMGetInitializer(v) }
;
168 unsafe { llvm::LLVMConstTrunc(d, Type::i1(cx).to_ref()) }
174 fn const_deref
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
177 -> (ValueRef
, Ty
<'tcx
>) {
178 match ty
.builtin_deref(true, ty
::NoPreference
) {
180 if type_is_sized(cx
.tcx(), mt
.ty
) {
181 (load_const(cx
, v
, mt
.ty
), mt
.ty
)
183 // Derefing a fat pointer does not change the representation,
184 // just the type to the unsized contents.
189 bug
!("unexpected dereferenceable type {:?}", ty
)
194 fn const_fn_call
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
196 substs
: Substs
<'tcx
>,
197 arg_vals
: &[ValueRef
],
198 param_substs
: &'tcx Substs
<'tcx
>,
199 trueconst
: TrueConst
) -> Result
<ValueRef
, ConstEvalFailure
> {
200 let fn_like
= lookup_const_fn_by_id(ccx
.tcx(), def_id
);
201 let fn_like
= fn_like
.expect("lookup_const_fn_by_id failed in const_fn_call");
203 let body
= match fn_like
.body().expr
{
204 Some(ref expr
) => expr
,
205 None
=> return Ok(C_nil(ccx
))
208 let args
= &fn_like
.decl().inputs
;
209 assert_eq
!(args
.len(), arg_vals
.len());
211 let arg_ids
= args
.iter().map(|arg
| arg
.pat
.id
);
212 let fn_args
= arg_ids
.zip(arg_vals
.iter().cloned()).collect();
214 let substs
= monomorphize
::apply_param_substs(ccx
.tcx(),
216 &substs
.erase_regions());
217 let substs
= ccx
.tcx().mk_substs(substs
);
219 const_expr(ccx
, body
, substs
, Some(&fn_args
), trueconst
).map(|(res
, _
)| res
)
222 pub fn get_const_expr
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
224 ref_expr
: &hir
::Expr
,
225 param_substs
: &'tcx Substs
<'tcx
>)
227 let substs
= ccx
.tcx().node_id_item_substs(ref_expr
.id
).substs
;
228 let substs
= monomorphize
::apply_param_substs(ccx
.tcx(),
230 &substs
.erase_regions());
231 match lookup_const_by_id(ccx
.tcx(), def_id
, Some(substs
)) {
232 Some((ref expr
, _ty
)) => expr
,
234 span_bug
!(ref_expr
.span
, "constant item not found")
239 pub enum ConstEvalFailure
{
240 /// in case the const evaluator failed on something that panic at runtime
241 /// as defined in RFC 1229
242 Runtime(ConstEvalErr
),
243 // in case we found a true constant
244 Compiletime(ConstEvalErr
),
247 impl ConstEvalFailure
{
248 fn into_inner(self) -> ConstEvalErr
{
254 pub fn description(&self) -> Cow
<str> {
256 &Runtime(ref e
) => e
.description(),
257 &Compiletime(ref e
) => e
.description(),
262 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
267 use self::ConstEvalFailure
::*;
269 fn get_const_val
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
271 ref_expr
: &hir
::Expr
,
272 param_substs
: &'tcx Substs
<'tcx
>)
273 -> Result
<ValueRef
, ConstEvalFailure
> {
274 let expr
= get_const_expr(ccx
, def_id
, ref_expr
, param_substs
);
275 let empty_substs
= ccx
.tcx().mk_substs(Substs
::empty());
276 match get_const_expr_as_global(ccx
, expr
, ConstQualif
::empty(), empty_substs
, TrueConst
::Yes
) {
277 Err(Runtime(err
)) => {
278 ccx
.tcx().sess
.span_err(expr
.span
, &err
.description());
279 Err(Compiletime(err
))
285 pub fn get_const_expr_as_global
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
288 param_substs
: &'tcx Substs
<'tcx
>,
289 trueconst
: TrueConst
)
290 -> Result
<ValueRef
, ConstEvalFailure
> {
291 debug
!("get_const_expr_as_global: {:?}", expr
.id
);
292 // Special-case constants to cache a common global for all uses.
293 if let hir
::ExprPath(..) = expr
.node
{
294 // `def` must be its own statement and cannot be in the `match`
295 // otherwise the `def_map` will be borrowed for the entire match instead
296 // of just to get the `def` value
297 let def
= ccx
.tcx().def_map
.borrow().get(&expr
.id
).unwrap().full_def();
299 Def
::Const(def_id
) | Def
::AssociatedConst(def_id
) => {
300 if !ccx
.tcx().tables
.borrow().adjustments
.contains_key(&expr
.id
) {
301 debug
!("get_const_expr_as_global ({:?}): found const {:?}",
303 return get_const_val(ccx
, def_id
, expr
, param_substs
);
310 let key
= (expr
.id
, param_substs
);
311 if let Some(&val
) = ccx
.const_values().borrow().get(&key
) {
314 let ty
= monomorphize
::apply_param_substs(ccx
.tcx(), param_substs
,
315 &ccx
.tcx().expr_ty(expr
));
316 let val
= if qualif
.intersects(ConstQualif
::NON_STATIC_BORROWS
) {
317 // Avoid autorefs as they would create global instead of stack
318 // references, even when only the latter are correct.
319 const_expr_unadjusted(ccx
, expr
, ty
, param_substs
, None
, trueconst
)?
321 const_expr(ccx
, expr
, param_substs
, None
, trueconst
)?
.0
324 // boolean SSA values are i1, but they have to be stored in i8 slots,
325 // otherwise some LLVM optimization passes don't work as expected
327 if llvm
::LLVMTypeOf(val
) == Type
::i1(ccx
).to_ref() {
328 llvm
::LLVMConstZExt(val
, Type
::i8(ccx
).to_ref())
334 let lvalue
= addr_of(ccx
, val
, type_of
::align_of(ccx
, ty
), "const");
335 ccx
.const_values().borrow_mut().insert(key
, lvalue
);
339 pub fn const_expr
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
341 param_substs
: &'tcx Substs
<'tcx
>,
343 trueconst
: TrueConst
)
344 -> Result
<(ValueRef
, Ty
<'tcx
>), ConstEvalFailure
> {
345 let ety
= monomorphize
::apply_param_substs(cx
.tcx(), param_substs
,
346 &cx
.tcx().expr_ty(e
));
347 let llconst
= const_expr_unadjusted(cx
, e
, ety
, param_substs
, fn_args
, trueconst
)?
;
348 let mut llconst
= llconst
;
349 let mut ety_adjusted
= monomorphize
::apply_param_substs(cx
.tcx(), param_substs
,
350 &cx
.tcx().expr_ty_adjusted(e
));
351 let opt_adj
= cx
.tcx().tables
.borrow().adjustments
.get(&e
.id
).cloned();
353 Some(AdjustReifyFnPointer
) => {
355 ty
::TyFnDef(def_id
, substs
, _
) => {
356 llconst
= Callee
::def(cx
, def_id
, substs
).reify(cx
).val
;
359 bug
!("{} cannot be reified to a fn ptr", ety
)
363 Some(AdjustUnsafeFnPointer
) | Some(AdjustMutToConstPointer
) => {
364 // purely a type-level thing
366 Some(AdjustDerefRef(adj
)) => {
368 // Save the last autoderef in case we can avoid it.
369 if adj
.autoderefs
> 0 {
370 for _
in 0..adj
.autoderefs
-1 {
371 let (dv
, dt
) = const_deref(cx
, llconst
, ty
);
377 if adj
.autoref
.is_some() {
378 if adj
.autoderefs
== 0 {
379 // Don't copy data to do a deref+ref
380 // (i.e., skip the last auto-deref).
381 llconst
= addr_of(cx
, llconst
, type_of
::align_of(cx
, ty
), "autoref");
382 ty
= cx
.tcx().mk_imm_ref(cx
.tcx().mk_region(ty
::ReStatic
), ty
);
384 } else if adj
.autoderefs
> 0 {
385 let (dv
, dt
) = const_deref(cx
, llconst
, ty
);
388 // If we derefed a fat pointer then we will have an
389 // open type here. So we need to update the type with
390 // the one returned from const_deref.
394 if let Some(target
) = adj
.unsize
{
395 let target
= monomorphize
::apply_param_substs(cx
.tcx(),
399 let pointee_ty
= ty
.builtin_deref(true, ty
::NoPreference
)
400 .expect("consts: unsizing got non-pointer type").ty
;
401 let (base
, old_info
) = if !type_is_sized(cx
.tcx(), pointee_ty
) {
402 // Normally, the source is a thin pointer and we are
403 // adding extra info to make a fat pointer. The exception
404 // is when we are upcasting an existing object fat pointer
405 // to use a different vtable. In that case, we want to
406 // load out the original data pointer so we can repackage
408 (const_get_elt(llconst
, &[abi
::FAT_PTR_ADDR
as u32]),
409 Some(const_get_elt(llconst
, &[abi
::FAT_PTR_EXTRA
as u32])))
414 let unsized_ty
= target
.builtin_deref(true, ty
::NoPreference
)
415 .expect("consts: unsizing got non-pointer target type").ty
;
416 let ptr_ty
= type_of
::in_memory_type_of(cx
, unsized_ty
).ptr_to();
417 let base
= ptrcast(base
, ptr_ty
);
418 let info
= base
::unsized_info(cx
, pointee_ty
, unsized_ty
, old_info
);
420 if old_info
.is_none() {
421 let prev_const
= cx
.const_unsized().borrow_mut()
422 .insert(base
, llconst
);
423 assert
!(prev_const
.is_none() || prev_const
== Some(llconst
));
425 assert_eq
!(abi
::FAT_PTR_ADDR
, 0);
426 assert_eq
!(abi
::FAT_PTR_EXTRA
, 1);
427 llconst
= C_struct(cx
, &[base
, info
], false);
433 let llty
= type_of
::sizing_type_of(cx
, ety_adjusted
);
434 let csize
= machine
::llsize_of_alloc(cx
, val_ty(llconst
));
435 let tsize
= machine
::llsize_of_alloc(cx
, llty
);
437 cx
.sess().abort_if_errors();
439 // FIXME these values could use some context
440 llvm
::LLVMDumpValue(llconst
);
441 llvm
::LLVMDumpValue(C_undef(llty
));
443 bug
!("const {:?} of type {:?} has size {} instead of {}",
447 Ok((llconst
, ety_adjusted
))
450 fn check_unary_expr_validity(cx
: &CrateContext
, e
: &hir
::Expr
, t
: Ty
,
451 te
: ValueRef
, trueconst
: TrueConst
) -> Result
<(), ConstEvalFailure
> {
452 // The only kind of unary expression that we check for validity
453 // here is `-expr`, to check if it "overflows" (e.g. `-i32::MIN`).
454 if let hir
::ExprUnary(hir
::UnNeg
, ref inner_e
) = e
.node
{
456 // An unfortunate special case: we parse e.g. -128 as a
457 // negation of the literal 128, which means if we're expecting
458 // a i8 (or if it was already suffixed, e.g. `-128_i8`), then
459 // 128 will have already overflowed to -128, and so then the
460 // constant evaluator thinks we're trying to negate -128.
462 // Catch this up front by looking for ExprLit directly,
463 // and just accepting it.
464 if let hir
::ExprLit(_
) = inner_e
.node { return Ok(()); }
465 let cval
= match to_const_int(te
, t
, cx
.tcx()) {
467 None
=> return Ok(()),
470 Ok(_
) => return Ok(()),
471 Err(err
) => const_err(cx
, e
, Err(err
), trueconst
),
478 fn to_const_int(value
: ValueRef
, t
: Ty
, tcx
: &TyCtxt
) -> Option
<ConstInt
> {
480 ty
::TyInt(int_type
) => const_to_opt_int(value
).and_then(|input
| match int_type
{
482 assert_eq
!(input
as i8 as i64, input
);
483 Some(ConstInt
::I8(input
as i8))
486 assert_eq
!(input
as i16 as i64, input
);
487 Some(ConstInt
::I16(input
as i16))
490 assert_eq
!(input
as i32 as i64, input
);
491 Some(ConstInt
::I32(input
as i32))
494 Some(ConstInt
::I64(input
))
497 ConstIsize
::new(input
, tcx
.sess
.target
.int_type
)
498 .ok().map(ConstInt
::Isize
)
501 ty
::TyUint(uint_type
) => const_to_opt_uint(value
).and_then(|input
| match uint_type
{
503 assert_eq
!(input
as u8 as u64, input
);
504 Some(ConstInt
::U8(input
as u8))
506 ast
::UintTy
::U16
=> {
507 assert_eq
!(input
as u16 as u64, input
);
508 Some(ConstInt
::U16(input
as u16))
510 ast
::UintTy
::U32
=> {
511 assert_eq
!(input
as u32 as u64, input
);
512 Some(ConstInt
::U32(input
as u32))
514 ast
::UintTy
::U64
=> {
515 Some(ConstInt
::U64(input
))
518 ConstUsize
::new(input
, tcx
.sess
.target
.uint_type
)
519 .ok().map(ConstInt
::Usize
)
526 fn const_err(cx
: &CrateContext
,
528 result
: Result
<ConstInt
, ConstMathErr
>,
529 trueconst
: TrueConst
)
530 -> Result
<(), ConstEvalFailure
> {
531 match (result
, trueconst
) {
533 // We do not actually care about a successful result.
536 (Err(err
), TrueConst
::Yes
) => {
537 let err
= ConstEvalErr{ span: e.span, kind: ErrKind::Math(err) }
;
538 cx
.tcx().sess
.span_err(e
.span
, &err
.description());
539 Err(Compiletime(err
))
541 (Err(err
), TrueConst
::No
) => {
542 let err
= ConstEvalErr{ span: e.span, kind: ErrKind::Math(err) }
;
543 cx
.tcx().sess
.span_warn(e
.span
, &err
.description());
549 fn check_binary_expr_validity(cx
: &CrateContext
, e
: &hir
::Expr
, t
: Ty
,
550 te1
: ValueRef
, te2
: ValueRef
,
551 trueconst
: TrueConst
) -> Result
<(), ConstEvalFailure
> {
552 let b
= if let hir
::ExprBinary(b
, _
, _
) = e
.node { b }
else { bug!() }
;
553 let (lhs
, rhs
) = match (to_const_int(te1
, t
, cx
.tcx()), to_const_int(te2
, t
, cx
.tcx())) {
554 (Some(v1
), Some(v2
)) => (v1
, v2
),
557 let result
= match b
.node
{
558 hir
::BiAdd
=> lhs
+ rhs
,
559 hir
::BiSub
=> lhs
- rhs
,
560 hir
::BiMul
=> lhs
* rhs
,
561 hir
::BiDiv
=> lhs
/ rhs
,
562 hir
::BiRem
=> lhs
% rhs
,
563 hir
::BiShl
=> lhs
<< rhs
,
564 hir
::BiShr
=> lhs
>> rhs
,
567 const_err(cx
, e
, result
, trueconst
)
570 fn const_expr_unadjusted
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
573 param_substs
: &'tcx Substs
<'tcx
>,
575 trueconst
: TrueConst
)
576 -> Result
<ValueRef
, ConstEvalFailure
>
578 debug
!("const_expr_unadjusted(e={:?}, ety={:?}, param_substs={:?})",
583 let map_list
= |exprs
: &[P
<hir
::Expr
>]| -> Result
<Vec
<ValueRef
>, ConstEvalFailure
> {
585 .map(|e
| const_expr(cx
, &e
, param_substs
, fn_args
, trueconst
).map(|(l
, _
)| l
))
586 .collect
::<Vec
<Result
<ValueRef
, ConstEvalFailure
>>>()
589 // this dance is necessary to eagerly run const_expr so all errors are reported
591 let _icx
= push_ctxt("const_expr");
593 hir
::ExprLit(ref lit
) => const_lit(cx
, e
, &lit
),
594 hir
::ExprBinary(b
, ref e1
, ref e2
) => {
595 /* Neither type is bottom, and we expect them to be unified
596 * already, so the following is safe. */
597 let (te1
, ty
) = const_expr(cx
, &e1
, param_substs
, fn_args
, trueconst
)?
;
598 debug
!("const_expr_unadjusted: te1={:?}, ty={:?}",
600 assert
!(!ty
.is_simd());
601 let is_float
= ty
.is_fp();
602 let signed
= ty
.is_signed();
604 let (te2
, ty2
) = const_expr(cx
, &e2
, param_substs
, fn_args
, trueconst
)?
;
605 debug
!("const_expr_unadjusted: te2={:?}, ty={:?}",
608 check_binary_expr_validity(cx
, e
, ty
, te1
, te2
, trueconst
)?
;
610 unsafe { match b
.node
{
611 hir
::BiAdd
if is_float
=> llvm
::LLVMConstFAdd(te1
, te2
),
612 hir
::BiAdd
=> llvm
::LLVMConstAdd(te1
, te2
),
614 hir
::BiSub
if is_float
=> llvm
::LLVMConstFSub(te1
, te2
),
615 hir
::BiSub
=> llvm
::LLVMConstSub(te1
, te2
),
617 hir
::BiMul
if is_float
=> llvm
::LLVMConstFMul(te1
, te2
),
618 hir
::BiMul
=> llvm
::LLVMConstMul(te1
, te2
),
620 hir
::BiDiv
if is_float
=> llvm
::LLVMConstFDiv(te1
, te2
),
621 hir
::BiDiv
if signed
=> llvm
::LLVMConstSDiv(te1
, te2
),
622 hir
::BiDiv
=> llvm
::LLVMConstUDiv(te1
, te2
),
624 hir
::BiRem
if is_float
=> llvm
::LLVMConstFRem(te1
, te2
),
625 hir
::BiRem
if signed
=> llvm
::LLVMConstSRem(te1
, te2
),
626 hir
::BiRem
=> llvm
::LLVMConstURem(te1
, te2
),
628 hir
::BiAnd
=> llvm
::LLVMConstAnd(te1
, te2
),
629 hir
::BiOr
=> llvm
::LLVMConstOr(te1
, te2
),
630 hir
::BiBitXor
=> llvm
::LLVMConstXor(te1
, te2
),
631 hir
::BiBitAnd
=> llvm
::LLVMConstAnd(te1
, te2
),
632 hir
::BiBitOr
=> llvm
::LLVMConstOr(te1
, te2
),
634 let te2
= base
::cast_shift_const_rhs(b
.node
, te1
, te2
);
635 llvm
::LLVMConstShl(te1
, te2
)
638 let te2
= base
::cast_shift_const_rhs(b
.node
, te1
, te2
);
639 if signed { llvm::LLVMConstAShr(te1, te2) }
640 else { llvm::LLVMConstLShr(te1, te2) }
642 hir
::BiEq
| hir
::BiNe
| hir
::BiLt
| hir
::BiLe
| hir
::BiGt
| hir
::BiGe
=> {
644 let cmp
= base
::bin_op_to_fcmp_predicate(b
.node
);
645 ConstFCmp(cmp
, te1
, te2
)
647 let cmp
= base
::bin_op_to_icmp_predicate(b
.node
, signed
);
648 ConstICmp(cmp
, te1
, te2
)
651 } } // unsafe { match b.node {
653 hir
::ExprUnary(u
, ref inner_e
) => {
654 let (te
, ty
) = const_expr(cx
, &inner_e
, param_substs
, fn_args
, trueconst
)?
;
656 check_unary_expr_validity(cx
, e
, ty
, te
, trueconst
)?
;
658 let is_float
= ty
.is_fp();
660 hir
::UnDeref
=> const_deref(cx
, te
, ty
).0,
661 hir
::UnNot
=> llvm
::LLVMConstNot(te
),
662 hir
::UnNeg
if is_float
=> llvm
::LLVMConstFNeg(te
),
663 hir
::UnNeg
=> llvm
::LLVMConstNeg(te
),
666 hir
::ExprField(ref base
, field
) => {
667 let (bv
, bt
) = const_expr(cx
, &base
, param_substs
, fn_args
, trueconst
)?
;
668 let brepr
= adt
::represent_type(cx
, bt
);
669 let vinfo
= VariantInfo
::from_ty(cx
.tcx(), bt
, None
);
670 let ix
= vinfo
.field_index(field
.node
);
671 adt
::const_get_field(&brepr
, bv
, vinfo
.discr
, ix
)
673 hir
::ExprTupField(ref base
, idx
) => {
674 let (bv
, bt
) = const_expr(cx
, &base
, param_substs
, fn_args
, trueconst
)?
;
675 let brepr
= adt
::represent_type(cx
, bt
);
676 let vinfo
= VariantInfo
::from_ty(cx
.tcx(), bt
, None
);
677 adt
::const_get_field(&brepr
, bv
, vinfo
.discr
, idx
.node
)
679 hir
::ExprIndex(ref base
, ref index
) => {
680 let (bv
, bt
) = const_expr(cx
, &base
, param_substs
, fn_args
, trueconst
)?
;
681 let iv
= const_expr(cx
, &index
, param_substs
, fn_args
, TrueConst
::Yes
)?
.0;
682 let iv
= if let Some(iv
) = const_to_opt_uint(iv
) {
685 span_bug
!(index
.span
, "index is not an integer-constant expression");
687 let (arr
, len
) = match bt
.sty
{
688 ty
::TyArray(_
, u
) => (bv
, C_uint(cx
, u
)),
689 ty
::TySlice(..) | ty
::TyStr
=> {
690 let e1
= const_get_elt(bv
, &[0]);
691 (load_const(cx
, e1
, bt
), const_get_elt(bv
, &[1]))
693 ty
::TyRef(_
, mt
) => match mt
.ty
.sty
{
694 ty
::TyArray(_
, u
) => {
695 (load_const(cx
, bv
, mt
.ty
), C_uint(cx
, u
))
697 _
=> span_bug
!(base
.span
,
698 "index-expr base must be a vector \
699 or string type, found {:?}",
702 _
=> span_bug
!(base
.span
,
703 "index-expr base must be a vector \
704 or string type, found {:?}",
708 let len
= unsafe { llvm::LLVMConstIntGetZExtValue(len) as u64 }
;
709 let len
= match bt
.sty
{
710 ty
::TyBox(ty
) | ty
::TyRef(_
, ty
::TypeAndMut{ty, ..}
) => match ty
.sty
{
720 // FIXME #3170: report this earlier on in the const-eval
721 // pass. Reporting here is a bit late.
722 span_err
!(cx
.sess(), e
.span
, E0515
,
723 "const index-expr is out of bounds");
724 C_undef(val_ty(arr
).element_type())
726 const_get_elt(arr
, &[iv
as c_uint
])
729 hir
::ExprCast(ref base
, _
) => {
731 let llty
= type_of
::type_of(cx
, t_cast
);
732 let (v
, t_expr
) = const_expr(cx
, &base
, param_substs
, fn_args
, trueconst
)?
;
733 debug
!("trans_const_cast({:?} as {:?})", t_expr
, t_cast
);
734 if expr
::cast_is_noop(cx
.tcx(), base
, t_expr
, t_cast
) {
737 if type_is_fat_ptr(cx
.tcx(), t_expr
) {
738 // Fat pointer casts.
740 t_cast
.builtin_deref(true, ty
::NoPreference
).expect("cast to non-pointer").ty
;
741 let ptr_ty
= type_of
::in_memory_type_of(cx
, t_cast_inner
).ptr_to();
742 let addr
= ptrcast(const_get_elt(v
, &[abi
::FAT_PTR_ADDR
as u32]),
744 if type_is_fat_ptr(cx
.tcx(), t_cast
) {
745 let info
= const_get_elt(v
, &[abi
::FAT_PTR_EXTRA
as u32]);
746 return Ok(C_struct(cx
, &[addr
, info
], false))
752 CastTy
::from_ty(t_expr
).expect("bad input type for cast"),
753 CastTy
::from_ty(t_cast
).expect("bad output type for cast"),
755 (CastTy
::Int(IntTy
::CEnum
), CastTy
::Int(_
)) => {
756 let repr
= adt
::represent_type(cx
, t_expr
);
757 let discr
= adt
::const_get_discrim(&repr
, v
);
758 let iv
= C_integral(cx
.int_type(), discr
.0, false);
759 let s
= adt
::is_discr_signed(&repr
) as Bool
;
760 llvm
::LLVMConstIntCast(iv
, llty
.to_ref(), s
)
762 (CastTy
::Int(_
), CastTy
::Int(_
)) => {
763 let s
= t_expr
.is_signed() as Bool
;
764 llvm
::LLVMConstIntCast(v
, llty
.to_ref(), s
)
766 (CastTy
::Int(_
), CastTy
::Float
) => {
767 if t_expr
.is_signed() {
768 llvm
::LLVMConstSIToFP(v
, llty
.to_ref())
770 llvm
::LLVMConstUIToFP(v
, llty
.to_ref())
773 (CastTy
::Float
, CastTy
::Float
) => llvm
::LLVMConstFPCast(v
, llty
.to_ref()),
774 (CastTy
::Float
, CastTy
::Int(IntTy
::I
)) => llvm
::LLVMConstFPToSI(v
, llty
.to_ref()),
775 (CastTy
::Float
, CastTy
::Int(_
)) => llvm
::LLVMConstFPToUI(v
, llty
.to_ref()),
776 (CastTy
::Ptr(_
), CastTy
::Ptr(_
)) | (CastTy
::FnPtr
, CastTy
::Ptr(_
))
777 | (CastTy
::RPtr(_
), CastTy
::Ptr(_
)) => {
780 (CastTy
::FnPtr
, CastTy
::FnPtr
) => ptrcast(v
, llty
), // isn't this a coercion?
781 (CastTy
::Int(_
), CastTy
::Ptr(_
)) => llvm
::LLVMConstIntToPtr(v
, llty
.to_ref()),
782 (CastTy
::Ptr(_
), CastTy
::Int(_
)) | (CastTy
::FnPtr
, CastTy
::Int(_
)) => {
783 llvm
::LLVMConstPtrToInt(v
, llty
.to_ref())
786 span_bug
!(e
.span
, "bad combination of types for cast")
788 } } // unsafe { match ( ... ) {
790 hir
::ExprAddrOf(hir
::MutImmutable
, ref sub
) => {
791 // If this is the address of some static, then we need to return
792 // the actual address of the static itself (short circuit the rest
797 hir
::ExprBlock(ref blk
) => {
798 if let Some(ref sub
) = blk
.expr
{
807 let opt_def
= cx
.tcx().def_map
.borrow().get(&cur
.id
).map(|d
| d
.full_def());
808 if let Some(Def
::Static(def_id
, _
)) = opt_def
{
809 get_static(cx
, def_id
).val
811 // If this isn't the address of a static, then keep going through
812 // normal constant evaluation.
813 let (v
, ty
) = const_expr(cx
, &sub
, param_substs
, fn_args
, trueconst
)?
;
814 addr_of(cx
, v
, type_of
::align_of(cx
, ty
), "ref")
817 hir
::ExprAddrOf(hir
::MutMutable
, ref sub
) => {
818 let (v
, ty
) = const_expr(cx
, &sub
, param_substs
, fn_args
, trueconst
)?
;
819 addr_of_mut(cx
, v
, type_of
::align_of(cx
, ty
), "ref_mut_slice")
821 hir
::ExprTup(ref es
) => {
822 let repr
= adt
::represent_type(cx
, ety
);
823 let vals
= map_list(&es
[..])?
;
824 adt
::trans_const(cx
, &repr
, Disr(0), &vals
[..])
826 hir
::ExprStruct(_
, ref fs
, ref base_opt
) => {
827 let repr
= adt
::represent_type(cx
, ety
);
829 let base_val
= match *base_opt
{
830 Some(ref base
) => Some(const_expr(
840 let VariantInfo { discr, fields }
= VariantInfo
::of_node(cx
.tcx(), ety
, e
.id
);
841 let cs
= fields
.iter().enumerate().map(|(ix
, &Field(f_name
, _
))| {
842 match (fs
.iter().find(|f
| f_name
== f
.name
.node
), base_val
) {
843 (Some(ref f
), _
) => {
844 const_expr(cx
, &f
.expr
, param_substs
, fn_args
, trueconst
).map(|(l
, _
)| l
)
846 (_
, Some((bv
, _
))) => Ok(adt
::const_get_field(&repr
, bv
, discr
, ix
)),
847 (_
, None
) => span_bug
!(e
.span
, "missing struct field"),
850 .collect
::<Vec
<Result
<_
, ConstEvalFailure
>>>()
852 .collect
::<Result
<Vec
<_
>,ConstEvalFailure
>>();
857 adt
::trans_const(cx
, &repr
, discr
, &cs
[..])
860 hir
::ExprVec(ref es
) => {
861 let unit_ty
= ety
.sequence_element_type(cx
.tcx());
862 let llunitty
= type_of
::type_of(cx
, unit_ty
);
871 .collect
::<Vec
<Result
<_
, ConstEvalFailure
>>>()
873 .collect
::<Result
<Vec
<_
>, ConstEvalFailure
>>();
875 // If the vector contains enums, an LLVM array won't work.
876 if vs
.iter().any(|vi
| val_ty(*vi
) != llunitty
) {
877 C_struct(cx
, &vs
[..], false)
879 C_array(llunitty
, &vs
[..])
882 hir
::ExprRepeat(ref elem
, ref count
) => {
883 let unit_ty
= ety
.sequence_element_type(cx
.tcx());
884 let llunitty
= type_of
::type_of(cx
, unit_ty
);
885 let n
= eval_repeat_count(cx
.tcx(), count
);
886 let unit_val
= const_expr(cx
, &elem
, param_substs
, fn_args
, trueconst
)?
.0;
887 let vs
= vec
![unit_val
; n
];
888 if val_ty(unit_val
) != llunitty
{
889 C_struct(cx
, &vs
[..], false)
891 C_array(llunitty
, &vs
[..])
894 hir
::ExprPath(..) => {
895 let def
= cx
.tcx().def_map
.borrow().get(&e
.id
).unwrap().full_def();
897 Def
::Local(_
, id
) => {
898 if let Some(val
) = fn_args
.and_then(|args
| args
.get(&id
).cloned()) {
901 span_bug
!(e
.span
, "const fn argument not found")
904 Def
::Fn(..) | Def
::Method(..) => C_nil(cx
),
905 Def
::Const(def_id
) | Def
::AssociatedConst(def_id
) => {
906 load_const(cx
, get_const_val(cx
, def_id
, e
, param_substs
)?
,
909 Def
::Variant(enum_did
, variant_did
) => {
910 let vinfo
= cx
.tcx().lookup_adt_def(enum_did
).variant_with_id(variant_did
);
912 ty
::VariantKind
::Unit
=> {
913 let repr
= adt
::represent_type(cx
, ety
);
914 adt
::trans_const(cx
, &repr
, Disr
::from(vinfo
.disr_val
), &[])
916 ty
::VariantKind
::Tuple
=> C_nil(cx
),
917 ty
::VariantKind
::Struct
=> {
918 span_bug
!(e
.span
, "path-expr refers to a dict variant!")
922 // Unit struct or ctor.
923 Def
::Struct(..) => C_null(type_of
::type_of(cx
, ety
)),
925 span_bug
!(e
.span
, "expected a const, fn, struct, \
930 hir
::ExprCall(ref callee
, ref args
) => {
931 let mut callee
= &**callee
;
933 callee
= match callee
.node
{
934 hir
::ExprBlock(ref block
) => match block
.expr
{
935 Some(ref tail
) => &tail
,
941 let def
= cx
.tcx().def_map
.borrow()[&callee
.id
].full_def();
942 let arg_vals
= map_list(args
)?
;
944 Def
::Fn(did
) | Def
::Method(did
) => {
948 cx
.tcx().node_id_item_substs(callee
.id
).substs
,
956 C_vector(&arg_vals
[..])
958 let repr
= adt
::represent_type(cx
, ety
);
959 adt
::trans_const(cx
, &repr
, Disr(0), &arg_vals
[..])
962 Def
::Variant(enum_did
, variant_did
) => {
963 let repr
= adt
::represent_type(cx
, ety
);
964 let vinfo
= cx
.tcx().lookup_adt_def(enum_did
).variant_with_id(variant_did
);
967 Disr
::from(vinfo
.disr_val
),
970 _
=> span_bug
!(e
.span
, "expected a struct, variant, or const fn def"),
973 hir
::ExprMethodCall(_
, _
, ref args
) => {
974 let arg_vals
= map_list(args
)?
;
975 let method_call
= ty
::MethodCall
::expr(e
.id
);
976 let method
= cx
.tcx().tables
.borrow().method_map
[&method_call
];
977 const_fn_call(cx
, method
.def_id
, method
.substs
.clone(),
978 &arg_vals
, param_substs
, trueconst
)?
980 hir
::ExprType(ref e
, _
) => const_expr(cx
, &e
, param_substs
, fn_args
, trueconst
)?
.0,
981 hir
::ExprBlock(ref block
) => {
983 Some(ref expr
) => const_expr(
993 hir
::ExprClosure(_
, ref decl
, ref body
) => {
995 ty
::TyClosure(def_id
, ref substs
) => {
996 closure
::trans_closure_expr(closure
::Dest
::Ignore(cx
),
1006 "bad type for closure expr: {:?}", ety
)
1008 C_null(type_of
::type_of(cx
, ety
))
1010 _
=> span_bug
!(e
.span
,
1011 "bad constant expression type in consts::const_expr"),
1015 pub fn get_static
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>, def_id
: DefId
)
1016 -> Datum
<'tcx
, Lvalue
> {
1017 let ty
= ccx
.tcx().lookup_item_type(def_id
).ty
;
1019 let instance
= Instance
::mono(ccx
.tcx(), def_id
);
1020 if let Some(&g
) = ccx
.instances().borrow().get(&instance
) {
1021 return Datum
::new(g
, ty
, Lvalue
::new("static"));
1024 let g
= if let Some(id
) = ccx
.tcx().map
.as_local_node_id(def_id
) {
1025 let llty
= type_of
::type_of(ccx
, ty
);
1026 match ccx
.tcx().map
.get(id
) {
1027 hir_map
::NodeItem(&hir
::Item
{
1028 ref attrs
, span
, node
: hir
::ItemStatic(..), ..
1030 // If this static came from an external crate, then
1031 // we need to get the symbol from metadata instead of
1032 // using the current crate's name/version
1033 // information in the hash of the symbol
1034 let sym
= exported_name(ccx
, instance
, attrs
);
1035 debug
!("making {}", sym
);
1037 // Create the global before evaluating the initializer;
1038 // this is necessary to allow recursive statics.
1039 let g
= declare
::define_global(ccx
, &sym
, llty
).unwrap_or_else(|| {
1040 ccx
.sess().span_fatal(span
,
1041 &format
!("symbol `{}` is already defined", sym
))
1044 ccx
.item_symbols().borrow_mut().insert(id
, sym
);
1048 hir_map
::NodeForeignItem(&hir
::ForeignItem
{
1049 ref attrs
, name
, span
, node
: hir
::ForeignItemStatic(..), ..
1051 let ident
= imported_name(name
, attrs
);
1052 let g
= if let Some(name
) =
1053 attr
::first_attr_value_str_by_name(&attrs
, "linkage") {
1054 // If this is a static with a linkage specified, then we need to handle
1055 // it a little specially. The typesystem prevents things like &T and
1056 // extern "C" fn() from being non-null, so we can't just declare a
1057 // static and call it a day. Some linkages (like weak) will make it such
1058 // that the static actually has a null value.
1059 let linkage
= match base
::llvm_linkage_by_name(&name
) {
1060 Some(linkage
) => linkage
,
1062 ccx
.sess().span_fatal(span
, "invalid linkage specified");
1065 let llty2
= match ty
.sty
{
1066 ty
::TyRawPtr(ref mt
) => type_of
::type_of(ccx
, mt
.ty
),
1068 ccx
.sess().span_fatal(span
, "must have type `*const T` or `*mut T`");
1072 // Declare a symbol `foo` with the desired linkage.
1073 let g1
= declare
::declare_global(ccx
, &ident
, llty2
);
1074 llvm
::SetLinkage(g1
, linkage
);
1076 // Declare an internal global `extern_with_linkage_foo` which
1077 // is initialized with the address of `foo`. If `foo` is
1078 // discarded during linking (for example, if `foo` has weak
1079 // linkage and there are no definitions), then
1080 // `extern_with_linkage_foo` will instead be initialized to
1082 let mut real_name
= "_rust_extern_with_linkage_".to_string();
1083 real_name
.push_str(&ident
);
1084 let g2
= declare
::define_global(ccx
, &real_name
, llty
).unwrap_or_else(||{
1085 ccx
.sess().span_fatal(span
,
1086 &format
!("symbol `{}` is already defined", ident
))
1088 llvm
::SetLinkage(g2
, llvm
::InternalLinkage
);
1089 llvm
::LLVMSetInitializer(g2
, g1
);
1093 // Generate an external declaration.
1094 declare
::declare_global(ccx
, &ident
, llty
)
1098 if attr
.check_name("thread_local") {
1099 llvm
::set_thread_local(g
, true);
1106 item
=> bug
!("get_static: expected static, found {:?}", item
)
1109 // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
1110 // FIXME(nagisa): investigate whether it can be changed into define_global
1111 let name
= ccx
.sess().cstore
.item_symbol(def_id
);
1112 let g
= declare
::declare_global(ccx
, &name
, type_of
::type_of(ccx
, ty
));
1113 // Thread-local statics in some other crate need to *always* be linked
1114 // against in a thread-local fashion, so we need to be sure to apply the
1115 // thread-local attribute locally if it was present remotely. If we
1116 // don't do this then linker errors can be generated where the linker
1117 // complains that one object files has a thread local version of the
1118 // symbol and another one doesn't.
1119 for attr
in ccx
.tcx().get_attrs(def_id
).iter() {
1120 if attr
.check_name("thread_local") {
1121 llvm
::set_thread_local(g
, true);
1124 if ccx
.use_dll_storage_attrs() {
1125 llvm
::SetDLLStorageClass(g
, llvm
::DLLImportStorageClass
);
1130 ccx
.instances().borrow_mut().insert(instance
, g
);
1131 Datum
::new(g
, ty
, Lvalue
::new("static"))
1134 pub fn trans_static(ccx
: &CrateContext
,
1138 attrs
: &[ast
::Attribute
])
1139 -> Result
<ValueRef
, ConstEvalErr
> {
1141 if collector
::collecting_debug_information(ccx
) {
1142 ccx
.record_translation_item_as_generated(TransItem
::Static(id
));
1146 let _icx
= push_ctxt("trans_static");
1147 let def_id
= ccx
.tcx().map
.local_def_id(id
);
1148 let datum
= get_static(ccx
, def_id
);
1150 let empty_substs
= ccx
.tcx().mk_substs(Substs
::empty());
1151 let (v
, _
) = const_expr(
1157 ).map_err(|e
| e
.into_inner())?
;
1159 // boolean SSA values are i1, but they have to be stored in i8 slots,
1160 // otherwise some LLVM optimization passes don't work as expected
1161 let mut val_llty
= val_ty(v
);
1162 let v
= if val_llty
== Type
::i1(ccx
) {
1163 val_llty
= Type
::i8(ccx
);
1164 llvm
::LLVMConstZExt(v
, val_llty
.to_ref())
1169 let llty
= type_of
::type_of(ccx
, datum
.ty
);
1170 let g
= if val_llty
== llty
{
1173 // If we created the global with the wrong type,
1174 // correct the type.
1175 let empty_string
= CString
::new("").unwrap();
1176 let name_str_ref
= CStr
::from_ptr(llvm
::LLVMGetValueName(datum
.val
));
1177 let name_string
= CString
::new(name_str_ref
.to_bytes()).unwrap();
1178 llvm
::LLVMSetValueName(datum
.val
, empty_string
.as_ptr());
1179 let new_g
= llvm
::LLVMGetOrInsertGlobal(
1180 ccx
.llmod(), name_string
.as_ptr(), val_llty
.to_ref());
1181 // To avoid breaking any invariants, we leave around the old
1182 // global for the moment; we'll replace all references to it
1183 // with the new global later. (See base::trans_crate.)
1184 ccx
.statics_to_rauw().borrow_mut().push((datum
.val
, new_g
));
1187 llvm
::LLVMSetAlignment(g
, type_of
::align_of(ccx
, datum
.ty
));
1188 llvm
::LLVMSetInitializer(g
, v
);
1190 // As an optimization, all shared statics which do not have interior
1191 // mutability are placed into read-only memory.
1192 if m
!= hir
::MutMutable
{
1193 let tcontents
= datum
.ty
.type_contents(ccx
.tcx());
1194 if !tcontents
.interior_unsafe() {
1195 llvm
::LLVMSetGlobalConstant(g
, llvm
::True
);
1199 debuginfo
::create_global_var_metadata(ccx
, id
, g
);
1201 if attr
::contains_name(attrs
,
1203 llvm
::set_thread_local(g
, true);