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