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