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