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