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