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
::const_qualif
::ConstQualif
;
17 use middle
::cstore
::LOCAL_CRATE
;
18 use middle
::const_eval
::{self, ConstVal, ConstEvalErr}
;
19 use middle
::const_eval
::{const_int_checked_neg, const_uint_checked_neg}
;
20 use middle
::const_eval
::{const_int_checked_add, const_uint_checked_add}
;
21 use middle
::const_eval
::{const_int_checked_sub, const_uint_checked_sub}
;
22 use middle
::const_eval
::{const_int_checked_mul, const_uint_checked_mul}
;
23 use middle
::const_eval
::{const_int_checked_div, const_uint_checked_div}
;
24 use middle
::const_eval
::{const_int_checked_rem, const_uint_checked_rem}
;
25 use middle
::const_eval
::{const_int_checked_shl, const_uint_checked_shl}
;
26 use middle
::const_eval
::{const_int_checked_shr, const_uint_checked_shr}
;
28 use middle
::def_id
::DefId
;
29 use trans
::{adt, closure, debuginfo, expr, inline, machine}
;
30 use trans
::base
::{self, push_ctxt}
;
31 use trans
::collector
::{self, TransItem}
;
32 use trans
::common
::{self, type_is_sized, ExprOrMethodCall, node_id_substs, C_nil, const_get_elt}
;
33 use trans
::common
::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty}
;
34 use trans
::common
::{C_struct, C_undef, const_to_opt_int, const_to_opt_uint, VariantInfo, C_uint}
;
35 use trans
::common
::{type_is_fat_ptr, Field, C_vector, C_array, C_null, ExprId, MethodCallKey}
;
37 use trans
::monomorphize
;
38 use trans
::type_
::Type
;
41 use middle
::subst
::Substs
;
42 use middle
::ty
::adjustment
::{AdjustDerefRef, AdjustReifyFnPointer}
;
43 use middle
::ty
::adjustment
::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}
;
44 use middle
::ty
::{self, Ty}
;
45 use middle
::ty
::cast
::{CastTy,IntTy}
;
46 use util
::nodemap
::NodeMap
;
50 use std
::ffi
::{CStr, CString}
;
53 use syntax
::ast
::{self, LitKind}
;
55 use syntax
::parse
::token
;
58 pub type FnArgMap
<'a
> = Option
<&'a NodeMap
<ValueRef
>>;
60 pub fn const_lit(cx
: &CrateContext
, e
: &hir
::Expr
, lit
: &ast
::Lit
)
62 let _icx
= push_ctxt("trans_lit");
63 debug
!("const_lit: {:?}", lit
);
65 LitKind
::Byte(b
) => C_integral(Type
::uint_from_ty(cx
, ast
::UintTy
::U8
), b
as u64, false),
66 LitKind
::Char(i
) => C_integral(Type
::char(cx
), i
as u64, false),
67 LitKind
::Int(i
, ast
::LitIntType
::Signed(t
)) => {
68 C_integral(Type
::int_from_ty(cx
, t
), i
, true)
70 LitKind
::Int(u
, ast
::LitIntType
::Unsigned(t
)) => {
71 C_integral(Type
::uint_from_ty(cx
, t
), u
, false)
73 LitKind
::Int(i
, ast
::LitIntType
::Unsuffixed
) => {
74 let lit_int_ty
= cx
.tcx().node_id_to_type(e
.id
);
75 match lit_int_ty
.sty
{
77 C_integral(Type
::int_from_ty(cx
, t
), i
as u64, true)
80 C_integral(Type
::uint_from_ty(cx
, t
), i
as u64, false)
82 _
=> cx
.sess().span_bug(lit
.span
,
83 &format
!("integer literal has type {:?} (expected int \
88 LitKind
::Float(ref fs
, t
) => {
89 C_floating(&fs
, Type
::float_from_ty(cx
, t
))
91 LitKind
::FloatUnsuffixed(ref fs
) => {
92 let lit_float_ty
= cx
.tcx().node_id_to_type(e
.id
);
93 match lit_float_ty
.sty
{
95 C_floating(&fs
, Type
::float_from_ty(cx
, t
))
98 cx
.sess().span_bug(lit
.span
,
99 "floating point literal doesn't have the right type");
103 LitKind
::Bool(b
) => C_bool(cx
, b
),
104 LitKind
::Str(ref s
, _
) => C_str_slice(cx
, (*s
).clone()),
105 LitKind
::ByteStr(ref data
) => {
106 addr_of(cx
, C_bytes(cx
, &data
[..]), 1, "byte_str")
111 pub fn ptrcast(val
: ValueRef
, ty
: Type
) -> ValueRef
{
113 llvm
::LLVMConstPointerCast(val
, ty
.to_ref())
117 fn addr_of_mut(ccx
: &CrateContext
,
119 align
: machine
::llalign
,
123 // FIXME: this totally needs a better name generation scheme, perhaps a simple global
124 // counter? Also most other uses of gensym in trans.
125 let gsym
= token
::gensym("_");
126 let name
= format
!("{}{}", kind
, gsym
.0);
127 let gv
= declare
::define_global(ccx
, &name
[..], val_ty(cv
)).unwrap_or_else(||{
128 ccx
.sess().bug(&format
!("symbol `{}` is already defined", name
));
130 llvm
::LLVMSetInitializer(gv
, cv
);
131 llvm
::LLVMSetAlignment(gv
, align
);
132 SetLinkage(gv
, InternalLinkage
);
133 SetUnnamedAddr(gv
, true);
138 pub fn addr_of(ccx
: &CrateContext
,
140 align
: machine
::llalign
,
143 match ccx
.const_globals().borrow().get(&cv
) {
146 // Upgrade the alignment in cases where the same constant is used with different
147 // alignment requirements
148 if align
> llvm
::LLVMGetAlignment(gv
) {
149 llvm
::LLVMSetAlignment(gv
, align
);
156 let gv
= addr_of_mut(ccx
, cv
, align
, kind
);
158 llvm
::LLVMSetGlobalConstant(gv
, True
);
160 ccx
.const_globals().borrow_mut().insert(cv
, gv
);
164 /// Deref a constant pointer
165 fn load_const(cx
: &CrateContext
, v
: ValueRef
, t
: Ty
) -> ValueRef
{
166 let v
= match cx
.const_unsized().borrow().get(&v
) {
170 let d
= unsafe { llvm::LLVMGetInitializer(v) }
;
172 unsafe { llvm::LLVMConstTrunc(d, Type::i1(cx).to_ref()) }
178 fn const_deref
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
181 -> (ValueRef
, Ty
<'tcx
>) {
182 match ty
.builtin_deref(true, ty
::NoPreference
) {
184 if type_is_sized(cx
.tcx(), mt
.ty
) {
185 (load_const(cx
, v
, mt
.ty
), mt
.ty
)
187 // Derefing a fat pointer does not change the representation,
188 // just the type to the unsized contents.
193 cx
.sess().bug(&format
!("unexpected dereferenceable type {:?}",
199 fn const_fn_call
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
200 node
: ExprOrMethodCall
,
202 arg_vals
: &[ValueRef
],
203 param_substs
: &'tcx Substs
<'tcx
>,
204 trueconst
: TrueConst
) -> Result
<ValueRef
, ConstEvalFailure
> {
205 let fn_like
= const_eval
::lookup_const_fn_by_id(ccx
.tcx(), def_id
);
206 let fn_like
= fn_like
.expect("lookup_const_fn_by_id failed in const_fn_call");
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
= ccx
.tcx().mk_substs(node_id_substs(ccx
, node
, param_substs
));
215 match fn_like
.body().expr
{
217 const_expr(ccx
, &expr
, substs
, Some(&fn_args
), trueconst
).map(|(res
, _
)| res
)
219 None
=> Ok(C_nil(ccx
)),
223 pub fn get_const_expr
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
225 ref_expr
: &hir
::Expr
,
226 param_substs
: &'tcx Substs
<'tcx
>)
228 let def_id
= inline
::maybe_instantiate_inline(ccx
, def_id
);
230 if def_id
.krate
!= LOCAL_CRATE
{
231 ccx
.sess().span_bug(ref_expr
.span
,
232 "cross crate constant could not be inlined");
235 match const_eval
::lookup_const_by_id(ccx
.tcx(), def_id
, Some(ref_expr
.id
), Some(param_substs
)) {
236 Some(ref expr
) => expr
,
238 ccx
.sess().span_bug(ref_expr
.span
, "constant item not found")
243 pub enum ConstEvalFailure
{
244 /// in case the const evaluator failed on something that panic at runtime
245 /// as defined in RFC 1229
246 Runtime(ConstEvalErr
),
247 // in case we found a true constant
248 Compiletime(ConstEvalErr
),
251 impl ConstEvalFailure
{
252 fn into_inner(self) -> ConstEvalErr
{
258 pub fn description(&self) -> Cow
<str> {
260 &Runtime(ref e
) => e
.description(),
261 &Compiletime(ref e
) => e
.description(),
266 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
271 use self::ConstEvalFailure
::*;
273 fn get_const_val
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
275 ref_expr
: &hir
::Expr
,
276 param_substs
: &'tcx Substs
<'tcx
>)
277 -> Result
<ValueRef
, ConstEvalFailure
> {
278 let expr
= get_const_expr(ccx
, def_id
, ref_expr
, param_substs
);
279 let empty_substs
= ccx
.tcx().mk_substs(Substs
::trans_empty());
280 match get_const_expr_as_global(ccx
, expr
, ConstQualif
::empty(), empty_substs
, TrueConst
::Yes
) {
281 Err(Runtime(err
)) => {
282 ccx
.tcx().sess
.span_err(expr
.span
, &err
.description());
283 Err(Compiletime(err
))
289 pub fn get_const_expr_as_global
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
292 param_substs
: &'tcx Substs
<'tcx
>,
293 trueconst
: TrueConst
)
294 -> Result
<ValueRef
, ConstEvalFailure
> {
295 debug
!("get_const_expr_as_global: {:?}", expr
.id
);
296 // Special-case constants to cache a common global for all uses.
297 if let hir
::ExprPath(..) = expr
.node
{
298 // `def` must be its own statement and cannot be in the `match`
299 // otherwise the `def_map` will be borrowed for the entire match instead
300 // of just to get the `def` value
301 let def
= ccx
.tcx().def_map
.borrow().get(&expr
.id
).unwrap().full_def();
303 Def
::Const(def_id
) | Def
::AssociatedConst(def_id
) => {
304 if !ccx
.tcx().tables
.borrow().adjustments
.contains_key(&expr
.id
) {
305 debug
!("get_const_expr_as_global ({:?}): found const {:?}",
307 return get_const_val(ccx
, def_id
, expr
, param_substs
);
314 let key
= (expr
.id
, param_substs
);
315 if let Some(&val
) = ccx
.const_values().borrow().get(&key
) {
318 let ty
= monomorphize
::apply_param_substs(ccx
.tcx(), param_substs
,
319 &ccx
.tcx().expr_ty(expr
));
320 let val
= if qualif
.intersects(ConstQualif
::NON_STATIC_BORROWS
) {
321 // Avoid autorefs as they would create global instead of stack
322 // references, even when only the latter are correct.
323 try
!(const_expr_unadjusted(ccx
, expr
, ty
, param_substs
, None
, trueconst
))
325 try
!(const_expr(ccx
, expr
, param_substs
, None
, trueconst
)).0
328 // boolean SSA values are i1, but they have to be stored in i8 slots,
329 // otherwise some LLVM optimization passes don't work as expected
331 if llvm
::LLVMTypeOf(val
) == Type
::i1(ccx
).to_ref() {
332 llvm
::LLVMConstZExt(val
, Type
::i8(ccx
).to_ref())
338 let lvalue
= addr_of(ccx
, val
, type_of
::align_of(ccx
, ty
), "const");
339 ccx
.const_values().borrow_mut().insert(key
, lvalue
);
343 pub fn const_expr
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
345 param_substs
: &'tcx Substs
<'tcx
>,
347 trueconst
: TrueConst
)
348 -> Result
<(ValueRef
, Ty
<'tcx
>), ConstEvalFailure
> {
349 let ety
= monomorphize
::apply_param_substs(cx
.tcx(), param_substs
,
350 &cx
.tcx().expr_ty(e
));
351 let llconst
= try
!(const_expr_unadjusted(cx
, e
, ety
, param_substs
, fn_args
, trueconst
));
352 let mut llconst
= llconst
;
353 let mut ety_adjusted
= monomorphize
::apply_param_substs(cx
.tcx(), param_substs
,
354 &cx
.tcx().expr_ty_adjusted(e
));
355 let opt_adj
= cx
.tcx().tables
.borrow().adjustments
.get(&e
.id
).cloned();
357 Some(AdjustReifyFnPointer
) => {
358 // FIXME(#19925) once fn item types are
359 // zero-sized, we'll need to do something here
361 Some(AdjustUnsafeFnPointer
) | Some(AdjustMutToConstPointer
) => {
362 // purely a type-level thing
364 Some(AdjustDerefRef(adj
)) => {
366 // Save the last autoderef in case we can avoid it.
367 if adj
.autoderefs
> 0 {
368 for _
in 0..adj
.autoderefs
-1 {
369 let (dv
, dt
) = const_deref(cx
, llconst
, ty
);
375 if adj
.autoref
.is_some() {
376 if adj
.autoderefs
== 0 {
377 // Don't copy data to do a deref+ref
378 // (i.e., skip the last auto-deref).
379 llconst
= addr_of(cx
, llconst
, type_of
::align_of(cx
, ty
), "autoref");
380 ty
= cx
.tcx().mk_imm_ref(cx
.tcx().mk_region(ty
::ReStatic
), ty
);
383 let (dv
, dt
) = const_deref(cx
, llconst
, ty
);
386 // If we derefed a fat pointer then we will have an
387 // open type here. So we need to update the type with
388 // the one returned from const_deref.
392 if let Some(target
) = adj
.unsize
{
393 let target
= monomorphize
::apply_param_substs(cx
.tcx(),
397 let pointee_ty
= ty
.builtin_deref(true, ty
::NoPreference
)
398 .expect("consts: unsizing got non-pointer type").ty
;
399 let (base
, old_info
) = if !type_is_sized(cx
.tcx(), pointee_ty
) {
400 // Normally, the source is a thin pointer and we are
401 // adding extra info to make a fat pointer. The exception
402 // is when we are upcasting an existing object fat pointer
403 // to use a different vtable. In that case, we want to
404 // load out the original data pointer so we can repackage
406 (const_get_elt(cx
, llconst
, &[abi
::FAT_PTR_ADDR
as u32]),
407 Some(const_get_elt(cx
, llconst
, &[abi
::FAT_PTR_EXTRA
as u32])))
412 let unsized_ty
= target
.builtin_deref(true, ty
::NoPreference
)
413 .expect("consts: unsizing got non-pointer target type").ty
;
414 let ptr_ty
= type_of
::in_memory_type_of(cx
, unsized_ty
).ptr_to();
415 let base
= ptrcast(base
, ptr_ty
);
416 let info
= base
::unsized_info(cx
, pointee_ty
, unsized_ty
,
417 old_info
, param_substs
);
419 if old_info
.is_none() {
420 let prev_const
= cx
.const_unsized().borrow_mut()
421 .insert(base
, llconst
);
422 assert
!(prev_const
.is_none() || prev_const
== Some(llconst
));
424 assert_eq
!(abi
::FAT_PTR_ADDR
, 0);
425 assert_eq
!(abi
::FAT_PTR_EXTRA
, 1);
426 llconst
= C_struct(cx
, &[base
, info
], false);
432 let llty
= type_of
::sizing_type_of(cx
, ety_adjusted
);
433 let csize
= machine
::llsize_of_alloc(cx
, val_ty(llconst
));
434 let tsize
= machine
::llsize_of_alloc(cx
, llty
);
436 cx
.sess().abort_if_errors();
438 // FIXME these values could use some context
439 llvm
::LLVMDumpValue(llconst
);
440 llvm
::LLVMDumpValue(C_undef(llty
));
442 cx
.sess().bug(&format
!("const {:?} of type {:?} has size {} instead of {}",
446 Ok((llconst
, ety_adjusted
))
449 fn check_unary_expr_validity(cx
: &CrateContext
, e
: &hir
::Expr
, t
: Ty
,
450 te
: ValueRef
, trueconst
: TrueConst
) -> Result
<(), ConstEvalFailure
> {
451 // The only kind of unary expression that we check for validity
452 // here is `-expr`, to check if it "overflows" (e.g. `-i32::MIN`).
453 if let hir
::ExprUnary(hir
::UnNeg
, ref inner_e
) = e
.node
{
455 // An unfortunate special case: we parse e.g. -128 as a
456 // negation of the literal 128, which means if we're expecting
457 // a i8 (or if it was already suffixed, e.g. `-128_i8`), then
458 // 128 will have already overflowed to -128, and so then the
459 // constant evaluator thinks we're trying to negate -128.
461 // Catch this up front by looking for ExprLit directly,
462 // and just accepting it.
463 if let hir
::ExprLit(_
) = inner_e
.node { return Ok(()); }
465 let result
= match t
.sty
{
466 ty
::TyInt(int_type
) => {
467 let input
= match const_to_opt_int(te
) {
469 None
=> return Ok(()),
471 const_int_checked_neg(
472 input
, e
, Some(const_eval
::IntTy
::from(cx
.tcx(), int_type
)))
474 ty
::TyUint(uint_type
) => {
475 let input
= match const_to_opt_uint(te
) {
477 None
=> return Ok(()),
479 const_uint_checked_neg(
480 input
, e
, Some(const_eval
::UintTy
::from(cx
.tcx(), uint_type
)))
484 const_err(cx
, e
, result
, trueconst
)
490 fn const_err(cx
: &CrateContext
,
492 result
: Result
<ConstVal
, ConstEvalErr
>,
493 trueconst
: TrueConst
)
494 -> Result
<(), ConstEvalFailure
> {
495 match (result
, trueconst
) {
497 // We do not actually care about a successful result.
500 (Err(err
), TrueConst
::Yes
) => {
501 cx
.tcx().sess
.span_err(e
.span
, &err
.description());
502 Err(Compiletime(err
))
504 (Err(err
), TrueConst
::No
) => {
505 cx
.tcx().sess
.span_warn(e
.span
, &err
.description());
511 fn check_binary_expr_validity(cx
: &CrateContext
, e
: &hir
::Expr
, t
: Ty
,
512 te1
: ValueRef
, te2
: ValueRef
,
513 trueconst
: TrueConst
) -> Result
<(), ConstEvalFailure
> {
514 let b
= if let hir
::ExprBinary(b
, _
, _
) = e
.node { b }
else { unreachable!() }
;
516 let result
= match t
.sty
{
517 ty
::TyInt(int_type
) => {
518 let (lhs
, rhs
) = match (const_to_opt_int(te1
),
519 const_to_opt_int(te2
)) {
520 (Some(v1
), Some(v2
)) => (v1
, v2
),
524 let opt_ety
= Some(const_eval
::IntTy
::from(cx
.tcx(), int_type
));
526 hir
::BiAdd
=> const_int_checked_add(lhs
, rhs
, e
, opt_ety
),
527 hir
::BiSub
=> const_int_checked_sub(lhs
, rhs
, e
, opt_ety
),
528 hir
::BiMul
=> const_int_checked_mul(lhs
, rhs
, e
, opt_ety
),
529 hir
::BiDiv
=> const_int_checked_div(lhs
, rhs
, e
, opt_ety
),
530 hir
::BiRem
=> const_int_checked_rem(lhs
, rhs
, e
, opt_ety
),
531 hir
::BiShl
=> const_int_checked_shl(lhs
, rhs
, e
, opt_ety
),
532 hir
::BiShr
=> const_int_checked_shr(lhs
, rhs
, e
, opt_ety
),
536 ty
::TyUint(uint_type
) => {
537 let (lhs
, rhs
) = match (const_to_opt_uint(te1
),
538 const_to_opt_uint(te2
)) {
539 (Some(v1
), Some(v2
)) => (v1
, v2
),
543 let opt_ety
= Some(const_eval
::UintTy
::from(cx
.tcx(), uint_type
));
545 hir
::BiAdd
=> const_uint_checked_add(lhs
, rhs
, e
, opt_ety
),
546 hir
::BiSub
=> const_uint_checked_sub(lhs
, rhs
, e
, opt_ety
),
547 hir
::BiMul
=> const_uint_checked_mul(lhs
, rhs
, e
, opt_ety
),
548 hir
::BiDiv
=> const_uint_checked_div(lhs
, rhs
, e
, opt_ety
),
549 hir
::BiRem
=> const_uint_checked_rem(lhs
, rhs
, e
, opt_ety
),
550 hir
::BiShl
=> const_uint_checked_shl(lhs
, rhs
, e
, opt_ety
),
551 hir
::BiShr
=> const_uint_checked_shr(lhs
, rhs
, e
, opt_ety
),
557 const_err(cx
, e
, result
, trueconst
)
560 fn const_expr_unadjusted
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
563 param_substs
: &'tcx Substs
<'tcx
>,
565 trueconst
: TrueConst
)
566 -> Result
<ValueRef
, ConstEvalFailure
>
568 debug
!("const_expr_unadjusted(e={:?}, ety={:?}, param_substs={:?})",
573 let map_list
= |exprs
: &[P
<hir
::Expr
>]| -> Result
<Vec
<ValueRef
>, ConstEvalFailure
> {
575 .map(|e
| const_expr(cx
, &e
, param_substs
, fn_args
, trueconst
).map(|(l
, _
)| l
))
576 .collect
::<Vec
<Result
<ValueRef
, ConstEvalFailure
>>>()
579 // this dance is necessary to eagerly run const_expr so all errors are reported
581 let _icx
= push_ctxt("const_expr");
583 hir
::ExprLit(ref lit
) => const_lit(cx
, e
, &lit
),
584 hir
::ExprBinary(b
, ref e1
, ref e2
) => {
585 /* Neither type is bottom, and we expect them to be unified
586 * already, so the following is safe. */
587 let (te1
, ty
) = try
!(const_expr(cx
, &e1
, param_substs
, fn_args
, trueconst
));
588 debug
!("const_expr_unadjusted: te1={}, ty={:?}",
589 cx
.tn().val_to_string(te1
),
591 assert
!(!ty
.is_simd());
592 let is_float
= ty
.is_fp();
593 let signed
= ty
.is_signed();
595 let (te2
, ty2
) = try
!(const_expr(cx
, &e2
, param_substs
, fn_args
, trueconst
));
596 debug
!("const_expr_unadjusted: te2={}, ty={:?}",
597 cx
.tn().val_to_string(te2
),
600 try
!(check_binary_expr_validity(cx
, e
, ty
, te1
, te2
, trueconst
));
602 unsafe { match b
.node
{
603 hir
::BiAdd
if is_float
=> llvm
::LLVMConstFAdd(te1
, te2
),
604 hir
::BiAdd
=> llvm
::LLVMConstAdd(te1
, te2
),
606 hir
::BiSub
if is_float
=> llvm
::LLVMConstFSub(te1
, te2
),
607 hir
::BiSub
=> llvm
::LLVMConstSub(te1
, te2
),
609 hir
::BiMul
if is_float
=> llvm
::LLVMConstFMul(te1
, te2
),
610 hir
::BiMul
=> llvm
::LLVMConstMul(te1
, te2
),
612 hir
::BiDiv
if is_float
=> llvm
::LLVMConstFDiv(te1
, te2
),
613 hir
::BiDiv
if signed
=> llvm
::LLVMConstSDiv(te1
, te2
),
614 hir
::BiDiv
=> llvm
::LLVMConstUDiv(te1
, te2
),
616 hir
::BiRem
if is_float
=> llvm
::LLVMConstFRem(te1
, te2
),
617 hir
::BiRem
if signed
=> llvm
::LLVMConstSRem(te1
, te2
),
618 hir
::BiRem
=> llvm
::LLVMConstURem(te1
, te2
),
620 hir
::BiAnd
=> llvm
::LLVMConstAnd(te1
, te2
),
621 hir
::BiOr
=> llvm
::LLVMConstOr(te1
, te2
),
622 hir
::BiBitXor
=> llvm
::LLVMConstXor(te1
, te2
),
623 hir
::BiBitAnd
=> llvm
::LLVMConstAnd(te1
, te2
),
624 hir
::BiBitOr
=> llvm
::LLVMConstOr(te1
, te2
),
626 let te2
= base
::cast_shift_const_rhs(b
.node
, te1
, te2
);
627 llvm
::LLVMConstShl(te1
, te2
)
630 let te2
= base
::cast_shift_const_rhs(b
.node
, te1
, te2
);
631 if signed { llvm::LLVMConstAShr(te1, te2) }
632 else { llvm::LLVMConstLShr(te1, te2) }
634 hir
::BiEq
| hir
::BiNe
| hir
::BiLt
| hir
::BiLe
| hir
::BiGt
| hir
::BiGe
=> {
636 let cmp
= base
::bin_op_to_fcmp_predicate(cx
, b
.node
);
637 ConstFCmp(cmp
, te1
, te2
)
639 let cmp
= base
::bin_op_to_icmp_predicate(cx
, b
.node
, signed
);
640 ConstICmp(cmp
, te1
, te2
)
643 } } // unsafe { match b.node {
645 hir
::ExprUnary(u
, ref inner_e
) => {
646 let (te
, ty
) = try
!(const_expr(cx
, &inner_e
, param_substs
, fn_args
, trueconst
));
648 try
!(check_unary_expr_validity(cx
, e
, ty
, te
, trueconst
));
650 let is_float
= ty
.is_fp();
652 hir
::UnDeref
=> const_deref(cx
, te
, ty
).0,
653 hir
::UnNot
=> llvm
::LLVMConstNot(te
),
654 hir
::UnNeg
if is_float
=> llvm
::LLVMConstFNeg(te
),
655 hir
::UnNeg
=> llvm
::LLVMConstNeg(te
),
658 hir
::ExprField(ref base
, field
) => {
659 let (bv
, bt
) = try
!(const_expr(cx
, &base
, param_substs
, fn_args
, trueconst
));
660 let brepr
= adt
::represent_type(cx
, bt
);
661 let vinfo
= VariantInfo
::from_ty(cx
.tcx(), bt
, None
);
662 let ix
= vinfo
.field_index(field
.node
);
663 adt
::const_get_field(cx
, &brepr
, bv
, vinfo
.discr
, ix
)
665 hir
::ExprTupField(ref base
, idx
) => {
666 let (bv
, bt
) = try
!(const_expr(cx
, &base
, param_substs
, fn_args
, trueconst
));
667 let brepr
= adt
::represent_type(cx
, bt
);
668 let vinfo
= VariantInfo
::from_ty(cx
.tcx(), bt
, None
);
669 adt
::const_get_field(cx
, &brepr
, bv
, vinfo
.discr
, idx
.node
)
671 hir
::ExprIndex(ref base
, ref index
) => {
672 let (bv
, bt
) = try
!(const_expr(cx
, &base
, param_substs
, fn_args
, trueconst
));
673 let iv
= try
!(const_expr(cx
, &index
, param_substs
, fn_args
, TrueConst
::Yes
)).0;
674 let iv
= if let Some(iv
) = const_to_opt_uint(iv
) {
677 cx
.sess().span_bug(index
.span
, "index is not an integer-constant expression");
679 let (arr
, len
) = match bt
.sty
{
680 ty
::TyArray(_
, u
) => (bv
, C_uint(cx
, u
)),
681 ty
::TySlice(..) | ty
::TyStr
=> {
682 let e1
= const_get_elt(cx
, bv
, &[0]);
683 (load_const(cx
, e1
, bt
), const_get_elt(cx
, bv
, &[1]))
685 ty
::TyRef(_
, mt
) => match mt
.ty
.sty
{
686 ty
::TyArray(_
, u
) => {
687 (load_const(cx
, bv
, mt
.ty
), C_uint(cx
, u
))
689 _
=> cx
.sess().span_bug(base
.span
,
690 &format
!("index-expr base must be a vector \
691 or string type, found {:?}",
694 _
=> cx
.sess().span_bug(base
.span
,
695 &format
!("index-expr base must be a vector \
696 or string type, found {:?}",
700 let len
= unsafe { llvm::LLVMConstIntGetZExtValue(len) as u64 }
;
701 let len
= match bt
.sty
{
702 ty
::TyBox(ty
) | ty
::TyRef(_
, ty
::TypeAndMut{ty, ..}
) => match ty
.sty
{
712 // FIXME #3170: report this earlier on in the const-eval
713 // pass. Reporting here is a bit late.
714 span_err
!(cx
.sess(), e
.span
, E0515
,
715 "const index-expr is out of bounds");
716 C_undef(val_ty(arr
).element_type())
718 const_get_elt(cx
, arr
, &[iv
as c_uint
])
721 hir
::ExprCast(ref base
, _
) => {
723 let llty
= type_of
::type_of(cx
, t_cast
);
724 let (v
, t_expr
) = try
!(const_expr(cx
, &base
, param_substs
, fn_args
, trueconst
));
725 debug
!("trans_const_cast({:?} as {:?})", t_expr
, t_cast
);
726 if expr
::cast_is_noop(cx
.tcx(), base
, t_expr
, t_cast
) {
729 if type_is_fat_ptr(cx
.tcx(), t_expr
) {
730 // Fat pointer casts.
732 t_cast
.builtin_deref(true, ty
::NoPreference
).expect("cast to non-pointer").ty
;
733 let ptr_ty
= type_of
::in_memory_type_of(cx
, t_cast_inner
).ptr_to();
734 let addr
= ptrcast(const_get_elt(cx
, v
, &[abi
::FAT_PTR_ADDR
as u32]),
736 if type_is_fat_ptr(cx
.tcx(), t_cast
) {
737 let info
= const_get_elt(cx
, v
, &[abi
::FAT_PTR_EXTRA
as u32]);
738 return Ok(C_struct(cx
, &[addr
, info
], false))
744 CastTy
::from_ty(t_expr
).expect("bad input type for cast"),
745 CastTy
::from_ty(t_cast
).expect("bad output type for cast"),
747 (CastTy
::Int(IntTy
::CEnum
), CastTy
::Int(_
)) => {
748 let repr
= adt
::represent_type(cx
, t_expr
);
749 let discr
= adt
::const_get_discrim(cx
, &repr
, v
);
750 let iv
= C_integral(cx
.int_type(), discr
.0, false);
751 let s
= adt
::is_discr_signed(&repr
) as Bool
;
752 llvm
::LLVMConstIntCast(iv
, llty
.to_ref(), s
)
754 (CastTy
::Int(_
), CastTy
::Int(_
)) => {
755 let s
= t_expr
.is_signed() as Bool
;
756 llvm
::LLVMConstIntCast(v
, llty
.to_ref(), s
)
758 (CastTy
::Int(_
), CastTy
::Float
) => {
759 if t_expr
.is_signed() {
760 llvm
::LLVMConstSIToFP(v
, llty
.to_ref())
762 llvm
::LLVMConstUIToFP(v
, llty
.to_ref())
765 (CastTy
::Float
, CastTy
::Float
) => llvm
::LLVMConstFPCast(v
, llty
.to_ref()),
766 (CastTy
::Float
, CastTy
::Int(IntTy
::I
)) => llvm
::LLVMConstFPToSI(v
, llty
.to_ref()),
767 (CastTy
::Float
, CastTy
::Int(_
)) => llvm
::LLVMConstFPToUI(v
, llty
.to_ref()),
768 (CastTy
::Ptr(_
), CastTy
::Ptr(_
)) | (CastTy
::FnPtr
, CastTy
::Ptr(_
))
769 | (CastTy
::RPtr(_
), CastTy
::Ptr(_
)) => {
772 (CastTy
::FnPtr
, CastTy
::FnPtr
) => ptrcast(v
, llty
), // isn't this a coercion?
773 (CastTy
::Int(_
), CastTy
::Ptr(_
)) => llvm
::LLVMConstIntToPtr(v
, llty
.to_ref()),
774 (CastTy
::Ptr(_
), CastTy
::Int(_
)) | (CastTy
::FnPtr
, CastTy
::Int(_
)) => {
775 llvm
::LLVMConstPtrToInt(v
, llty
.to_ref())
778 cx
.sess().impossible_case(e
.span
,
779 "bad combination of types for cast")
781 } } // unsafe { match ( ... ) {
783 hir
::ExprAddrOf(hir
::MutImmutable
, ref sub
) => {
784 // If this is the address of some static, then we need to return
785 // the actual address of the static itself (short circuit the rest
790 hir
::ExprBlock(ref blk
) => {
791 if let Some(ref sub
) = blk
.expr
{
800 let opt_def
= cx
.tcx().def_map
.borrow().get(&cur
.id
).map(|d
| d
.full_def());
801 if let Some(Def
::Static(def_id
, _
)) = opt_def
{
802 common
::get_static_val(cx
, def_id
, ety
)
804 // If this isn't the address of a static, then keep going through
805 // normal constant evaluation.
806 let (v
, ty
) = try
!(const_expr(cx
, &sub
, param_substs
, fn_args
, trueconst
));
807 addr_of(cx
, v
, type_of
::align_of(cx
, ty
), "ref")
810 hir
::ExprAddrOf(hir
::MutMutable
, ref sub
) => {
811 let (v
, ty
) = try
!(const_expr(cx
, &sub
, param_substs
, fn_args
, trueconst
));
812 addr_of_mut(cx
, v
, type_of
::align_of(cx
, ty
), "ref_mut_slice")
814 hir
::ExprTup(ref es
) => {
815 let repr
= adt
::represent_type(cx
, ety
);
816 let vals
= try
!(map_list(&es
[..]));
817 adt
::trans_const(cx
, &repr
, Disr(0), &vals
[..])
819 hir
::ExprStruct(_
, ref fs
, ref base_opt
) => {
820 let repr
= adt
::represent_type(cx
, ety
);
822 let base_val
= match *base_opt
{
823 Some(ref base
) => Some(try
!(const_expr(
833 let VariantInfo { discr, fields }
= VariantInfo
::of_node(cx
.tcx(), ety
, e
.id
);
834 let cs
= fields
.iter().enumerate().map(|(ix
, &Field(f_name
, _
))| {
835 match (fs
.iter().find(|f
| f_name
== f
.name
.node
), base_val
) {
836 (Some(ref f
), _
) => {
837 const_expr(cx
, &f
.expr
, param_substs
, fn_args
, trueconst
).map(|(l
, _
)| l
)
839 (_
, Some((bv
, _
))) => Ok(adt
::const_get_field(cx
, &repr
, bv
, discr
, ix
)),
840 (_
, None
) => cx
.sess().span_bug(e
.span
, "missing struct field"),
843 .collect
::<Vec
<Result
<_
, ConstEvalFailure
>>>()
845 .collect
::<Result
<Vec
<_
>,ConstEvalFailure
>>();
850 adt
::trans_const(cx
, &repr
, discr
, &cs
[..])
853 hir
::ExprVec(ref es
) => {
854 let unit_ty
= ety
.sequence_element_type(cx
.tcx());
855 let llunitty
= type_of
::type_of(cx
, unit_ty
);
864 .collect
::<Vec
<Result
<_
, ConstEvalFailure
>>>()
866 .collect
::<Result
<Vec
<_
>, ConstEvalFailure
>>();
868 // If the vector contains enums, an LLVM array won't work.
869 if vs
.iter().any(|vi
| val_ty(*vi
) != llunitty
) {
870 C_struct(cx
, &vs
[..], false)
872 C_array(llunitty
, &vs
[..])
875 hir
::ExprRepeat(ref elem
, ref count
) => {
876 let unit_ty
= ety
.sequence_element_type(cx
.tcx());
877 let llunitty
= type_of
::type_of(cx
, unit_ty
);
878 let n
= cx
.tcx().eval_repeat_count(count
);
879 let unit_val
= try
!(const_expr(cx
, &elem
, param_substs
, fn_args
, trueconst
)).0;
880 let vs
= vec
![unit_val
; n
];
881 if val_ty(unit_val
) != llunitty
{
882 C_struct(cx
, &vs
[..], false)
884 C_array(llunitty
, &vs
[..])
887 hir
::ExprPath(..) => {
888 let def
= cx
.tcx().def_map
.borrow().get(&e
.id
).unwrap().full_def();
890 Def
::Local(_
, id
) => {
891 if let Some(val
) = fn_args
.and_then(|args
| args
.get(&id
).cloned()) {
894 cx
.sess().span_bug(e
.span
, "const fn argument not found")
897 Def
::Fn(..) | Def
::Method(..) => {
898 expr
::trans_def_fn_unadjusted(cx
, e
, def
, param_substs
).val
900 Def
::Const(def_id
) | Def
::AssociatedConst(def_id
) => {
901 load_const(cx
, try
!(get_const_val(cx
, def_id
, e
, param_substs
)),
904 Def
::Variant(enum_did
, variant_did
) => {
905 let vinfo
= cx
.tcx().lookup_adt_def(enum_did
).variant_with_id(variant_did
);
907 ty
::VariantKind
::Unit
=> {
908 let repr
= adt
::represent_type(cx
, ety
);
909 adt
::trans_const(cx
, &repr
, Disr
::from(vinfo
.disr_val
), &[])
911 ty
::VariantKind
::Tuple
=> {
912 expr
::trans_def_fn_unadjusted(cx
, e
, def
, param_substs
).val
914 ty
::VariantKind
::Struct
=> {
915 cx
.sess().span_bug(e
.span
, "path-expr refers to a dict variant!")
920 if let ty
::TyBareFn(..) = ety
.sty
{
922 expr
::trans_def_fn_unadjusted(cx
, e
, def
, param_substs
).val
925 C_null(type_of
::type_of(cx
, ety
))
929 cx
.sess().span_bug(e
.span
, "expected a const, fn, struct, \
934 hir
::ExprCall(ref callee
, ref args
) => {
935 let mut callee
= &**callee
;
937 callee
= match callee
.node
{
938 hir
::ExprBlock(ref block
) => match block
.expr
{
939 Some(ref tail
) => &tail
,
945 let def
= cx
.tcx().def_map
.borrow()[&callee
.id
].full_def();
946 let arg_vals
= try
!(map_list(args
));
948 Def
::Fn(did
) | Def
::Method(did
) => {
960 C_vector(&arg_vals
[..])
962 let repr
= adt
::represent_type(cx
, ety
);
963 adt
::trans_const(cx
, &repr
, Disr(0), &arg_vals
[..])
966 Def
::Variant(enum_did
, variant_did
) => {
967 let repr
= adt
::represent_type(cx
, ety
);
968 let vinfo
= cx
.tcx().lookup_adt_def(enum_did
).variant_with_id(variant_did
);
971 Disr
::from(vinfo
.disr_val
),
974 _
=> cx
.sess().span_bug(e
.span
, "expected a struct, variant, or const fn def"),
977 hir
::ExprMethodCall(_
, _
, ref args
) => {
978 let arg_vals
= try
!(map_list(args
));
979 let method_call
= ty
::MethodCall
::expr(e
.id
);
980 let method_did
= cx
.tcx().tables
.borrow().method_map
[&method_call
].def_id
;
981 try
!(const_fn_call(cx
, MethodCallKey(method_call
),
982 method_did
, &arg_vals
, param_substs
, trueconst
))
984 hir
::ExprType(ref e
, _
) => try
!(const_expr(cx
, &e
, param_substs
, fn_args
, trueconst
)).0,
985 hir
::ExprBlock(ref block
) => {
987 Some(ref expr
) => try
!(const_expr(
997 hir
::ExprClosure(_
, ref decl
, ref body
) => {
999 ty
::TyClosure(def_id
, ref substs
) => {
1000 closure
::trans_closure_expr(closure
::Dest
::Ignore(cx
),
1011 &format
!("bad type for closure expr: {:?}", ety
))
1013 C_null(type_of
::type_of(cx
, ety
))
1015 _
=> cx
.sess().span_bug(e
.span
,
1016 "bad constant expression type in consts::const_expr"),
1020 pub fn trans_static(ccx
: &CrateContext
,
1024 attrs
: &[ast
::Attribute
])
1025 -> Result
<ValueRef
, ConstEvalErr
> {
1027 if collector
::collecting_debug_information(ccx
) {
1028 ccx
.record_translation_item_as_generated(TransItem
::Static(id
));
1032 let _icx
= push_ctxt("trans_static");
1033 let g
= base
::get_item_val(ccx
, id
);
1035 let empty_substs
= ccx
.tcx().mk_substs(Substs
::trans_empty());
1036 let (v
, _
) = try
!(const_expr(
1042 ).map_err(|e
| e
.into_inner()));
1044 // boolean SSA values are i1, but they have to be stored in i8 slots,
1045 // otherwise some LLVM optimization passes don't work as expected
1046 let mut val_llty
= llvm
::LLVMTypeOf(v
);
1047 let v
= if val_llty
== Type
::i1(ccx
).to_ref() {
1048 val_llty
= Type
::i8(ccx
).to_ref();
1049 llvm
::LLVMConstZExt(v
, val_llty
)
1054 let ty
= ccx
.tcx().node_id_to_type(id
);
1055 let llty
= type_of
::type_of(ccx
, ty
);
1056 let g
= if val_llty
== llty
.to_ref() {
1059 // If we created the global with the wrong type,
1060 // correct the type.
1061 let empty_string
= CString
::new("").unwrap();
1062 let name_str_ref
= CStr
::from_ptr(llvm
::LLVMGetValueName(g
));
1063 let name_string
= CString
::new(name_str_ref
.to_bytes()).unwrap();
1064 llvm
::LLVMSetValueName(g
, empty_string
.as_ptr());
1065 let new_g
= llvm
::LLVMGetOrInsertGlobal(
1066 ccx
.llmod(), name_string
.as_ptr(), val_llty
);
1067 // To avoid breaking any invariants, we leave around the old
1068 // global for the moment; we'll replace all references to it
1069 // with the new global later. (See base::trans_crate.)
1070 ccx
.statics_to_rauw().borrow_mut().push((g
, new_g
));
1073 llvm
::LLVMSetAlignment(g
, type_of
::align_of(ccx
, ty
));
1074 llvm
::LLVMSetInitializer(g
, v
);
1076 // As an optimization, all shared statics which do not have interior
1077 // mutability are placed into read-only memory.
1078 if m
!= hir
::MutMutable
{
1079 let tcontents
= ty
.type_contents(ccx
.tcx());
1080 if !tcontents
.interior_unsafe() {
1081 llvm
::LLVMSetGlobalConstant(g
, llvm
::True
);
1085 debuginfo
::create_global_var_metadata(ccx
, id
, g
);
1087 if attr
::contains_name(attrs
,
1089 llvm
::set_thread_local(g
, true);