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