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