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