]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/consts.rs
split ty::util and ty::adjustment
[rust.git] / src / librustc_trans / trans / consts.rs
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.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11
12 use back::abi;
13 use llvm;
14 use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
15 use llvm::{InternalLinkage, ValueRef, Bool, True};
16 use middle::{check_const, def};
17 use middle::const_eval::{self, ConstVal};
18 use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg};
19 use middle::const_eval::{const_int_checked_add, const_uint_checked_add};
20 use middle::const_eval::{const_int_checked_sub, const_uint_checked_sub};
21 use middle::const_eval::{const_int_checked_mul, const_uint_checked_mul};
22 use middle::const_eval::{const_int_checked_div, const_uint_checked_div};
23 use middle::const_eval::{const_int_checked_rem, const_uint_checked_rem};
24 use middle::const_eval::{const_int_checked_shl, const_uint_checked_shl};
25 use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr};
26 use middle::const_eval::EvalHint::ExprTypeChecked;
27 use middle::const_eval::eval_const_expr_partial;
28 use middle::def_id::{DefId, LOCAL_CRATE};
29 use trans::{adt, closure, debuginfo, expr, inline, machine};
30 use trans::base::{self, push_ctxt};
31 use trans::common::*;
32 use trans::declare;
33 use trans::monomorphize;
34 use trans::type_::Type;
35 use trans::type_of;
36 use middle::subst::Substs;
37 use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
38 use middle::ty::adjustment::AdjustUnsafeFnPointer;
39 use middle::ty::{self, Ty};
40 use middle::ty::cast::{CastTy,IntTy};
41 use util::nodemap::NodeMap;
42
43 use rustc_front::hir;
44 use rustc_front::attr;
45
46 use std::ffi::{CStr, CString};
47 use libc::c_uint;
48 use syntax::ast;
49 use syntax::parse::token;
50 use syntax::ptr::P;
51
52 pub type FnArgMap<'a> = Option<&'a NodeMap<ValueRef>>;
53
54 pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &hir::Lit)
55     -> ValueRef {
56     let _icx = push_ctxt("trans_lit");
57     debug!("const_lit: {:?}", lit);
58     match lit.node {
59         hir::LitByte(b) => C_integral(Type::uint_from_ty(cx, hir::TyU8), b as u64, false),
60         hir::LitChar(i) => C_integral(Type::char(cx), i as u64, false),
61         hir::LitInt(i, hir::SignedIntLit(t, _)) => {
62             C_integral(Type::int_from_ty(cx, t), i, true)
63         }
64         hir::LitInt(u, hir::UnsignedIntLit(t)) => {
65             C_integral(Type::uint_from_ty(cx, t), u, false)
66         }
67         hir::LitInt(i, hir::UnsuffixedIntLit(_)) => {
68             let lit_int_ty = cx.tcx().node_id_to_type(e.id);
69             match lit_int_ty.sty {
70                 ty::TyInt(t) => {
71                     C_integral(Type::int_from_ty(cx, t), i as u64, true)
72                 }
73                 ty::TyUint(t) => {
74                     C_integral(Type::uint_from_ty(cx, t), i as u64, false)
75                 }
76                 _ => cx.sess().span_bug(lit.span,
77                         &format!("integer literal has type {:?} (expected int \
78                                  or usize)",
79                                 lit_int_ty))
80             }
81         }
82         hir::LitFloat(ref fs, t) => {
83             C_floating(&fs, Type::float_from_ty(cx, t))
84         }
85         hir::LitFloatUnsuffixed(ref fs) => {
86             let lit_float_ty = cx.tcx().node_id_to_type(e.id);
87             match lit_float_ty.sty {
88                 ty::TyFloat(t) => {
89                     C_floating(&fs, Type::float_from_ty(cx, t))
90                 }
91                 _ => {
92                     cx.sess().span_bug(lit.span,
93                         "floating point literal doesn't have the right type");
94                 }
95             }
96         }
97         hir::LitBool(b) => C_bool(cx, b),
98         hir::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()),
99         hir::LitByteStr(ref data) => {
100             addr_of(cx, C_bytes(cx, &data[..]), "byte_str")
101         }
102     }
103 }
104
105 pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef {
106     unsafe {
107         llvm::LLVMConstPointerCast(val, ty.to_ref())
108     }
109 }
110
111 fn addr_of_mut(ccx: &CrateContext,
112                cv: ValueRef,
113                kind: &str)
114                -> ValueRef {
115     unsafe {
116         // FIXME: this totally needs a better name generation scheme, perhaps a simple global
117         // counter? Also most other uses of gensym in trans.
118         let gsym = token::gensym("_");
119         let name = format!("{}{}", kind, gsym.usize());
120         let gv = declare::define_global(ccx, &name[..], val_ty(cv)).unwrap_or_else(||{
121             ccx.sess().bug(&format!("symbol `{}` is already defined", name));
122         });
123         llvm::LLVMSetInitializer(gv, cv);
124         SetLinkage(gv, InternalLinkage);
125         SetUnnamedAddr(gv, true);
126         gv
127     }
128 }
129
130 pub fn addr_of(ccx: &CrateContext,
131                cv: ValueRef,
132                kind: &str)
133                -> ValueRef {
134     match ccx.const_globals().borrow().get(&cv) {
135         Some(&gv) => return gv,
136         None => {}
137     }
138     let gv = addr_of_mut(ccx, cv, kind);
139     unsafe {
140         llvm::LLVMSetGlobalConstant(gv, True);
141     }
142     ccx.const_globals().borrow_mut().insert(cv, gv);
143     gv
144 }
145
146 fn const_deref_ptr(cx: &CrateContext, v: ValueRef) -> ValueRef {
147     let v = match cx.const_unsized().borrow().get(&v) {
148         Some(&v) => v,
149         None => v
150     };
151     unsafe {
152         llvm::LLVMGetInitializer(v)
153     }
154 }
155
156 fn const_deref<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
157                          v: ValueRef,
158                          ty: Ty<'tcx>)
159                          -> (ValueRef, Ty<'tcx>) {
160     match ty.builtin_deref(true, ty::NoPreference) {
161         Some(mt) => {
162             if type_is_sized(cx.tcx(), mt.ty) {
163                 (const_deref_ptr(cx, v), mt.ty)
164             } else {
165                 // Derefing a fat pointer does not change the representation,
166                 // just the type to the unsized contents.
167                 (v, mt.ty)
168             }
169         }
170         None => {
171             cx.sess().bug(&format!("unexpected dereferenceable type {:?}",
172                                    ty))
173         }
174     }
175 }
176
177 fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
178                            node: ExprOrMethodCall,
179                            def_id: DefId,
180                            arg_vals: &[ValueRef],
181                            param_substs: &'tcx Substs<'tcx>) -> ValueRef {
182     let fn_like = const_eval::lookup_const_fn_by_id(ccx.tcx(), def_id);
183     let fn_like = fn_like.expect("lookup_const_fn_by_id failed in const_fn_call");
184
185     let args = &fn_like.decl().inputs;
186     assert_eq!(args.len(), arg_vals.len());
187
188     let arg_ids = args.iter().map(|arg| arg.pat.id);
189     let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect();
190
191     let substs = ccx.tcx().mk_substs(node_id_substs(ccx, node, param_substs));
192     match fn_like.body().expr {
193         Some(ref expr) => {
194             const_expr(ccx, &**expr, substs, Some(&fn_args)).0
195         }
196         None => C_nil(ccx)
197     }
198 }
199
200 pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
201                                 def_id: DefId,
202                                 ref_expr: &hir::Expr)
203                                 -> &'tcx hir::Expr {
204     let def_id = inline::maybe_instantiate_inline(ccx, def_id);
205
206     if def_id.krate != LOCAL_CRATE {
207         ccx.sess().span_bug(ref_expr.span,
208                             "cross crate constant could not be inlined");
209     }
210
211     match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id)) {
212         Some(ref expr) => expr,
213         None => {
214             ccx.sess().span_bug(ref_expr.span, "constant item not found")
215         }
216     }
217 }
218
219 fn get_const_val(ccx: &CrateContext,
220                  def_id: DefId,
221                  ref_expr: &hir::Expr) -> ValueRef {
222     let expr = get_const_expr(ccx, def_id, ref_expr);
223     let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
224     get_const_expr_as_global(ccx, expr, check_const::ConstQualif::empty(), empty_substs)
225 }
226
227 pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
228                                           expr: &hir::Expr,
229                                           qualif: check_const::ConstQualif,
230                                           param_substs: &'tcx Substs<'tcx>)
231                                           -> ValueRef {
232     debug!("get_const_expr_as_global: {:?}", expr.id);
233     // Special-case constants to cache a common global for all uses.
234     match expr.node {
235         hir::ExprPath(..) => {
236             let def = ccx.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
237             match def {
238                 def::DefConst(def_id) | def::DefAssociatedConst(def_id) => {
239                     if !ccx.tcx().tables.borrow().adjustments.contains_key(&expr.id) {
240                         debug!("get_const_expr_as_global ({:?}): found const {:?}",
241                                expr.id, def_id);
242                         return get_const_val(ccx, def_id, expr);
243                     }
244                 }
245                 _ => {}
246             }
247         }
248         _ => {}
249     }
250
251     let key = (expr.id, param_substs);
252     match ccx.const_values().borrow().get(&key) {
253         Some(&val) => return val,
254         None => {}
255     }
256     let val = if qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS) {
257         // Avoid autorefs as they would create global instead of stack
258         // references, even when only the latter are correct.
259         let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs,
260                                                   &ccx.tcx().expr_ty(expr));
261         const_expr_unadjusted(ccx, expr, ty, param_substs, None)
262     } else {
263         const_expr(ccx, expr, param_substs, None).0
264     };
265
266     // boolean SSA values are i1, but they have to be stored in i8 slots,
267     // otherwise some LLVM optimization passes don't work as expected
268     let val = unsafe {
269         if llvm::LLVMTypeOf(val) == Type::i1(ccx).to_ref() {
270             llvm::LLVMConstZExt(val, Type::i8(ccx).to_ref())
271         } else {
272             val
273         }
274     };
275
276     let lvalue = addr_of(ccx, val, "const");
277     ccx.const_values().borrow_mut().insert(key, lvalue);
278     lvalue
279 }
280
281 pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
282                             e: &hir::Expr,
283                             param_substs: &'tcx Substs<'tcx>,
284                             fn_args: FnArgMap)
285                             -> (ValueRef, Ty<'tcx>) {
286     let ety = monomorphize::apply_param_substs(cx.tcx(), param_substs,
287                                                &cx.tcx().expr_ty(e));
288     let llconst = const_expr_unadjusted(cx, e, ety, param_substs, fn_args);
289     let mut llconst = llconst;
290     let mut ety_adjusted = monomorphize::apply_param_substs(cx.tcx(), param_substs,
291                                                             &cx.tcx().expr_ty_adjusted(e));
292     let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned();
293     match opt_adj {
294         Some(AdjustReifyFnPointer) => {
295             // FIXME(#19925) once fn item types are
296             // zero-sized, we'll need to do something here
297         }
298         Some(AdjustUnsafeFnPointer) => {
299             // purely a type-level thing
300         }
301         Some(AdjustDerefRef(adj)) => {
302             let mut ty = ety;
303             // Save the last autoderef in case we can avoid it.
304             if adj.autoderefs > 0 {
305                 for _ in 0..adj.autoderefs-1 {
306                     let (dv, dt) = const_deref(cx, llconst, ty);
307                     llconst = dv;
308                     ty = dt;
309                 }
310             }
311
312             if adj.autoref.is_some() {
313                 if adj.autoderefs == 0 {
314                     // Don't copy data to do a deref+ref
315                     // (i.e., skip the last auto-deref).
316                     llconst = addr_of(cx, llconst, "autoref");
317                     ty = cx.tcx().mk_imm_ref(cx.tcx().mk_region(ty::ReStatic), ty);
318                 }
319             } else {
320                 let (dv, dt) = const_deref(cx, llconst, ty);
321                 llconst = dv;
322
323                 // If we derefed a fat pointer then we will have an
324                 // open type here. So we need to update the type with
325                 // the one returned from const_deref.
326                 ety_adjusted = dt;
327             }
328
329             if let Some(target) = adj.unsize {
330                 let target = monomorphize::apply_param_substs(cx.tcx(),
331                                                               param_substs,
332                                                               &target);
333
334                 let pointee_ty = ty.builtin_deref(true, ty::NoPreference)
335                     .expect("consts: unsizing got non-pointer type").ty;
336                 let (base, old_info) = if !type_is_sized(cx.tcx(), pointee_ty) {
337                     // Normally, the source is a thin pointer and we are
338                     // adding extra info to make a fat pointer. The exception
339                     // is when we are upcasting an existing object fat pointer
340                     // to use a different vtable. In that case, we want to
341                     // load out the original data pointer so we can repackage
342                     // it.
343                     (const_get_elt(cx, llconst, &[abi::FAT_PTR_ADDR as u32]),
344                      Some(const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32])))
345                 } else {
346                     (llconst, None)
347                 };
348
349                 let unsized_ty = target.builtin_deref(true, ty::NoPreference)
350                     .expect("consts: unsizing got non-pointer target type").ty;
351                 let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
352                 let base = ptrcast(base, ptr_ty);
353                 let info = expr::unsized_info(cx, pointee_ty, unsized_ty,
354                                               old_info, param_substs);
355
356                 if old_info.is_none() {
357                     let prev_const = cx.const_unsized().borrow_mut()
358                                        .insert(base, llconst);
359                     assert!(prev_const.is_none() || prev_const == Some(llconst));
360                 }
361                 assert_eq!(abi::FAT_PTR_ADDR, 0);
362                 assert_eq!(abi::FAT_PTR_EXTRA, 1);
363                 llconst = C_struct(cx, &[base, info], false);
364             }
365         }
366         None => {}
367     };
368
369     let llty = type_of::sizing_type_of(cx, ety_adjusted);
370     let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
371     let tsize = machine::llsize_of_alloc(cx, llty);
372     if csize != tsize {
373         cx.sess().abort_if_errors();
374         unsafe {
375             // FIXME these values could use some context
376             llvm::LLVMDumpValue(llconst);
377             llvm::LLVMDumpValue(C_undef(llty));
378         }
379         cx.sess().bug(&format!("const {:?} of type {:?} has size {} instead of {}",
380                          e, ety_adjusted,
381                          csize, tsize));
382     }
383     (llconst, ety_adjusted)
384 }
385
386 fn check_unary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
387                              te: ValueRef) {
388     // The only kind of unary expression that we check for validity
389     // here is `-expr`, to check if it "overflows" (e.g. `-i32::MIN`).
390     if let hir::ExprUnary(hir::UnNeg, ref inner_e) = e.node {
391
392         // An unfortunate special case: we parse e.g. -128 as a
393         // negation of the literal 128, which means if we're expecting
394         // a i8 (or if it was already suffixed, e.g. `-128_i8`), then
395         // 128 will have already overflowed to -128, and so then the
396         // constant evaluator thinks we're trying to negate -128.
397         //
398         // Catch this up front by looking for ExprLit directly,
399         // and just accepting it.
400         if let hir::ExprLit(_) = inner_e.node { return; }
401
402         let result = match t.sty {
403             ty::TyInt(int_type) => {
404                 let input = match const_to_opt_int(te) {
405                     Some(v) => v,
406                     None => return,
407                 };
408                 const_int_checked_neg(
409                     input, e, Some(const_eval::IntTy::from(cx.tcx(), int_type)))
410             }
411             ty::TyUint(uint_type) => {
412                 let input = match const_to_opt_uint(te) {
413                     Some(v) => v,
414                     None => return,
415                 };
416                 const_uint_checked_neg(
417                     input, e, Some(const_eval::UintTy::from(cx.tcx(), uint_type)))
418             }
419             _ => return,
420         };
421
422         // We do not actually care about a successful result.
423         if let Err(err) = result {
424             cx.tcx().sess.span_err(e.span, &err.description());
425         }
426     }
427 }
428
429 fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
430                               te1: ValueRef, te2: ValueRef) {
431     let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { return };
432
433     let result = match t.sty {
434         ty::TyInt(int_type) => {
435             let (lhs, rhs) = match (const_to_opt_int(te1),
436                                     const_to_opt_int(te2)) {
437                 (Some(v1), Some(v2)) => (v1, v2),
438                 _ => return,
439             };
440
441             let opt_ety = Some(const_eval::IntTy::from(cx.tcx(), int_type));
442             match b.node {
443                 hir::BiAdd => const_int_checked_add(lhs, rhs, e, opt_ety),
444                 hir::BiSub => const_int_checked_sub(lhs, rhs, e, opt_ety),
445                 hir::BiMul => const_int_checked_mul(lhs, rhs, e, opt_ety),
446                 hir::BiDiv => const_int_checked_div(lhs, rhs, e, opt_ety),
447                 hir::BiRem => const_int_checked_rem(lhs, rhs, e, opt_ety),
448                 hir::BiShl => const_int_checked_shl(lhs, rhs, e, opt_ety),
449                 hir::BiShr => const_int_checked_shr(lhs, rhs, e, opt_ety),
450                 _ => return,
451             }
452         }
453         ty::TyUint(uint_type) => {
454             let (lhs, rhs) = match (const_to_opt_uint(te1),
455                                     const_to_opt_uint(te2)) {
456                 (Some(v1), Some(v2)) => (v1, v2),
457                 _ => return,
458             };
459
460             let opt_ety = Some(const_eval::UintTy::from(cx.tcx(), uint_type));
461             match b.node {
462                 hir::BiAdd => const_uint_checked_add(lhs, rhs, e, opt_ety),
463                 hir::BiSub => const_uint_checked_sub(lhs, rhs, e, opt_ety),
464                 hir::BiMul => const_uint_checked_mul(lhs, rhs, e, opt_ety),
465                 hir::BiDiv => const_uint_checked_div(lhs, rhs, e, opt_ety),
466                 hir::BiRem => const_uint_checked_rem(lhs, rhs, e, opt_ety),
467                 hir::BiShl => const_uint_checked_shl(lhs, rhs, e, opt_ety),
468                 hir::BiShr => const_uint_checked_shr(lhs, rhs, e, opt_ety),
469                 _ => return,
470             }
471         }
472         _ => return,
473     };
474     // We do not actually care about a successful result.
475     if let Err(err) = result {
476         cx.tcx().sess.span_err(e.span, &err.description());
477     }
478 }
479
480 fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
481                                    e: &hir::Expr,
482                                    ety: Ty<'tcx>,
483                                    param_substs: &'tcx Substs<'tcx>,
484                                    fn_args: FnArgMap)
485                                    -> ValueRef
486 {
487     debug!("const_expr_unadjusted(e={:?}, ety={:?}, param_substs={:?})",
488            e,
489            ety,
490            param_substs);
491
492     let map_list = |exprs: &[P<hir::Expr>]| -> Vec<ValueRef> {
493         exprs.iter()
494              .map(|e| const_expr(cx, &**e, param_substs, fn_args).0)
495              .collect()
496     };
497     let _icx = push_ctxt("const_expr");
498     match e.node {
499         hir::ExprLit(ref lit) => {
500             const_lit(cx, e, &**lit)
501         },
502         hir::ExprBinary(b, ref e1, ref e2) => {
503             /* Neither type is bottom, and we expect them to be unified
504              * already, so the following is safe. */
505             let (te1, ty) = const_expr(cx, &**e1, param_substs, fn_args);
506             debug!("const_expr_unadjusted: te1={}, ty={:?}",
507                    cx.tn().val_to_string(te1),
508                    ty);
509             assert!(!ty.is_simd());
510             let is_float = ty.is_fp();
511             let signed = ty.is_signed();
512
513             let (te2, _) = const_expr(cx, &**e2, param_substs, fn_args);
514
515             check_binary_expr_validity(cx, e, ty, te1, te2);
516
517             unsafe { match b.node {
518                 hir::BiAdd if is_float => llvm::LLVMConstFAdd(te1, te2),
519                 hir::BiAdd             => llvm::LLVMConstAdd(te1, te2),
520
521                 hir::BiSub if is_float => llvm::LLVMConstFSub(te1, te2),
522                 hir::BiSub             => llvm::LLVMConstSub(te1, te2),
523
524                 hir::BiMul if is_float => llvm::LLVMConstFMul(te1, te2),
525                 hir::BiMul             => llvm::LLVMConstMul(te1, te2),
526
527                 hir::BiDiv if is_float => llvm::LLVMConstFDiv(te1, te2),
528                 hir::BiDiv if signed   => llvm::LLVMConstSDiv(te1, te2),
529                 hir::BiDiv             => llvm::LLVMConstUDiv(te1, te2),
530
531                 hir::BiRem if is_float => llvm::LLVMConstFRem(te1, te2),
532                 hir::BiRem if signed   => llvm::LLVMConstSRem(te1, te2),
533                 hir::BiRem             => llvm::LLVMConstURem(te1, te2),
534
535                 hir::BiAnd    => llvm::LLVMConstAnd(te1, te2),
536                 hir::BiOr     => llvm::LLVMConstOr(te1, te2),
537                 hir::BiBitXor => llvm::LLVMConstXor(te1, te2),
538                 hir::BiBitAnd => llvm::LLVMConstAnd(te1, te2),
539                 hir::BiBitOr  => llvm::LLVMConstOr(te1, te2),
540                 hir::BiShl    => {
541                     let te2 = base::cast_shift_const_rhs(b.node, te1, te2);
542                     llvm::LLVMConstShl(te1, te2)
543                 },
544                 hir::BiShr    => {
545                     let te2 = base::cast_shift_const_rhs(b.node, te1, te2);
546                     if signed { llvm::LLVMConstAShr(te1, te2) }
547                     else      { llvm::LLVMConstLShr(te1, te2) }
548                 },
549                 hir::BiEq | hir::BiNe | hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe => {
550                     if is_float {
551                         let cmp = base::bin_op_to_fcmp_predicate(cx, b.node);
552                         ConstFCmp(cmp, te1, te2)
553                     } else {
554                         let cmp = base::bin_op_to_icmp_predicate(cx, b.node, signed);
555                         ConstICmp(cmp, te1, te2)
556                     }
557                 },
558             } } // unsafe { match b.node {
559         },
560         hir::ExprUnary(u, ref inner_e) => {
561             let (te, ty) = const_expr(cx, &**inner_e, param_substs, fn_args);
562
563             check_unary_expr_validity(cx, e, ty, te);
564
565             let is_float = ty.is_fp();
566             unsafe { match u {
567                 hir::UnUniq | hir::UnDeref => const_deref(cx, te, ty).0,
568                 hir::UnNot                 => llvm::LLVMConstNot(te),
569                 hir::UnNeg if is_float     => llvm::LLVMConstFNeg(te),
570                 hir::UnNeg                 => llvm::LLVMConstNeg(te),
571             } }
572         },
573         hir::ExprField(ref base, field) => {
574             let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
575             let brepr = adt::represent_type(cx, bt);
576             let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None);
577             let ix = vinfo.field_index(field.node.name);
578             adt::const_get_field(cx, &*brepr, bv, vinfo.discr, ix)
579         },
580         hir::ExprTupField(ref base, idx) => {
581             let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
582             let brepr = adt::represent_type(cx, bt);
583             let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None);
584             adt::const_get_field(cx, &*brepr, bv, vinfo.discr, idx.node)
585         },
586
587         hir::ExprIndex(ref base, ref index) => {
588             let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
589             let iv = match eval_const_expr_partial(cx.tcx(), &index, ExprTypeChecked) {
590                 Ok(ConstVal::Int(i)) => i as u64,
591                 Ok(ConstVal::Uint(u)) => u,
592                 _ => cx.sess().span_bug(index.span,
593                                         "index is not an integer-constant expression")
594             };
595             let (arr, len) = match bt.sty {
596                 ty::TyArray(_, u) => (bv, C_uint(cx, u)),
597                 ty::TySlice(_) | ty::TyStr => {
598                     let e1 = const_get_elt(cx, bv, &[0]);
599                     (const_deref_ptr(cx, e1), const_get_elt(cx, bv, &[1]))
600                 },
601                 ty::TyRef(_, mt) => match mt.ty.sty {
602                     ty::TyArray(_, u) => {
603                         (const_deref_ptr(cx, bv), C_uint(cx, u))
604                     },
605                     _ => cx.sess().span_bug(base.span,
606                                             &format!("index-expr base must be a vector \
607                                                       or string type, found {:?}",
608                                                      bt)),
609                 },
610                 _ => cx.sess().span_bug(base.span,
611                                         &format!("index-expr base must be a vector \
612                                                   or string type, found {:?}",
613                                                  bt)),
614             };
615
616             let len = unsafe { llvm::LLVMConstIntGetZExtValue(len) as u64 };
617             let len = match bt.sty {
618                 ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) => match ty.sty {
619                     ty::TyStr => {
620                         assert!(len > 0);
621                         len - 1
622                     },
623                     _ => len,
624                 },
625                 _ => len,
626             };
627             if iv >= len {
628                 // FIXME #3170: report this earlier on in the const-eval
629                 // pass. Reporting here is a bit late.
630                 cx.sess().span_err(e.span,
631                                    "const index-expr is out of bounds");
632                 C_undef(type_of::type_of(cx, bt).element_type())
633             } else {
634                 const_get_elt(cx, arr, &[iv as c_uint])
635             }
636         },
637         hir::ExprCast(ref base, _) => {
638             let t_cast = ety;
639             let llty = type_of::type_of(cx, t_cast);
640             let (v, t_expr) = const_expr(cx, &**base, param_substs, fn_args);
641             debug!("trans_const_cast({:?} as {:?})", t_expr, t_cast);
642             if expr::cast_is_noop(cx.tcx(), base, t_expr, t_cast) {
643                 return v;
644             }
645             if type_is_fat_ptr(cx.tcx(), t_expr) {
646                 // Fat pointer casts.
647                 let t_cast_inner =
648                     t_cast.builtin_deref(true, ty::NoPreference).expect("cast to non-pointer").ty;
649                 let ptr_ty = type_of::in_memory_type_of(cx, t_cast_inner).ptr_to();
650                 let addr = ptrcast(const_get_elt(cx, v, &[abi::FAT_PTR_ADDR as u32]),
651                                    ptr_ty);
652                 if type_is_fat_ptr(cx.tcx(), t_cast) {
653                     let info = const_get_elt(cx, v, &[abi::FAT_PTR_EXTRA as u32]);
654                     return C_struct(cx, &[addr, info], false)
655                 } else {
656                     return addr;
657                 }
658             }
659             unsafe { match (
660                 CastTy::from_ty(t_expr).expect("bad input type for cast"),
661                 CastTy::from_ty(t_cast).expect("bad output type for cast"),
662             ) {
663                 (CastTy::Int(IntTy::CEnum), CastTy::Int(_)) => {
664                     let repr = adt::represent_type(cx, t_expr);
665                     let discr = adt::const_get_discrim(cx, &*repr, v);
666                     let iv = C_integral(cx.int_type(), discr, false);
667                     let s = adt::is_discr_signed(&*repr) as Bool;
668                     llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
669                 },
670                 (CastTy::Int(_), CastTy::Int(_)) => {
671                     let s = t_expr.is_signed() as Bool;
672                     llvm::LLVMConstIntCast(v, llty.to_ref(), s)
673                 },
674                 (CastTy::Int(_), CastTy::Float) => {
675                     if t_expr.is_signed() {
676                         llvm::LLVMConstSIToFP(v, llty.to_ref())
677                     } else {
678                         llvm::LLVMConstUIToFP(v, llty.to_ref())
679                     }
680                 },
681                 (CastTy::Float, CastTy::Float) => llvm::LLVMConstFPCast(v, llty.to_ref()),
682                 (CastTy::Float, CastTy::Int(IntTy::I)) => llvm::LLVMConstFPToSI(v, llty.to_ref()),
683                 (CastTy::Float, CastTy::Int(_)) => llvm::LLVMConstFPToUI(v, llty.to_ref()),
684                 (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_))
685                 | (CastTy::RPtr(_), CastTy::Ptr(_)) => {
686                     ptrcast(v, llty)
687                 },
688                 (CastTy::FnPtr, CastTy::FnPtr) => ptrcast(v, llty), // isn't this a coercion?
689                 (CastTy::Int(_), CastTy::Ptr(_)) => llvm::LLVMConstIntToPtr(v, llty.to_ref()),
690                 (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => {
691                   llvm::LLVMConstPtrToInt(v, llty.to_ref())
692                 },
693                 _ => {
694                   cx.sess().impossible_case(e.span,
695                                             "bad combination of types for cast")
696                 },
697             } } // unsafe { match ( ... ) {
698         },
699         hir::ExprAddrOf(hir::MutImmutable, ref sub) => {
700             // If this is the address of some static, then we need to return
701             // the actual address of the static itself (short circuit the rest
702             // of const eval).
703             let mut cur = sub;
704             loop {
705                 match cur.node {
706                     hir::ExprParen(ref sub) => cur = sub,
707                     hir::ExprBlock(ref blk) => {
708                         if let Some(ref sub) = blk.expr {
709                             cur = sub;
710                         } else {
711                             break;
712                         }
713                     },
714                     _ => break,
715                 }
716             }
717             let opt_def = cx.tcx().def_map.borrow().get(&cur.id).map(|d| d.full_def());
718             if let Some(def::DefStatic(def_id, _)) = opt_def {
719                 get_static_val(cx, def_id, ety)
720             } else {
721                 // If this isn't the address of a static, then keep going through
722                 // normal constant evaluation.
723                 let (v, _) = const_expr(cx, &**sub, param_substs, fn_args);
724                 addr_of(cx, v, "ref")
725             }
726         },
727         hir::ExprAddrOf(hir::MutMutable, ref sub) => {
728             let (v, _) = const_expr(cx, &**sub, param_substs, fn_args);
729             addr_of_mut(cx, v, "ref_mut_slice")
730         },
731         hir::ExprTup(ref es) => {
732             let repr = adt::represent_type(cx, ety);
733             let vals = map_list(&es[..]);
734             adt::trans_const(cx, &*repr, 0, &vals[..])
735         },
736         hir::ExprStruct(_, ref fs, ref base_opt) => {
737             let repr = adt::represent_type(cx, ety);
738
739             let base_val = match *base_opt {
740                 Some(ref base) => Some(const_expr(cx, &**base, param_substs, fn_args)),
741                 None => None
742             };
743
744             let VariantInfo { discr, fields } = VariantInfo::of_node(cx.tcx(), ety, e.id);
745             let cs = fields.iter().enumerate().map(|(ix, &Field(f_name, _))| {
746                 match (fs.iter().find(|f| f_name == f.ident.node.name), base_val) {
747                     (Some(ref f), _) => const_expr(cx, &*f.expr, param_substs, fn_args).0,
748                     (_, Some((bv, _))) => adt::const_get_field(cx, &*repr, bv, discr, ix),
749                     (_, None) => cx.sess().span_bug(e.span, "missing struct field"),
750                 }
751             }).collect::<Vec<_>>();
752             if ety.is_simd() {
753                 C_vector(&cs[..])
754             } else {
755                 adt::trans_const(cx, &*repr, discr, &cs[..])
756             }
757         },
758         hir::ExprVec(ref es) => {
759             let unit_ty = ety.sequence_element_type(cx.tcx());
760             let llunitty = type_of::type_of(cx, unit_ty);
761             let vs = es.iter()
762                        .map(|e| const_expr(cx, &**e, param_substs, fn_args).0)
763                        .collect::<Vec<_>>();
764             // If the vector contains enums, an LLVM array won't work.
765             if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
766                 C_struct(cx, &vs[..], false)
767             } else {
768                 C_array(llunitty, &vs[..])
769             }
770         },
771         hir::ExprRepeat(ref elem, ref count) => {
772             let unit_ty = ety.sequence_element_type(cx.tcx());
773             let llunitty = type_of::type_of(cx, unit_ty);
774             let n = cx.tcx().eval_repeat_count(count);
775             let unit_val = const_expr(cx, &**elem, param_substs, fn_args).0;
776             let vs = vec![unit_val; n];
777             if val_ty(unit_val) != llunitty {
778                 C_struct(cx, &vs[..], false)
779             } else {
780                 C_array(llunitty, &vs[..])
781             }
782         },
783         hir::ExprPath(..) => {
784             let def = cx.tcx().def_map.borrow().get(&e.id).unwrap().full_def();
785             match def {
786                 def::DefLocal(id) => {
787                     if let Some(val) = fn_args.and_then(|args| args.get(&id).cloned()) {
788                         val
789                     } else {
790                         cx.sess().span_bug(e.span, "const fn argument not found")
791                     }
792                 }
793                 def::DefFn(..) | def::DefMethod(..) => {
794                     expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
795                 }
796                 def::DefConst(def_id) | def::DefAssociatedConst(def_id) => {
797                     const_deref_ptr(cx, get_const_val(cx, def_id, e))
798                 }
799                 def::DefVariant(enum_did, variant_did, _) => {
800                     let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);
801                     match vinfo.kind() {
802                         ty::VariantKind::Unit => {
803                             let repr = adt::represent_type(cx, ety);
804                             adt::trans_const(cx, &*repr, vinfo.disr_val, &[])
805                         }
806                         ty::VariantKind::Tuple => {
807                             expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
808                         }
809                         ty::VariantKind::Dict => {
810                             cx.sess().span_bug(e.span, "path-expr refers to a dict variant!")
811                         }
812                     }
813                 }
814                 def::DefStruct(_) => {
815                     if let ty::TyBareFn(..) = ety.sty {
816                         // Tuple struct.
817                         expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
818                     } else {
819                         // Unit struct.
820                         C_null(type_of::type_of(cx, ety))
821                     }
822                 }
823                 _ => {
824                     cx.sess().span_bug(e.span, "expected a const, fn, struct, \
825                                                 or variant def")
826                 }
827             }
828         },
829         hir::ExprCall(ref callee, ref args) => {
830             let mut callee = &**callee;
831             loop {
832                 callee = match callee.node {
833                     hir::ExprParen(ref inner) => &**inner,
834                     hir::ExprBlock(ref block) => match block.expr {
835                         Some(ref tail) => &**tail,
836                         None => break,
837                     },
838                     _ => break,
839                 };
840             }
841             let def = cx.tcx().def_map.borrow()[&callee.id].full_def();
842             let arg_vals = map_list(args);
843             match def {
844                 def::DefFn(did, _) | def::DefMethod(did) => {
845                     const_fn_call(cx, ExprId(callee.id), did, &arg_vals, param_substs)
846                 }
847                 def::DefStruct(_) => {
848                     if ety.is_simd() {
849                         C_vector(&arg_vals[..])
850                     } else {
851                         let repr = adt::represent_type(cx, ety);
852                         adt::trans_const(cx, &*repr, 0, &arg_vals[..])
853                     }
854                 }
855                 def::DefVariant(enum_did, variant_did, _) => {
856                     let repr = adt::represent_type(cx, ety);
857                     let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);
858                     adt::trans_const(cx,
859                                      &*repr,
860                                      vinfo.disr_val,
861                                      &arg_vals[..])
862                 }
863                 _ => cx.sess().span_bug(e.span, "expected a struct, variant, or const fn def"),
864             }
865         },
866         hir::ExprMethodCall(_, _, ref args) => {
867             let arg_vals = map_list(args);
868             let method_call = ty::MethodCall::expr(e.id);
869             let method_did = cx.tcx().tables.borrow().method_map[&method_call].def_id;
870             const_fn_call(cx, MethodCallKey(method_call),
871                           method_did, &arg_vals, param_substs)
872         },
873         hir::ExprParen(ref e) => const_expr(cx, &**e, param_substs, fn_args).0,
874         hir::ExprBlock(ref block) => {
875             match block.expr {
876                 Some(ref expr) => const_expr(cx, &**expr, param_substs, fn_args).0,
877                 None => C_nil(cx),
878             }
879         },
880         hir::ExprClosure(_, ref decl, ref body) => {
881             match ety.sty {
882                 ty::TyClosure(_, ref substs) => {
883                     closure::trans_closure_expr(closure::Dest::Ignore(cx), decl,
884                                                 body, e.id, substs);
885                 }
886                 _ =>
887                     cx.sess().span_bug(
888                         e.span,
889                         &format!("bad type for closure expr: {:?}", ety))
890             }
891             C_null(type_of::type_of(cx, ety))
892         },
893         _ => cx.sess().span_bug(e.span,
894                                 "bad constant expression type in consts::const_expr"),
895     }
896 }
897 pub fn trans_static(ccx: &CrateContext,
898                     m: hir::Mutability,
899                     expr: &hir::Expr,
900                     id: ast::NodeId,
901                     attrs: &Vec<hir::Attribute>)
902                     -> ValueRef {
903     unsafe {
904         let _icx = push_ctxt("trans_static");
905         let g = base::get_item_val(ccx, id);
906
907         let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
908         let (v, _) = const_expr(ccx, expr, empty_substs, None);
909
910         // boolean SSA values are i1, but they have to be stored in i8 slots,
911         // otherwise some LLVM optimization passes don't work as expected
912         let mut val_llty = llvm::LLVMTypeOf(v);
913         let v = if val_llty == Type::i1(ccx).to_ref() {
914             val_llty = Type::i8(ccx).to_ref();
915             llvm::LLVMConstZExt(v, val_llty)
916         } else {
917             v
918         };
919
920         let ty = ccx.tcx().node_id_to_type(id);
921         let llty = type_of::type_of(ccx, ty);
922         let g = if val_llty == llty.to_ref() {
923             g
924         } else {
925             // If we created the global with the wrong type,
926             // correct the type.
927             let empty_string = CString::new("").unwrap();
928             let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g));
929             let name_string = CString::new(name_str_ref.to_bytes()).unwrap();
930             llvm::LLVMSetValueName(g, empty_string.as_ptr());
931             let new_g = llvm::LLVMGetOrInsertGlobal(
932                 ccx.llmod(), name_string.as_ptr(), val_llty);
933             // To avoid breaking any invariants, we leave around the old
934             // global for the moment; we'll replace all references to it
935             // with the new global later. (See base::trans_crate.)
936             ccx.statics_to_rauw().borrow_mut().push((g, new_g));
937             new_g
938         };
939         llvm::LLVMSetInitializer(g, v);
940
941         // As an optimization, all shared statics which do not have interior
942         // mutability are placed into read-only memory.
943         if m != hir::MutMutable {
944             let tcontents = ty.type_contents(ccx.tcx());
945             if !tcontents.interior_unsafe() {
946                 llvm::LLVMSetGlobalConstant(g, llvm::True);
947             }
948         }
949
950         debuginfo::create_global_var_metadata(ccx, id, g);
951
952         if attr::contains_name(attrs,
953                                "thread_local") {
954             llvm::set_thread_local(g, true);
955         }
956         g
957     }
958 }
959
960
961 fn get_static_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
962                             did: DefId,
963                             ty: Ty<'tcx>)
964                             -> ValueRef {
965     if did.is_local() { return base::get_item_val(ccx, did.node) }
966     base::trans_external_path(ccx, did, ty)
967 }