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.
14 use llvm
::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr}
;
15 use llvm
::{InternalLinkage, ValueRef, Bool, True}
;
16 use middle
::{check_const, const_eval, def}
;
17 use middle
::const_eval
::{const_int_checked_neg, const_uint_checked_neg}
;
18 use middle
::const_eval
::{const_int_checked_add, const_uint_checked_add}
;
19 use middle
::const_eval
::{const_int_checked_sub, const_uint_checked_sub}
;
20 use middle
::const_eval
::{const_int_checked_mul, const_uint_checked_mul}
;
21 use middle
::const_eval
::{const_int_checked_div, const_uint_checked_div}
;
22 use middle
::const_eval
::{const_int_checked_rem, const_uint_checked_rem}
;
23 use middle
::const_eval
::{const_int_checked_shl, const_uint_checked_shl}
;
24 use middle
::const_eval
::{const_int_checked_shr, const_uint_checked_shr}
;
25 use trans
::{adt, closure, debuginfo, expr, inline, machine}
;
26 use trans
::base
::{self, push_ctxt}
;
29 use trans
::monomorphize
;
30 use trans
::type_
::Type
;
32 use middle
::subst
::Substs
;
33 use middle
::ty
::{self, Ty}
;
34 use util
::ppaux
::{Repr, ty_to_string}
;
36 use std
::iter
::repeat
;
38 use syntax
::{ast, ast_util}
;
39 use syntax
::parse
::token
;
42 pub fn const_lit(cx
: &CrateContext
, e
: &ast
::Expr
, lit
: &ast
::Lit
)
44 let _icx
= push_ctxt("trans_lit");
45 debug
!("const_lit: {:?}", lit
);
47 ast
::LitByte(b
) => C_integral(Type
::uint_from_ty(cx
, ast
::TyU8
), b
as u64, false),
48 ast
::LitChar(i
) => C_integral(Type
::char(cx
), i
as u64, false),
49 ast
::LitInt(i
, ast
::SignedIntLit(t
, _
)) => {
50 C_integral(Type
::int_from_ty(cx
, t
), i
, true)
52 ast
::LitInt(u
, ast
::UnsignedIntLit(t
)) => {
53 C_integral(Type
::uint_from_ty(cx
, t
), u
, false)
55 ast
::LitInt(i
, ast
::UnsuffixedIntLit(_
)) => {
56 let lit_int_ty
= ty
::node_id_to_type(cx
.tcx(), e
.id
);
57 match lit_int_ty
.sty
{
59 C_integral(Type
::int_from_ty(cx
, t
), i
as u64, true)
62 C_integral(Type
::uint_from_ty(cx
, t
), i
as u64, false)
64 _
=> cx
.sess().span_bug(lit
.span
,
65 &format
!("integer literal has type {} (expected int \
67 ty_to_string(cx
.tcx(), lit_int_ty
)))
70 ast
::LitFloat(ref fs
, t
) => {
71 C_floating(&fs
, Type
::float_from_ty(cx
, t
))
73 ast
::LitFloatUnsuffixed(ref fs
) => {
74 let lit_float_ty
= ty
::node_id_to_type(cx
.tcx(), e
.id
);
75 match lit_float_ty
.sty
{
77 C_floating(&fs
, Type
::float_from_ty(cx
, t
))
80 cx
.sess().span_bug(lit
.span
,
81 "floating point literal doesn't have the right type");
85 ast
::LitBool(b
) => C_bool(cx
, b
),
86 ast
::LitStr(ref s
, _
) => C_str_slice(cx
, (*s
).clone()),
87 ast
::LitBinary(ref data
) => {
88 addr_of(cx
, C_bytes(cx
, &data
[..]), "binary")
93 pub fn ptrcast(val
: ValueRef
, ty
: Type
) -> ValueRef
{
95 llvm
::LLVMConstPointerCast(val
, ty
.to_ref())
99 fn addr_of_mut(ccx
: &CrateContext
,
104 // FIXME: this totally needs a better name generation scheme, perhaps a simple global
105 // counter? Also most other uses of gensym in trans.
106 let gsym
= token
::gensym("_");
107 let name
= format
!("{}{}", kind
, gsym
.usize());
108 let gv
= declare
::define_global(ccx
, &name
[..], val_ty(cv
)).unwrap_or_else(||{
109 ccx
.sess().bug(&format
!("symbol `{}` is already defined", name
));
111 llvm
::LLVMSetInitializer(gv
, cv
);
112 SetLinkage(gv
, InternalLinkage
);
113 SetUnnamedAddr(gv
, true);
118 pub fn addr_of(ccx
: &CrateContext
,
122 match ccx
.const_globals().borrow().get(&cv
) {
123 Some(&gv
) => return gv
,
126 let gv
= addr_of_mut(ccx
, cv
, kind
);
128 llvm
::LLVMSetGlobalConstant(gv
, True
);
130 ccx
.const_globals().borrow_mut().insert(cv
, gv
);
134 fn const_deref_ptr(cx
: &CrateContext
, v
: ValueRef
) -> ValueRef
{
135 let v
= match cx
.const_unsized().borrow().get(&v
) {
140 llvm
::LLVMGetInitializer(v
)
144 fn const_deref
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
147 -> (ValueRef
, Ty
<'tcx
>) {
148 match ty
::deref(ty
, true) {
150 if type_is_sized(cx
.tcx(), mt
.ty
) {
151 (const_deref_ptr(cx
, v
), mt
.ty
)
153 // Derefing a fat pointer does not change the representation,
154 // just the type to the unsized contents.
159 cx
.sess().bug(&format
!("unexpected dereferenceable type {}",
160 ty_to_string(cx
.tcx(), ty
)))
165 pub fn get_const_expr
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
167 ref_expr
: &ast
::Expr
)
169 let def_id
= inline
::maybe_instantiate_inline(ccx
, def_id
);
171 if def_id
.krate
!= ast
::LOCAL_CRATE
{
172 ccx
.sess().span_bug(ref_expr
.span
,
173 "cross crate constant could not be inlined");
176 let item
= ccx
.tcx().map
.expect_item(def_id
.node
);
177 if let ast
::ItemConst(_
, ref expr
) = item
.node
{
180 ccx
.sess().span_bug(ref_expr
.span
,
181 &format
!("get_const_expr given non-constant item {}",
182 item
.repr(ccx
.tcx())));
186 fn get_const_val(ccx
: &CrateContext
,
188 ref_expr
: &ast
::Expr
) -> ValueRef
{
189 let expr
= get_const_expr(ccx
, def_id
, ref_expr
);
190 let empty_substs
= ccx
.tcx().mk_substs(Substs
::trans_empty());
191 get_const_expr_as_global(ccx
, expr
, check_const
::PURE_CONST
, empty_substs
)
194 pub fn get_const_expr_as_global
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
196 qualif
: check_const
::ConstQualif
,
197 param_substs
: &'tcx Substs
<'tcx
>)
199 // Special-case constants to cache a common global for all uses.
201 ast
::ExprPath(..) => {
202 let def
= ccx
.tcx().def_map
.borrow().get(&expr
.id
).unwrap().full_def();
204 def
::DefConst(def_id
) => {
205 if !ccx
.tcx().adjustments
.borrow().contains_key(&expr
.id
) {
206 return get_const_val(ccx
, def_id
, expr
);
215 let key
= (expr
.id
, param_substs
);
216 match ccx
.const_values().borrow().get(&key
) {
217 Some(&val
) => return val
,
220 let val
= if qualif
.intersects(check_const
::NON_STATIC_BORROWS
) {
221 // Avoid autorefs as they would create global instead of stack
222 // references, even when only the latter are correct.
223 let ty
= monomorphize
::apply_param_substs(ccx
.tcx(), param_substs
,
224 &ty
::expr_ty(ccx
.tcx(), expr
));
225 const_expr_unadjusted(ccx
, expr
, ty
, param_substs
)
227 const_expr(ccx
, expr
, param_substs
).0
230 // boolean SSA values are i1, but they have to be stored in i8 slots,
231 // otherwise some LLVM optimization passes don't work as expected
233 if llvm
::LLVMTypeOf(val
) == Type
::i1(ccx
).to_ref() {
234 llvm
::LLVMConstZExt(val
, Type
::i8(ccx
).to_ref())
240 let lvalue
= addr_of(ccx
, val
, "const");
241 ccx
.const_values().borrow_mut().insert(key
, lvalue
);
245 pub fn const_expr
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
247 param_substs
: &'tcx Substs
<'tcx
>)
248 -> (ValueRef
, Ty
<'tcx
>) {
249 let ety
= monomorphize
::apply_param_substs(cx
.tcx(), param_substs
,
250 &ty
::expr_ty(cx
.tcx(), e
));
251 let llconst
= const_expr_unadjusted(cx
, e
, ety
, param_substs
);
252 let mut llconst
= llconst
;
253 let mut ety_adjusted
= monomorphize
::apply_param_substs(cx
.tcx(), param_substs
,
254 &ty
::expr_ty_adjusted(cx
.tcx(), e
));
255 let opt_adj
= cx
.tcx().adjustments
.borrow().get(&e
.id
).cloned();
257 Some(ty
::AdjustReifyFnPointer
) => {
258 // FIXME(#19925) once fn item types are
259 // zero-sized, we'll need to do something here
261 Some(ty
::AdjustUnsafeFnPointer
) => {
262 // purely a type-level thing
264 Some(ty
::AdjustDerefRef(adj
)) => {
266 // Save the last autoderef in case we can avoid it.
267 if adj
.autoderefs
> 0 {
268 for _
in 0..adj
.autoderefs
-1 {
269 let (dv
, dt
) = const_deref(cx
, llconst
, ty
);
275 if adj
.autoref
.is_some() {
276 if adj
.autoderefs
== 0 {
277 // Don't copy data to do a deref+ref
278 // (i.e., skip the last auto-deref).
279 llconst
= addr_of(cx
, llconst
, "autoref");
280 ty
= ty
::mk_imm_rptr(cx
.tcx(), cx
.tcx().mk_region(ty
::ReStatic
), ty
);
283 let (dv
, dt
) = const_deref(cx
, llconst
, ty
);
286 // If we derefed a fat pointer then we will have an
287 // open type here. So we need to update the type with
288 // the one returned from const_deref.
292 if let Some(target
) = adj
.unsize
{
293 let target
= monomorphize
::apply_param_substs(cx
.tcx(),
297 let pointee_ty
= ty
::deref(ty
, true)
298 .expect("consts: unsizing got non-pointer type").ty
;
299 let (base
, old_info
) = if !type_is_sized(cx
.tcx(), pointee_ty
) {
300 // Normally, the source is a thin pointer and we are
301 // adding extra info to make a fat pointer. The exception
302 // is when we are upcasting an existing object fat pointer
303 // to use a different vtable. In that case, we want to
304 // load out the original data pointer so we can repackage
306 (const_get_elt(cx
, llconst
, &[abi
::FAT_PTR_ADDR
as u32]),
307 Some(const_get_elt(cx
, llconst
, &[abi
::FAT_PTR_EXTRA
as u32])))
312 let unsized_ty
= ty
::deref(target
, true)
313 .expect("consts: unsizing got non-pointer target type").ty
;
314 let ptr_ty
= type_of
::in_memory_type_of(cx
, unsized_ty
).ptr_to();
315 let base
= ptrcast(base
, ptr_ty
);
316 let info
= expr
::unsized_info(cx
, pointee_ty
, unsized_ty
,
317 old_info
, param_substs
);
319 let prev_const
= cx
.const_unsized().borrow_mut()
320 .insert(base
, llconst
);
321 assert
!(prev_const
.is_none() || prev_const
== Some(llconst
));
322 assert_eq
!(abi
::FAT_PTR_ADDR
, 0);
323 assert_eq
!(abi
::FAT_PTR_EXTRA
, 1);
324 llconst
= C_struct(cx
, &[base
, info
], false);
330 let llty
= type_of
::sizing_type_of(cx
, ety_adjusted
);
331 let csize
= machine
::llsize_of_alloc(cx
, val_ty(llconst
));
332 let tsize
= machine
::llsize_of_alloc(cx
, llty
);
334 cx
.sess().abort_if_errors();
336 // FIXME these values could use some context
337 llvm
::LLVMDumpValue(llconst
);
338 llvm
::LLVMDumpValue(C_undef(llty
));
340 cx
.sess().bug(&format
!("const {} of type {} has size {} instead of {}",
341 e
.repr(cx
.tcx()), ty_to_string(cx
.tcx(), ety_adjusted
),
344 (llconst
, ety_adjusted
)
347 fn check_unary_expr_validity(cx
: &CrateContext
, e
: &ast
::Expr
, t
: Ty
,
349 // The only kind of unary expression that we check for validity
350 // here is `-expr`, to check if it "overflows" (e.g. `-i32::MIN`).
351 if let ast
::ExprUnary(ast
::UnNeg
, ref inner_e
) = e
.node
{
353 // An unfortunate special case: we parse e.g. -128 as a
354 // negation of the literal 128, which means if we're expecting
355 // a i8 (or if it was already suffixed, e.g. `-128_i8`), then
356 // 128 will have already overflowed to -128, and so then the
357 // constant evaluator thinks we're trying to negate -128.
359 // Catch this up front by looking for ExprLit directly,
360 // and just accepting it.
361 if let ast
::ExprLit(_
) = inner_e
.node { return; }
363 let result
= match t
.sty
{
364 ty
::ty_int(int_type
) => {
365 let input
= match const_to_opt_int(te
) {
369 const_int_checked_neg(
370 input
, e
, Some(const_eval
::IntTy
::from(cx
.tcx(), int_type
)))
372 ty
::ty_uint(uint_type
) => {
373 let input
= match const_to_opt_uint(te
) {
377 const_uint_checked_neg(
378 input
, e
, Some(const_eval
::UintTy
::from(cx
.tcx(), uint_type
)))
383 // We do not actually care about a successful result.
384 if let Err(err
) = result
{
385 cx
.tcx().sess
.span_err(e
.span
, &err
.description());
390 fn check_binary_expr_validity(cx
: &CrateContext
, e
: &ast
::Expr
, t
: Ty
,
391 te1
: ValueRef
, te2
: ValueRef
) {
392 let b
= if let ast
::ExprBinary(b
, _
, _
) = e
.node { b }
else { return }
;
394 let result
= match t
.sty
{
395 ty
::ty_int(int_type
) => {
396 let (lhs
, rhs
) = match (const_to_opt_int(te1
),
397 const_to_opt_int(te2
)) {
398 (Some(v1
), Some(v2
)) => (v1
, v2
),
402 let opt_ety
= Some(const_eval
::IntTy
::from(cx
.tcx(), int_type
));
404 ast
::BiAdd
=> const_int_checked_add(lhs
, rhs
, e
, opt_ety
),
405 ast
::BiSub
=> const_int_checked_sub(lhs
, rhs
, e
, opt_ety
),
406 ast
::BiMul
=> const_int_checked_mul(lhs
, rhs
, e
, opt_ety
),
407 ast
::BiDiv
=> const_int_checked_div(lhs
, rhs
, e
, opt_ety
),
408 ast
::BiRem
=> const_int_checked_rem(lhs
, rhs
, e
, opt_ety
),
409 ast
::BiShl
=> const_int_checked_shl(lhs
, rhs
, e
, opt_ety
),
410 ast
::BiShr
=> const_int_checked_shr(lhs
, rhs
, e
, opt_ety
),
414 ty
::ty_uint(uint_type
) => {
415 let (lhs
, rhs
) = match (const_to_opt_uint(te1
),
416 const_to_opt_uint(te2
)) {
417 (Some(v1
), Some(v2
)) => (v1
, v2
),
421 let opt_ety
= Some(const_eval
::UintTy
::from(cx
.tcx(), uint_type
));
423 ast
::BiAdd
=> const_uint_checked_add(lhs
, rhs
, e
, opt_ety
),
424 ast
::BiSub
=> const_uint_checked_sub(lhs
, rhs
, e
, opt_ety
),
425 ast
::BiMul
=> const_uint_checked_mul(lhs
, rhs
, e
, opt_ety
),
426 ast
::BiDiv
=> const_uint_checked_div(lhs
, rhs
, e
, opt_ety
),
427 ast
::BiRem
=> const_uint_checked_rem(lhs
, rhs
, e
, opt_ety
),
428 ast
::BiShl
=> const_uint_checked_shl(lhs
, rhs
, e
, opt_ety
),
429 ast
::BiShr
=> const_uint_checked_shr(lhs
, rhs
, e
, opt_ety
),
435 // We do not actually care about a successful result.
436 if let Err(err
) = result
{
437 cx
.tcx().sess
.span_err(e
.span
, &err
.description());
441 fn const_expr_unadjusted
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
444 param_substs
: &'tcx Substs
<'tcx
>)
447 debug
!("const_expr_unadjusted(e={}, ety={}, param_substs={})",
450 param_substs
.repr(cx
.tcx()));
452 let map_list
= |exprs
: &[P
<ast
::Expr
>]| {
453 exprs
.iter().map(|e
| const_expr(cx
, &**e
, param_substs
).0)
454 .fold(Vec
::new(), |mut l
, val
| { l.push(val); l }
)
457 let _icx
= push_ctxt("const_expr");
459 ast
::ExprLit(ref lit
) => {
460 const_lit(cx
, e
, &**lit
)
462 ast
::ExprBinary(b
, ref e1
, ref e2
) => {
463 /* Neither type is bottom, and we expect them to be unified
464 * already, so the following is safe. */
465 let (te1
, ty
) = const_expr(cx
, &**e1
, param_substs
);
466 debug
!("const_expr_unadjusted: te1={}, ty={}",
467 cx
.tn().val_to_string(te1
),
469 let is_simd
= ty
::type_is_simd(cx
.tcx(), ty
);
470 let intype
= if is_simd
{
471 ty
::simd_type(cx
.tcx(), ty
)
475 let is_float
= ty
::type_is_fp(intype
);
476 let signed
= ty
::type_is_signed(intype
);
478 let (te2
, _
) = const_expr(cx
, &**e2
, param_substs
);
480 check_binary_expr_validity(cx
, e
, ty
, te1
, te2
);
484 if is_float { llvm::LLVMConstFAdd(te1, te2) }
485 else { llvm::LLVMConstAdd(te1, te2) }
488 if is_float { llvm::LLVMConstFSub(te1, te2) }
489 else { llvm::LLVMConstSub(te1, te2) }
492 if is_float { llvm::LLVMConstFMul(te1, te2) }
493 else { llvm::LLVMConstMul(te1, te2) }
496 if is_float { llvm::LLVMConstFDiv(te1, te2) }
497 else if signed { llvm::LLVMConstSDiv(te1, te2) }
498 else { llvm::LLVMConstUDiv(te1, te2) }
501 if is_float { llvm::LLVMConstFRem(te1, te2) }
502 else if signed { llvm::LLVMConstSRem(te1, te2) }
503 else { llvm::LLVMConstURem(te1, te2) }
505 ast
::BiAnd
=> llvm
::LLVMConstAnd(te1
, te2
),
506 ast
::BiOr
=> llvm
::LLVMConstOr(te1
, te2
),
507 ast
::BiBitXor
=> llvm
::LLVMConstXor(te1
, te2
),
508 ast
::BiBitAnd
=> llvm
::LLVMConstAnd(te1
, te2
),
509 ast
::BiBitOr
=> llvm
::LLVMConstOr(te1
, te2
),
511 let te2
= base
::cast_shift_const_rhs(b
.node
, te1
, te2
);
512 llvm
::LLVMConstShl(te1
, te2
)
515 let te2
= base
::cast_shift_const_rhs(b
.node
, te1
, te2
);
516 if signed { llvm::LLVMConstAShr(te1, te2) }
517 else { llvm::LLVMConstLShr(te1, te2) }
519 ast
::BiEq
| ast
::BiNe
| ast
::BiLt
| ast
::BiLe
| ast
::BiGt
| ast
::BiGe
=> {
521 let cmp
= base
::bin_op_to_fcmp_predicate(cx
, b
.node
);
522 ConstFCmp(cmp
, te1
, te2
)
524 let cmp
= base
::bin_op_to_icmp_predicate(cx
, b
.node
, signed
);
525 let bool_val
= ConstICmp(cmp
, te1
, te2
);
527 // LLVM outputs an `< size x i1 >`, so we need to perform
528 // a sign extension to get the correctly sized type.
529 llvm
::LLVMConstIntCast(bool_val
, val_ty(te1
).to_ref(), True
)
537 ast
::ExprUnary(u
, ref inner_e
) => {
538 let (te
, ty
) = const_expr(cx
, &**inner_e
, param_substs
);
540 check_unary_expr_validity(cx
, e
, ty
, te
);
542 let is_float
= ty
::type_is_fp(ty
);
544 ast
::UnUniq
| ast
::UnDeref
=> {
545 const_deref(cx
, te
, ty
).0
547 ast
::UnNot
=> llvm
::LLVMConstNot(te
),
549 if is_float { llvm::LLVMConstFNeg(te) }
550 else { llvm::LLVMConstNeg(te) }
554 ast
::ExprField(ref base
, field
) => {
555 let (bv
, bt
) = const_expr(cx
, &**base
, param_substs
);
556 let brepr
= adt
::represent_type(cx
, bt
);
557 expr
::with_field_tys(cx
.tcx(), bt
, None
, |discr
, field_tys
| {
558 let ix
= ty
::field_idx_strict(cx
.tcx(), field
.node
.name
, field_tys
);
559 adt
::const_get_field(cx
, &*brepr
, bv
, discr
, ix
)
562 ast
::ExprTupField(ref base
, idx
) => {
563 let (bv
, bt
) = const_expr(cx
, &**base
, param_substs
);
564 let brepr
= adt
::represent_type(cx
, bt
);
565 expr
::with_field_tys(cx
.tcx(), bt
, None
, |discr
, _
| {
566 adt
::const_get_field(cx
, &*brepr
, bv
, discr
, idx
.node
)
570 ast
::ExprIndex(ref base
, ref index
) => {
571 let (bv
, bt
) = const_expr(cx
, &**base
, param_substs
);
572 let iv
= match const_eval
::eval_const_expr_partial(cx
.tcx(), &**index
, None
) {
573 Ok(const_eval
::const_int(i
)) => i
as u64,
574 Ok(const_eval
::const_uint(u
)) => u
,
575 _
=> cx
.sess().span_bug(index
.span
,
576 "index is not an integer-constant expression")
578 let (arr
, len
) = match bt
.sty
{
579 ty
::ty_vec(_
, Some(u
)) => (bv
, C_uint(cx
, u
)),
580 ty
::ty_vec(_
, None
) | ty
::ty_str
=> {
581 let e1
= const_get_elt(cx
, bv
, &[0]);
582 (const_deref_ptr(cx
, e1
), const_get_elt(cx
, bv
, &[1]))
584 ty
::ty_rptr(_
, mt
) => match mt
.ty
.sty
{
585 ty
::ty_vec(_
, Some(u
)) => {
586 (const_deref_ptr(cx
, bv
), C_uint(cx
, u
))
588 _
=> cx
.sess().span_bug(base
.span
,
589 &format
!("index-expr base must be a vector \
590 or string type, found {}",
591 ty_to_string(cx
.tcx(), bt
)))
593 _
=> cx
.sess().span_bug(base
.span
,
594 &format
!("index-expr base must be a vector \
595 or string type, found {}",
596 ty_to_string(cx
.tcx(), bt
)))
599 let len
= llvm
::LLVMConstIntGetZExtValue(len
) as u64;
600 let len
= match bt
.sty
{
601 ty
::ty_uniq(ty
) | ty
::ty_rptr(_
, ty
::mt{ty, ..}
) => match ty
.sty
{
611 // FIXME #3170: report this earlier on in the const-eval
612 // pass. Reporting here is a bit late.
613 cx
.sess().span_err(e
.span
,
614 "const index-expr is out of bounds");
615 C_undef(type_of
::type_of(cx
, bt
).element_type())
617 const_get_elt(cx
, arr
, &[iv
as c_uint
])
620 ast
::ExprCast(ref base
, _
) => {
621 let llty
= type_of
::type_of(cx
, ety
);
622 let (v
, basety
) = const_expr(cx
, &**base
, param_substs
);
623 if expr
::cast_is_noop(basety
, ety
) {
626 match (expr
::cast_type_kind(cx
.tcx(), basety
),
627 expr
::cast_type_kind(cx
.tcx(), ety
)) {
629 (expr
::cast_integral
, expr
::cast_integral
) => {
630 let s
= ty
::type_is_signed(basety
) as Bool
;
631 llvm
::LLVMConstIntCast(v
, llty
.to_ref(), s
)
633 (expr
::cast_integral
, expr
::cast_float
) => {
634 if ty
::type_is_signed(basety
) {
635 llvm
::LLVMConstSIToFP(v
, llty
.to_ref())
637 llvm
::LLVMConstUIToFP(v
, llty
.to_ref())
640 (expr
::cast_float
, expr
::cast_float
) => {
641 llvm
::LLVMConstFPCast(v
, llty
.to_ref())
643 (expr
::cast_float
, expr
::cast_integral
) => {
644 if ty
::type_is_signed(ety
) { llvm::LLVMConstFPToSI(v, llty.to_ref()) }
645 else { llvm::LLVMConstFPToUI(v, llty.to_ref()) }
647 (expr
::cast_enum
, expr
::cast_integral
) => {
648 let repr
= adt
::represent_type(cx
, basety
);
649 let discr
= adt
::const_get_discrim(cx
, &*repr
, v
);
650 let iv
= C_integral(cx
.int_type(), discr
, false);
651 let ety_cast
= expr
::cast_type_kind(cx
.tcx(), ety
);
653 expr
::cast_integral
=> {
654 let s
= ty
::type_is_signed(ety
) as Bool
;
655 llvm
::LLVMConstIntCast(iv
, llty
.to_ref(), s
)
657 _
=> cx
.sess().bug("enum cast destination is not \
661 (expr
::cast_pointer
, expr
::cast_pointer
) => {
664 (expr
::cast_integral
, expr
::cast_pointer
) => {
665 llvm
::LLVMConstIntToPtr(v
, llty
.to_ref())
667 (expr
::cast_pointer
, expr
::cast_integral
) => {
668 llvm
::LLVMConstPtrToInt(v
, llty
.to_ref())
671 cx
.sess().impossible_case(e
.span
,
672 "bad combination of types for cast")
676 ast
::ExprAddrOf(ast
::MutImmutable
, ref sub
) => {
677 // If this is the address of some static, then we need to return
678 // the actual address of the static itself (short circuit the rest
683 ast
::ExprParen(ref sub
) => cur
= sub
,
684 ast
::ExprBlock(ref blk
) => {
685 if let Some(ref sub
) = blk
.expr
{
694 let opt_def
= cx
.tcx().def_map
.borrow().get(&cur
.id
).map(|d
| d
.full_def());
695 if let Some(def
::DefStatic(def_id
, _
)) = opt_def
{
696 get_static_val(cx
, def_id
, ety
)
698 // If this isn't the address of a static, then keep going through
699 // normal constant evaluation.
700 let (v
, _
) = const_expr(cx
, &**sub
, param_substs
);
701 addr_of(cx
, v
, "ref")
704 ast
::ExprAddrOf(ast
::MutMutable
, ref sub
) => {
705 let (v
, _
) = const_expr(cx
, &**sub
, param_substs
);
706 addr_of_mut(cx
, v
, "ref_mut_slice")
708 ast
::ExprTup(ref es
) => {
709 let repr
= adt
::represent_type(cx
, ety
);
710 let vals
= map_list(&es
[..]);
711 adt
::trans_const(cx
, &*repr
, 0, &vals
[..])
713 ast
::ExprStruct(_
, ref fs
, ref base_opt
) => {
714 let repr
= adt
::represent_type(cx
, ety
);
716 let base_val
= match *base_opt
{
717 Some(ref base
) => Some(const_expr(cx
, &**base
, param_substs
)),
721 expr
::with_field_tys(cx
.tcx(), ety
, Some(e
.id
), |discr
, field_tys
| {
722 let cs
= field_tys
.iter().enumerate()
723 .map(|(ix
, &field_ty
)| {
724 match fs
.iter().find(|f
| field_ty
.name
== f
.ident
.node
.name
) {
725 Some(ref f
) => const_expr(cx
, &*f
.expr
, param_substs
).0,
729 adt
::const_get_field(cx
, &*repr
, bv
,
733 cx
.sess().span_bug(e
.span
,
734 "missing struct field")
739 }).collect
::<Vec
<_
>>();
740 if ty
::type_is_simd(cx
.tcx(), ety
) {
743 adt
::trans_const(cx
, &*repr
, discr
, &cs
[..])
747 ast
::ExprVec(ref es
) => {
748 let unit_ty
= ty
::sequence_element_type(cx
.tcx(), ety
);
749 let llunitty
= type_of
::type_of(cx
, unit_ty
);
750 let vs
= es
.iter().map(|e
| const_expr(cx
, &**e
, param_substs
).0)
751 .collect
::<Vec
<_
>>();
752 // If the vector contains enums, an LLVM array won't work.
753 if vs
.iter().any(|vi
| val_ty(*vi
) != llunitty
) {
754 C_struct(cx
, &vs
[..], false)
756 C_array(llunitty
, &vs
[..])
759 ast
::ExprRepeat(ref elem
, ref count
) => {
760 let unit_ty
= ty
::sequence_element_type(cx
.tcx(), ety
);
761 let llunitty
= type_of
::type_of(cx
, unit_ty
);
762 let n
= ty
::eval_repeat_count(cx
.tcx(), count
);
763 let unit_val
= const_expr(cx
, &**elem
, param_substs
).0;
764 let vs
: Vec
<_
> = repeat(unit_val
).take(n
).collect();
765 if val_ty(unit_val
) != llunitty
{
766 C_struct(cx
, &vs
[..], false)
768 C_array(llunitty
, &vs
[..])
771 ast
::ExprPath(..) => {
772 let def
= cx
.tcx().def_map
.borrow().get(&e
.id
).unwrap().full_def();
774 def
::DefFn(..) | def
::DefMethod(..) => {
775 expr
::trans_def_fn_unadjusted(cx
, e
, def
, param_substs
).val
777 def
::DefConst(def_id
) => {
778 const_deref_ptr(cx
, get_const_val(cx
, def_id
, e
))
780 def
::DefVariant(enum_did
, variant_did
, _
) => {
781 let vinfo
= ty
::enum_variant_with_id(cx
.tcx(),
784 if !vinfo
.args
.is_empty() {
786 expr
::trans_def_fn_unadjusted(cx
, e
, def
, param_substs
).val
789 let repr
= adt
::represent_type(cx
, ety
);
790 adt
::trans_const(cx
, &*repr
, vinfo
.disr_val
, &[])
793 def
::DefStruct(_
) => {
794 if let ty
::ty_bare_fn(..) = ety
.sty
{
796 expr
::trans_def_fn_unadjusted(cx
, e
, def
, param_substs
).val
799 C_null(type_of
::type_of(cx
, ety
))
803 cx
.sess().span_bug(e
.span
, "expected a const, fn, struct, \
808 ast
::ExprCall(ref callee
, ref args
) => {
809 let opt_def
= cx
.tcx().def_map
.borrow().get(&callee
.id
).map(|d
| d
.full_def());
810 let arg_vals
= map_list(&args
[..]);
812 Some(def
::DefStruct(_
)) => {
813 if ty
::type_is_simd(cx
.tcx(), ety
) {
814 C_vector(&arg_vals
[..])
816 let repr
= adt
::represent_type(cx
, ety
);
817 adt
::trans_const(cx
, &*repr
, 0, &arg_vals
[..])
820 Some(def
::DefVariant(enum_did
, variant_did
, _
)) => {
821 let repr
= adt
::represent_type(cx
, ety
);
822 let vinfo
= ty
::enum_variant_with_id(cx
.tcx(),
830 _
=> cx
.sess().span_bug(e
.span
, "expected a struct or variant def")
833 ast
::ExprParen(ref e
) => const_expr(cx
, &**e
, param_substs
).0,
834 ast
::ExprBlock(ref block
) => {
836 Some(ref expr
) => const_expr(cx
, &**expr
, param_substs
).0,
840 ast
::ExprClosure(_
, ref decl
, ref body
) => {
841 closure
::trans_closure_expr(closure
::Dest
::Ignore(cx
),
842 &**decl
, &**body
, e
.id
,
844 C_null(type_of
::type_of(cx
, ety
))
846 _
=> cx
.sess().span_bug(e
.span
,
847 "bad constant expression type in consts::const_expr")
852 pub fn trans_static(ccx
: &CrateContext
, m
: ast
::Mutability
, id
: ast
::NodeId
) -> ValueRef
{
854 let _icx
= push_ctxt("trans_static");
855 let g
= base
::get_item_val(ccx
, id
);
856 // At this point, get_item_val has already translated the
857 // constant's initializer to determine its LLVM type.
858 let v
= ccx
.static_values().borrow().get(&id
).unwrap().clone();
859 // boolean SSA values are i1, but they have to be stored in i8 slots,
860 // otherwise some LLVM optimization passes don't work as expected
861 let v
= if llvm
::LLVMTypeOf(v
) == Type
::i1(ccx
).to_ref() {
862 llvm
::LLVMConstZExt(v
, Type
::i8(ccx
).to_ref())
866 llvm
::LLVMSetInitializer(g
, v
);
868 // As an optimization, all shared statics which do not have interior
869 // mutability are placed into read-only memory.
870 if m
!= ast
::MutMutable
{
871 let node_ty
= ty
::node_id_to_type(ccx
.tcx(), id
);
872 let tcontents
= ty
::type_contents(ccx
.tcx(), node_ty
);
873 if !tcontents
.interior_unsafe() {
874 llvm
::LLVMSetGlobalConstant(g
, True
);
877 debuginfo
::create_global_var_metadata(ccx
, id
, g
);
882 fn get_static_val
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>, did
: ast
::DefId
,
883 ty
: Ty
<'tcx
>) -> ValueRef
{
884 if ast_util
::is_local(did
) { return base::get_item_val(ccx, did.node) }
885 base
::trans_external_path(ccx
, did
, ty
)