]>
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 | ||
1a4d82fc | 12 | use llvm; |
5bcae85e | 13 | use llvm::{SetUnnamedAddr}; |
85aaf69f | 14 | use llvm::{InternalLinkage, ValueRef, Bool, True}; |
7453a54e | 15 | use middle::const_qualif::ConstQualif; |
54a0048b | 16 | use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind}; |
5bcae85e | 17 | use rustc_const_eval::{eval_length, report_const_eval_err, note_const_eval_err}; |
54a0048b SL |
18 | use rustc::hir::def::Def; |
19 | use rustc::hir::def_id::DefId; | |
20 | use rustc::hir::map as hir_map; | |
21 | use {abi, adt, closure, debuginfo, expr, machine}; | |
3157f602 | 22 | use base::{self, push_ctxt}; |
54a0048b | 23 | use callee::Callee; |
a7813a04 | 24 | use trans_item::TransItem; |
54a0048b SL |
25 | use common::{type_is_sized, C_nil, const_get_elt}; |
26 | use common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty}; | |
27 | use common::{C_struct, C_undef, const_to_opt_int, const_to_opt_uint, VariantInfo, C_uint}; | |
28 | use common::{type_is_fat_ptr, Field, C_vector, C_array, C_null}; | |
29 | use datum::{Datum, Lvalue}; | |
30 | use declare; | |
31 | use monomorphize::{self, Instance}; | |
32 | use type_::Type; | |
33 | use type_of; | |
34 | use value::Value; | |
35 | use Disr; | |
36 | use rustc::ty::subst::Substs; | |
5bcae85e | 37 | use rustc::ty::adjustment::{AdjustNeverToAny, AdjustDerefRef, AdjustReifyFnPointer}; |
54a0048b SL |
38 | use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; |
39 | use rustc::ty::{self, Ty, TyCtxt}; | |
40 | use rustc::ty::cast::{CastTy,IntTy}; | |
62682a34 | 41 | use util::nodemap::NodeMap; |
a7813a04 | 42 | use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; |
1a4d82fc | 43 | |
54a0048b | 44 | use rustc::hir; |
e9174d1e | 45 | |
c1a9b12d | 46 | use std::ffi::{CStr, CString}; |
1a4d82fc | 47 | use libc::c_uint; |
7453a54e | 48 | use syntax::ast::{self, LitKind}; |
54a0048b | 49 | use syntax::attr::{self, AttrMetaMethods}; |
9346a6ac | 50 | use syntax::parse::token; |
1a4d82fc | 51 | use syntax::ptr::P; |
3157f602 | 52 | use syntax_pos::Span; |
1a4d82fc | 53 | |
62682a34 SL |
54 | pub type FnArgMap<'a> = Option<&'a NodeMap<ValueRef>>; |
55 | ||
b039eaaf | 56 | pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &ast::Lit) |
1a4d82fc JJ |
57 | -> ValueRef { |
58 | let _icx = push_ctxt("trans_lit"); | |
59 | debug!("const_lit: {:?}", lit); | |
60 | match lit.node { | |
7453a54e SL |
61 | LitKind::Byte(b) => C_integral(Type::uint_from_ty(cx, ast::UintTy::U8), b as u64, false), |
62 | LitKind::Char(i) => C_integral(Type::char(cx), i as u64, false), | |
63 | LitKind::Int(i, ast::LitIntType::Signed(t)) => { | |
1a4d82fc JJ |
64 | C_integral(Type::int_from_ty(cx, t), i, true) |
65 | } | |
7453a54e | 66 | LitKind::Int(u, ast::LitIntType::Unsigned(t)) => { |
1a4d82fc JJ |
67 | C_integral(Type::uint_from_ty(cx, t), u, false) |
68 | } | |
7453a54e | 69 | LitKind::Int(i, ast::LitIntType::Unsuffixed) => { |
c1a9b12d | 70 | let lit_int_ty = cx.tcx().node_id_to_type(e.id); |
1a4d82fc | 71 | match lit_int_ty.sty { |
62682a34 | 72 | ty::TyInt(t) => { |
1a4d82fc JJ |
73 | C_integral(Type::int_from_ty(cx, t), i as u64, true) |
74 | } | |
62682a34 | 75 | ty::TyUint(t) => { |
1a4d82fc JJ |
76 | C_integral(Type::uint_from_ty(cx, t), i as u64, false) |
77 | } | |
54a0048b SL |
78 | _ => span_bug!(lit.span, |
79 | "integer literal has type {:?} (expected int \ | |
80 | or usize)", | |
81 | lit_int_ty) | |
1a4d82fc JJ |
82 | } |
83 | } | |
7453a54e | 84 | LitKind::Float(ref fs, t) => { |
85aaf69f | 85 | C_floating(&fs, Type::float_from_ty(cx, t)) |
1a4d82fc | 86 | } |
7453a54e | 87 | LitKind::FloatUnsuffixed(ref fs) => { |
c1a9b12d | 88 | let lit_float_ty = cx.tcx().node_id_to_type(e.id); |
1a4d82fc | 89 | match lit_float_ty.sty { |
62682a34 | 90 | ty::TyFloat(t) => { |
85aaf69f | 91 | C_floating(&fs, Type::float_from_ty(cx, t)) |
1a4d82fc JJ |
92 | } |
93 | _ => { | |
54a0048b | 94 | span_bug!(lit.span, |
1a4d82fc JJ |
95 | "floating point literal doesn't have the right type"); |
96 | } | |
97 | } | |
98 | } | |
7453a54e SL |
99 | LitKind::Bool(b) => C_bool(cx, b), |
100 | LitKind::Str(ref s, _) => C_str_slice(cx, (*s).clone()), | |
101 | LitKind::ByteStr(ref data) => { | |
b039eaaf | 102 | addr_of(cx, C_bytes(cx, &data[..]), 1, "byte_str") |
85aaf69f | 103 | } |
1a4d82fc JJ |
104 | } |
105 | } | |
106 | ||
107 | pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { | |
108 | unsafe { | |
109 | llvm::LLVMConstPointerCast(val, ty.to_ref()) | |
110 | } | |
111 | } | |
112 | ||
a7813a04 XL |
113 | pub fn addr_of_mut(ccx: &CrateContext, |
114 | cv: ValueRef, | |
115 | align: machine::llalign, | |
116 | kind: &str) | |
117 | -> ValueRef { | |
1a4d82fc | 118 | unsafe { |
9346a6ac AL |
119 | // FIXME: this totally needs a better name generation scheme, perhaps a simple global |
120 | // counter? Also most other uses of gensym in trans. | |
121 | let gsym = token::gensym("_"); | |
b039eaaf | 122 | let name = format!("{}{}", kind, gsym.0); |
9346a6ac | 123 | let gv = declare::define_global(ccx, &name[..], val_ty(cv)).unwrap_or_else(||{ |
54a0048b | 124 | bug!("symbol `{}` is already defined", name); |
9346a6ac | 125 | }); |
1a4d82fc | 126 | llvm::LLVMSetInitializer(gv, cv); |
b039eaaf | 127 | llvm::LLVMSetAlignment(gv, align); |
5bcae85e | 128 | llvm::LLVMSetLinkage(gv, InternalLinkage); |
85aaf69f | 129 | SetUnnamedAddr(gv, true); |
1a4d82fc JJ |
130 | gv |
131 | } | |
132 | } | |
133 | ||
85aaf69f SL |
134 | pub fn addr_of(ccx: &CrateContext, |
135 | cv: ValueRef, | |
b039eaaf | 136 | align: machine::llalign, |
9346a6ac | 137 | kind: &str) |
85aaf69f | 138 | -> ValueRef { |
3157f602 XL |
139 | if let Some(&gv) = ccx.const_globals().borrow().get(&cv) { |
140 | unsafe { | |
141 | // Upgrade the alignment in cases where the same constant is used with different | |
142 | // alignment requirements | |
143 | if align > llvm::LLVMGetAlignment(gv) { | |
144 | llvm::LLVMSetAlignment(gv, align); | |
b039eaaf | 145 | } |
b039eaaf | 146 | } |
3157f602 | 147 | return gv; |
85aaf69f | 148 | } |
b039eaaf | 149 | let gv = addr_of_mut(ccx, cv, align, kind); |
85aaf69f SL |
150 | unsafe { |
151 | llvm::LLVMSetGlobalConstant(gv, True); | |
152 | } | |
153 | ccx.const_globals().borrow_mut().insert(cv, gv); | |
154 | gv | |
155 | } | |
156 | ||
7453a54e | 157 | /// Deref a constant pointer |
a7813a04 | 158 | pub fn load_const(cx: &CrateContext, v: ValueRef, t: Ty) -> ValueRef { |
85aaf69f | 159 | let v = match cx.const_unsized().borrow().get(&v) { |
1a4d82fc JJ |
160 | Some(&v) => v, |
161 | None => v | |
162 | }; | |
7453a54e | 163 | let d = unsafe { llvm::LLVMGetInitializer(v) }; |
a7813a04 | 164 | if !d.is_null() && t.is_bool() { |
7453a54e SL |
165 | unsafe { llvm::LLVMConstTrunc(d, Type::i1(cx).to_ref()) } |
166 | } else { | |
167 | d | |
1a4d82fc JJ |
168 | } |
169 | } | |
170 | ||
85aaf69f SL |
171 | fn const_deref<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, |
172 | v: ValueRef, | |
173 | ty: Ty<'tcx>) | |
1a4d82fc | 174 | -> (ValueRef, Ty<'tcx>) { |
e9174d1e | 175 | match ty.builtin_deref(true, ty::NoPreference) { |
85aaf69f SL |
176 | Some(mt) => { |
177 | if type_is_sized(cx.tcx(), mt.ty) { | |
7453a54e | 178 | (load_const(cx, v, mt.ty), mt.ty) |
85aaf69f SL |
179 | } else { |
180 | // Derefing a fat pointer does not change the representation, | |
c34b1796 AL |
181 | // just the type to the unsized contents. |
182 | (v, mt.ty) | |
1a4d82fc JJ |
183 | } |
184 | } | |
185 | None => { | |
54a0048b | 186 | bug!("unexpected dereferenceable type {:?}", ty) |
62682a34 SL |
187 | } |
188 | } | |
189 | } | |
190 | ||
191 | fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
e9174d1e | 192 | def_id: DefId, |
a7813a04 | 193 | substs: &'tcx Substs<'tcx>, |
62682a34 | 194 | arg_vals: &[ValueRef], |
b039eaaf SL |
195 | param_substs: &'tcx Substs<'tcx>, |
196 | trueconst: TrueConst) -> Result<ValueRef, ConstEvalFailure> { | |
54a0048b | 197 | let fn_like = lookup_const_fn_by_id(ccx.tcx(), def_id); |
62682a34 SL |
198 | let fn_like = fn_like.expect("lookup_const_fn_by_id failed in const_fn_call"); |
199 | ||
54a0048b SL |
200 | let body = match fn_like.body().expr { |
201 | Some(ref expr) => expr, | |
202 | None => return Ok(C_nil(ccx)) | |
203 | }; | |
204 | ||
62682a34 SL |
205 | let args = &fn_like.decl().inputs; |
206 | assert_eq!(args.len(), arg_vals.len()); | |
207 | ||
208 | let arg_ids = args.iter().map(|arg| arg.pat.id); | |
209 | let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect(); | |
210 | ||
a7813a04 | 211 | let substs = ccx.tcx().mk_substs(substs.clone().erase_regions()); |
54a0048b SL |
212 | let substs = monomorphize::apply_param_substs(ccx.tcx(), |
213 | param_substs, | |
a7813a04 | 214 | &substs); |
54a0048b SL |
215 | |
216 | const_expr(ccx, body, substs, Some(&fn_args), trueconst).map(|(res, _)| res) | |
1a4d82fc JJ |
217 | } |
218 | ||
85aaf69f | 219 | pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, |
e9174d1e | 220 | def_id: DefId, |
9cc50fc6 SL |
221 | ref_expr: &hir::Expr, |
222 | param_substs: &'tcx Substs<'tcx>) | |
e9174d1e | 223 | -> &'tcx hir::Expr { |
54a0048b | 224 | let substs = ccx.tcx().node_id_item_substs(ref_expr.id).substs; |
a7813a04 | 225 | let substs = ccx.tcx().mk_substs(substs.clone().erase_regions()); |
54a0048b SL |
226 | let substs = monomorphize::apply_param_substs(ccx.tcx(), |
227 | param_substs, | |
a7813a04 | 228 | &substs); |
54a0048b SL |
229 | match lookup_const_by_id(ccx.tcx(), def_id, Some(substs)) { |
230 | Some((ref expr, _ty)) => expr, | |
d9579d0f | 231 | None => { |
54a0048b | 232 | span_bug!(ref_expr.span, "constant item not found") |
d9579d0f | 233 | } |
85aaf69f SL |
234 | } |
235 | } | |
236 | ||
b039eaaf SL |
237 | pub enum ConstEvalFailure { |
238 | /// in case the const evaluator failed on something that panic at runtime | |
239 | /// as defined in RFC 1229 | |
240 | Runtime(ConstEvalErr), | |
241 | // in case we found a true constant | |
242 | Compiletime(ConstEvalErr), | |
243 | } | |
244 | ||
245 | impl ConstEvalFailure { | |
246 | fn into_inner(self) -> ConstEvalErr { | |
247 | match self { | |
248 | Runtime(e) => e, | |
249 | Compiletime(e) => e, | |
250 | } | |
251 | } | |
5bcae85e SL |
252 | |
253 | pub fn as_inner(&self) -> &ConstEvalErr { | |
b039eaaf | 254 | match self { |
5bcae85e SL |
255 | &Runtime(ref e) => e, |
256 | &Compiletime(ref e) => e, | |
b039eaaf SL |
257 | } |
258 | } | |
259 | } | |
260 | ||
7453a54e | 261 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
b039eaaf SL |
262 | pub enum TrueConst { |
263 | Yes, No | |
264 | } | |
265 | ||
266 | use self::ConstEvalFailure::*; | |
267 | ||
9cc50fc6 SL |
268 | fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, |
269 | def_id: DefId, | |
270 | ref_expr: &hir::Expr, | |
271 | param_substs: &'tcx Substs<'tcx>) | |
272 | -> Result<ValueRef, ConstEvalFailure> { | |
273 | let expr = get_const_expr(ccx, def_id, ref_expr, param_substs); | |
54a0048b | 274 | let empty_substs = ccx.tcx().mk_substs(Substs::empty()); |
7453a54e | 275 | match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) { |
b039eaaf | 276 | Err(Runtime(err)) => { |
5bcae85e | 277 | report_const_eval_err(ccx.tcx(), &err, expr.span, "expression").emit(); |
b039eaaf SL |
278 | Err(Compiletime(err)) |
279 | }, | |
280 | other => other, | |
281 | } | |
85aaf69f SL |
282 | } |
283 | ||
284 | pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
e9174d1e | 285 | expr: &hir::Expr, |
7453a54e | 286 | qualif: ConstQualif, |
b039eaaf SL |
287 | param_substs: &'tcx Substs<'tcx>, |
288 | trueconst: TrueConst) | |
289 | -> Result<ValueRef, ConstEvalFailure> { | |
62682a34 | 290 | debug!("get_const_expr_as_global: {:?}", expr.id); |
85aaf69f | 291 | // Special-case constants to cache a common global for all uses. |
9cc50fc6 SL |
292 | if let hir::ExprPath(..) = expr.node { |
293 | // `def` must be its own statement and cannot be in the `match` | |
294 | // otherwise the `def_map` will be borrowed for the entire match instead | |
295 | // of just to get the `def` value | |
3157f602 | 296 | match ccx.tcx().expect_def(expr.id) { |
7453a54e | 297 | Def::Const(def_id) | Def::AssociatedConst(def_id) => { |
9cc50fc6 SL |
298 | if !ccx.tcx().tables.borrow().adjustments.contains_key(&expr.id) { |
299 | debug!("get_const_expr_as_global ({:?}): found const {:?}", | |
300 | expr.id, def_id); | |
301 | return get_const_val(ccx, def_id, expr, param_substs); | |
85aaf69f | 302 | } |
9cc50fc6 SL |
303 | }, |
304 | _ => {}, | |
1a4d82fc JJ |
305 | } |
306 | } | |
307 | ||
85aaf69f | 308 | let key = (expr.id, param_substs); |
9cc50fc6 SL |
309 | if let Some(&val) = ccx.const_values().borrow().get(&key) { |
310 | return Ok(val); | |
85aaf69f | 311 | } |
b039eaaf SL |
312 | let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, |
313 | &ccx.tcx().expr_ty(expr)); | |
7453a54e | 314 | let val = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) { |
85aaf69f SL |
315 | // Avoid autorefs as they would create global instead of stack |
316 | // references, even when only the latter are correct. | |
54a0048b | 317 | const_expr_unadjusted(ccx, expr, ty, param_substs, None, trueconst)? |
85aaf69f | 318 | } else { |
54a0048b | 319 | const_expr(ccx, expr, param_substs, None, trueconst)?.0 |
85aaf69f SL |
320 | }; |
321 | ||
322 | // boolean SSA values are i1, but they have to be stored in i8 slots, | |
323 | // otherwise some LLVM optimization passes don't work as expected | |
324 | let val = unsafe { | |
325 | if llvm::LLVMTypeOf(val) == Type::i1(ccx).to_ref() { | |
326 | llvm::LLVMConstZExt(val, Type::i8(ccx).to_ref()) | |
327 | } else { | |
328 | val | |
329 | } | |
330 | }; | |
331 | ||
b039eaaf | 332 | let lvalue = addr_of(ccx, val, type_of::align_of(ccx, ty), "const"); |
85aaf69f | 333 | ccx.const_values().borrow_mut().insert(key, lvalue); |
b039eaaf | 334 | Ok(lvalue) |
1a4d82fc JJ |
335 | } |
336 | ||
85aaf69f | 337 | pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, |
e9174d1e | 338 | e: &hir::Expr, |
62682a34 | 339 | param_substs: &'tcx Substs<'tcx>, |
b039eaaf SL |
340 | fn_args: FnArgMap, |
341 | trueconst: TrueConst) | |
342 | -> Result<(ValueRef, Ty<'tcx>), ConstEvalFailure> { | |
85aaf69f | 343 | let ety = monomorphize::apply_param_substs(cx.tcx(), param_substs, |
c1a9b12d | 344 | &cx.tcx().expr_ty(e)); |
54a0048b | 345 | let llconst = const_expr_unadjusted(cx, e, ety, param_substs, fn_args, trueconst)?; |
1a4d82fc | 346 | let mut llconst = llconst; |
85aaf69f | 347 | let mut ety_adjusted = monomorphize::apply_param_substs(cx.tcx(), param_substs, |
c1a9b12d SL |
348 | &cx.tcx().expr_ty_adjusted(e)); |
349 | let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned(); | |
1a4d82fc | 350 | match opt_adj { |
5bcae85e | 351 | Some(AdjustNeverToAny(..)) => span_bug!(e.span, "const expression of type ! encountered"), |
e9174d1e | 352 | Some(AdjustReifyFnPointer) => { |
54a0048b SL |
353 | match ety.sty { |
354 | ty::TyFnDef(def_id, substs, _) => { | |
355 | llconst = Callee::def(cx, def_id, substs).reify(cx).val; | |
356 | } | |
357 | _ => { | |
358 | bug!("{} cannot be reified to a fn ptr", ety) | |
359 | } | |
360 | } | |
85aaf69f | 361 | } |
7453a54e | 362 | Some(AdjustUnsafeFnPointer) | Some(AdjustMutToConstPointer) => { |
c34b1796 AL |
363 | // purely a type-level thing |
364 | } | |
e9174d1e | 365 | Some(AdjustDerefRef(adj)) => { |
85aaf69f SL |
366 | let mut ty = ety; |
367 | // Save the last autoderef in case we can avoid it. | |
368 | if adj.autoderefs > 0 { | |
369 | for _ in 0..adj.autoderefs-1 { | |
370 | let (dv, dt) = const_deref(cx, llconst, ty); | |
371 | llconst = dv; | |
372 | ty = dt; | |
1a4d82fc | 373 | } |
85aaf69f | 374 | } |
1a4d82fc | 375 | |
9346a6ac AL |
376 | if adj.autoref.is_some() { |
377 | if adj.autoderefs == 0 { | |
378 | // Don't copy data to do a deref+ref | |
379 | // (i.e., skip the last auto-deref). | |
b039eaaf | 380 | llconst = addr_of(cx, llconst, type_of::align_of(cx, ty), "autoref"); |
3157f602 | 381 | ty = cx.tcx().mk_imm_ref(cx.tcx().mk_region(ty::ReErased), ty); |
1a4d82fc | 382 | } |
54a0048b | 383 | } else if adj.autoderefs > 0 { |
9346a6ac AL |
384 | let (dv, dt) = const_deref(cx, llconst, ty); |
385 | llconst = dv; | |
386 | ||
387 | // If we derefed a fat pointer then we will have an | |
388 | // open type here. So we need to update the type with | |
389 | // the one returned from const_deref. | |
390 | ety_adjusted = dt; | |
391 | } | |
392 | ||
393 | if let Some(target) = adj.unsize { | |
394 | let target = monomorphize::apply_param_substs(cx.tcx(), | |
395 | param_substs, | |
396 | &target); | |
397 | ||
e9174d1e | 398 | let pointee_ty = ty.builtin_deref(true, ty::NoPreference) |
9346a6ac AL |
399 | .expect("consts: unsizing got non-pointer type").ty; |
400 | let (base, old_info) = if !type_is_sized(cx.tcx(), pointee_ty) { | |
401 | // Normally, the source is a thin pointer and we are | |
402 | // adding extra info to make a fat pointer. The exception | |
403 | // is when we are upcasting an existing object fat pointer | |
404 | // to use a different vtable. In that case, we want to | |
405 | // load out the original data pointer so we can repackage | |
406 | // it. | |
54a0048b SL |
407 | (const_get_elt(llconst, &[abi::FAT_PTR_ADDR as u32]), |
408 | Some(const_get_elt(llconst, &[abi::FAT_PTR_EXTRA as u32]))) | |
9346a6ac AL |
409 | } else { |
410 | (llconst, None) | |
411 | }; | |
412 | ||
e9174d1e | 413 | let unsized_ty = target.builtin_deref(true, ty::NoPreference) |
9346a6ac AL |
414 | .expect("consts: unsizing got non-pointer target type").ty; |
415 | let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to(); | |
416 | let base = ptrcast(base, ptr_ty); | |
54a0048b | 417 | let info = base::unsized_info(cx, pointee_ty, unsized_ty, old_info); |
9346a6ac | 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 | } | |
54a0048b SL |
442 | bug!("const {:?} of type {:?} has size {} instead of {}", |
443 | e, ety_adjusted, | |
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(()); } |
54a0048b SL |
464 | let cval = match to_const_int(te, t, cx.tcx()) { |
465 | Some(v) => v, | |
466 | None => return Ok(()), | |
c34b1796 | 467 | }; |
a7813a04 | 468 | const_err(cx, e.span, (-cval).map_err(ErrKind::Math), trueconst)?; |
b039eaaf | 469 | } |
a7813a04 | 470 | Ok(()) |
b039eaaf | 471 | } |
c34b1796 | 472 | |
a7813a04 | 473 | pub fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> { |
54a0048b SL |
474 | match t.sty { |
475 | ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type { | |
476 | ast::IntTy::I8 => { | |
477 | assert_eq!(input as i8 as i64, input); | |
478 | Some(ConstInt::I8(input as i8)) | |
479 | }, | |
480 | ast::IntTy::I16 => { | |
481 | assert_eq!(input as i16 as i64, input); | |
482 | Some(ConstInt::I16(input as i16)) | |
483 | }, | |
484 | ast::IntTy::I32 => { | |
485 | assert_eq!(input as i32 as i64, input); | |
486 | Some(ConstInt::I32(input as i32)) | |
487 | }, | |
488 | ast::IntTy::I64 => { | |
489 | Some(ConstInt::I64(input)) | |
490 | }, | |
491 | ast::IntTy::Is => { | |
492 | ConstIsize::new(input, tcx.sess.target.int_type) | |
493 | .ok().map(ConstInt::Isize) | |
494 | }, | |
495 | }), | |
496 | ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type { | |
497 | ast::UintTy::U8 => { | |
498 | assert_eq!(input as u8 as u64, input); | |
499 | Some(ConstInt::U8(input as u8)) | |
500 | }, | |
501 | ast::UintTy::U16 => { | |
502 | assert_eq!(input as u16 as u64, input); | |
503 | Some(ConstInt::U16(input as u16)) | |
504 | }, | |
505 | ast::UintTy::U32 => { | |
506 | assert_eq!(input as u32 as u64, input); | |
507 | Some(ConstInt::U32(input as u32)) | |
508 | }, | |
509 | ast::UintTy::U64 => { | |
510 | Some(ConstInt::U64(input)) | |
511 | }, | |
512 | ast::UintTy::Us => { | |
513 | ConstUsize::new(input, tcx.sess.target.uint_type) | |
514 | .ok().map(ConstInt::Usize) | |
515 | }, | |
516 | }), | |
517 | _ => None, | |
518 | } | |
519 | } | |
520 | ||
a7813a04 XL |
521 | pub fn const_err<T>(cx: &CrateContext, |
522 | span: Span, | |
523 | result: Result<T, ErrKind>, | |
524 | trueconst: TrueConst) | |
525 | -> Result<T, ConstEvalFailure> { | |
b039eaaf | 526 | match (result, trueconst) { |
a7813a04 | 527 | (Ok(x), _) => Ok(x), |
b039eaaf | 528 | (Err(err), TrueConst::Yes) => { |
a7813a04 | 529 | let err = ConstEvalErr{ span: span, kind: err }; |
5bcae85e | 530 | report_const_eval_err(cx.tcx(), &err, span, "expression").emit(); |
b039eaaf SL |
531 | Err(Compiletime(err)) |
532 | }, | |
533 | (Err(err), TrueConst::No) => { | |
a7813a04 | 534 | let err = ConstEvalErr{ span: span, kind: err }; |
5bcae85e SL |
535 | let mut diag = cx.tcx().sess.struct_span_warn( |
536 | span, "this expression will panic at run-time"); | |
537 | note_const_eval_err(cx.tcx(), &err, span, "expression", &mut diag); | |
538 | diag.emit(); | |
b039eaaf SL |
539 | Err(Runtime(err)) |
540 | }, | |
c34b1796 AL |
541 | } |
542 | } | |
543 | ||
e9174d1e | 544 | fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty, |
b039eaaf SL |
545 | te1: ValueRef, te2: ValueRef, |
546 | trueconst: TrueConst) -> Result<(), ConstEvalFailure> { | |
54a0048b SL |
547 | let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { bug!() }; |
548 | let (lhs, rhs) = match (to_const_int(te1, t, cx.tcx()), to_const_int(te2, t, cx.tcx())) { | |
549 | (Some(v1), Some(v2)) => (v1, v2), | |
550 | _ => return Ok(()), | |
551 | }; | |
552 | let result = match b.node { | |
553 | hir::BiAdd => lhs + rhs, | |
554 | hir::BiSub => lhs - rhs, | |
555 | hir::BiMul => lhs * rhs, | |
556 | hir::BiDiv => lhs / rhs, | |
557 | hir::BiRem => lhs % rhs, | |
558 | hir::BiShl => lhs << rhs, | |
559 | hir::BiShr => lhs >> rhs, | |
b039eaaf | 560 | _ => return Ok(()), |
c34b1796 | 561 | }; |
a7813a04 XL |
562 | const_err(cx, e.span, result.map_err(ErrKind::Math), trueconst)?; |
563 | Ok(()) | |
c34b1796 AL |
564 | } |
565 | ||
85aaf69f | 566 | fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, |
e9174d1e | 567 | e: &hir::Expr, |
85aaf69f | 568 | ety: Ty<'tcx>, |
62682a34 | 569 | param_substs: &'tcx Substs<'tcx>, |
b039eaaf SL |
570 | fn_args: FnArgMap, |
571 | trueconst: TrueConst) | |
572 | -> Result<ValueRef, ConstEvalFailure> | |
c34b1796 | 573 | { |
62682a34 SL |
574 | debug!("const_expr_unadjusted(e={:?}, ety={:?}, param_substs={:?})", |
575 | e, | |
576 | ety, | |
577 | param_substs); | |
578 | ||
b039eaaf | 579 | let map_list = |exprs: &[P<hir::Expr>]| -> Result<Vec<ValueRef>, ConstEvalFailure> { |
62682a34 | 580 | exprs.iter() |
7453a54e | 581 | .map(|e| const_expr(cx, &e, param_substs, fn_args, trueconst).map(|(l, _)| l)) |
b039eaaf SL |
582 | .collect::<Vec<Result<ValueRef, ConstEvalFailure>>>() |
583 | .into_iter() | |
62682a34 | 584 | .collect() |
b039eaaf | 585 | // this dance is necessary to eagerly run const_expr so all errors are reported |
1a4d82fc | 586 | }; |
c1a9b12d | 587 | let _icx = push_ctxt("const_expr"); |
b039eaaf | 588 | Ok(match e.node { |
7453a54e | 589 | hir::ExprLit(ref lit) => const_lit(cx, e, &lit), |
e9174d1e | 590 | hir::ExprBinary(b, ref e1, ref e2) => { |
85aaf69f SL |
591 | /* Neither type is bottom, and we expect them to be unified |
592 | * already, so the following is safe. */ | |
54a0048b SL |
593 | let (te1, ty) = const_expr(cx, &e1, param_substs, fn_args, trueconst)?; |
594 | debug!("const_expr_unadjusted: te1={:?}, ty={:?}", | |
595 | Value(te1), ty); | |
e9174d1e SL |
596 | assert!(!ty.is_simd()); |
597 | let is_float = ty.is_fp(); | |
598 | let signed = ty.is_signed(); | |
1a4d82fc | 599 | |
54a0048b SL |
600 | let (te2, ty2) = const_expr(cx, &e2, param_substs, fn_args, trueconst)?; |
601 | debug!("const_expr_unadjusted: te2={:?}, ty={:?}", | |
602 | Value(te2), ty2); | |
1a4d82fc | 603 | |
54a0048b | 604 | check_binary_expr_validity(cx, e, ty, te1, te2, trueconst)?; |
c34b1796 | 605 | |
c1a9b12d | 606 | unsafe { match b.node { |
e9174d1e SL |
607 | hir::BiAdd if is_float => llvm::LLVMConstFAdd(te1, te2), |
608 | hir::BiAdd => llvm::LLVMConstAdd(te1, te2), | |
c1a9b12d | 609 | |
e9174d1e SL |
610 | hir::BiSub if is_float => llvm::LLVMConstFSub(te1, te2), |
611 | hir::BiSub => llvm::LLVMConstSub(te1, te2), | |
c1a9b12d | 612 | |
e9174d1e SL |
613 | hir::BiMul if is_float => llvm::LLVMConstFMul(te1, te2), |
614 | hir::BiMul => llvm::LLVMConstMul(te1, te2), | |
c1a9b12d | 615 | |
e9174d1e SL |
616 | hir::BiDiv if is_float => llvm::LLVMConstFDiv(te1, te2), |
617 | hir::BiDiv if signed => llvm::LLVMConstSDiv(te1, te2), | |
618 | hir::BiDiv => llvm::LLVMConstUDiv(te1, te2), | |
c1a9b12d | 619 | |
e9174d1e SL |
620 | hir::BiRem if is_float => llvm::LLVMConstFRem(te1, te2), |
621 | hir::BiRem if signed => llvm::LLVMConstSRem(te1, te2), | |
622 | hir::BiRem => llvm::LLVMConstURem(te1, te2), | |
c1a9b12d | 623 | |
e9174d1e SL |
624 | hir::BiAnd => llvm::LLVMConstAnd(te1, te2), |
625 | hir::BiOr => llvm::LLVMConstOr(te1, te2), | |
626 | hir::BiBitXor => llvm::LLVMConstXor(te1, te2), | |
627 | hir::BiBitAnd => llvm::LLVMConstAnd(te1, te2), | |
628 | hir::BiBitOr => llvm::LLVMConstOr(te1, te2), | |
629 | hir::BiShl => { | |
c1a9b12d SL |
630 | let te2 = base::cast_shift_const_rhs(b.node, te1, te2); |
631 | llvm::LLVMConstShl(te1, te2) | |
632 | }, | |
e9174d1e | 633 | hir::BiShr => { |
c1a9b12d SL |
634 | let te2 = base::cast_shift_const_rhs(b.node, te1, te2); |
635 | if signed { llvm::LLVMConstAShr(te1, te2) } | |
636 | else { llvm::LLVMConstLShr(te1, te2) } | |
637 | }, | |
e9174d1e | 638 | hir::BiEq | hir::BiNe | hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe => { |
c1a9b12d | 639 | if is_float { |
54a0048b | 640 | let cmp = base::bin_op_to_fcmp_predicate(b.node); |
5bcae85e | 641 | llvm::LLVMConstFCmp(cmp, te1, te2) |
c1a9b12d | 642 | } else { |
54a0048b | 643 | let cmp = base::bin_op_to_icmp_predicate(b.node, signed); |
5bcae85e | 644 | llvm::LLVMConstICmp(cmp, te1, te2) |
c1a9b12d SL |
645 | } |
646 | }, | |
647 | } } // unsafe { match b.node { | |
648 | }, | |
e9174d1e | 649 | hir::ExprUnary(u, ref inner_e) => { |
54a0048b | 650 | let (te, ty) = const_expr(cx, &inner_e, param_substs, fn_args, trueconst)?; |
c34b1796 | 651 | |
54a0048b | 652 | check_unary_expr_validity(cx, e, ty, te, trueconst)?; |
c34b1796 | 653 | |
c1a9b12d SL |
654 | let is_float = ty.is_fp(); |
655 | unsafe { match u { | |
b039eaaf SL |
656 | hir::UnDeref => const_deref(cx, te, ty).0, |
657 | hir::UnNot => llvm::LLVMConstNot(te), | |
658 | hir::UnNeg if is_float => llvm::LLVMConstFNeg(te), | |
659 | hir::UnNeg => llvm::LLVMConstNeg(te), | |
c1a9b12d SL |
660 | } } |
661 | }, | |
e9174d1e | 662 | hir::ExprField(ref base, field) => { |
54a0048b | 663 | let (bv, bt) = const_expr(cx, &base, param_substs, fn_args, trueconst)?; |
c1a9b12d | 664 | let brepr = adt::represent_type(cx, bt); |
e9174d1e | 665 | let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None); |
b039eaaf | 666 | let ix = vinfo.field_index(field.node); |
54a0048b | 667 | adt::const_get_field(&brepr, bv, vinfo.discr, ix) |
c1a9b12d | 668 | }, |
e9174d1e | 669 | hir::ExprTupField(ref base, idx) => { |
54a0048b | 670 | let (bv, bt) = const_expr(cx, &base, param_substs, fn_args, trueconst)?; |
c1a9b12d | 671 | let brepr = adt::represent_type(cx, bt); |
e9174d1e | 672 | let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None); |
54a0048b | 673 | adt::const_get_field(&brepr, bv, vinfo.discr, idx.node) |
c1a9b12d | 674 | }, |
e9174d1e | 675 | hir::ExprIndex(ref base, ref index) => { |
54a0048b SL |
676 | let (bv, bt) = const_expr(cx, &base, param_substs, fn_args, trueconst)?; |
677 | let iv = const_expr(cx, &index, param_substs, fn_args, TrueConst::Yes)?.0; | |
7453a54e SL |
678 | let iv = if let Some(iv) = const_to_opt_uint(iv) { |
679 | iv | |
680 | } else { | |
54a0048b | 681 | span_bug!(index.span, "index is not an integer-constant expression"); |
c1a9b12d SL |
682 | }; |
683 | let (arr, len) = match bt.sty { | |
684 | ty::TyArray(_, u) => (bv, C_uint(cx, u)), | |
7453a54e | 685 | ty::TySlice(..) | ty::TyStr => { |
54a0048b SL |
686 | let e1 = const_get_elt(bv, &[0]); |
687 | (load_const(cx, e1, bt), const_get_elt(bv, &[1])) | |
c1a9b12d SL |
688 | }, |
689 | ty::TyRef(_, mt) => match mt.ty.sty { | |
690 | ty::TyArray(_, u) => { | |
7453a54e | 691 | (load_const(cx, bv, mt.ty), C_uint(cx, u)) |
c1a9b12d | 692 | }, |
54a0048b SL |
693 | _ => span_bug!(base.span, |
694 | "index-expr base must be a vector \ | |
695 | or string type, found {:?}", | |
696 | bt), | |
c1a9b12d | 697 | }, |
54a0048b SL |
698 | _ => span_bug!(base.span, |
699 | "index-expr base must be a vector \ | |
700 | or string type, found {:?}", | |
701 | bt), | |
c1a9b12d SL |
702 | }; |
703 | ||
704 | let len = unsafe { llvm::LLVMConstIntGetZExtValue(len) as u64 }; | |
705 | let len = match bt.sty { | |
706 | ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) => match ty.sty { | |
707 | ty::TyStr => { | |
708 | assert!(len > 0); | |
709 | len - 1 | |
710 | }, | |
711 | _ => len, | |
712 | }, | |
713 | _ => len, | |
714 | }; | |
715 | if iv >= len { | |
716 | // FIXME #3170: report this earlier on in the const-eval | |
717 | // pass. Reporting here is a bit late. | |
3157f602 XL |
718 | const_err(cx, e.span, Err(ErrKind::IndexOutOfBounds { |
719 | len: len, | |
720 | index: iv | |
721 | }), trueconst)?; | |
b039eaaf | 722 | C_undef(val_ty(arr).element_type()) |
c1a9b12d | 723 | } else { |
54a0048b | 724 | const_get_elt(arr, &[iv as c_uint]) |
1a4d82fc | 725 | } |
c1a9b12d | 726 | }, |
e9174d1e | 727 | hir::ExprCast(ref base, _) => { |
62682a34 SL |
728 | let t_cast = ety; |
729 | let llty = type_of::type_of(cx, t_cast); | |
54a0048b | 730 | let (v, t_expr) = const_expr(cx, &base, param_substs, fn_args, trueconst)?; |
62682a34 SL |
731 | debug!("trans_const_cast({:?} as {:?})", t_expr, t_cast); |
732 | if expr::cast_is_noop(cx.tcx(), base, t_expr, t_cast) { | |
b039eaaf | 733 | return Ok(v); |
85aaf69f | 734 | } |
62682a34 SL |
735 | if type_is_fat_ptr(cx.tcx(), t_expr) { |
736 | // Fat pointer casts. | |
e9174d1e SL |
737 | let t_cast_inner = |
738 | t_cast.builtin_deref(true, ty::NoPreference).expect("cast to non-pointer").ty; | |
62682a34 | 739 | let ptr_ty = type_of::in_memory_type_of(cx, t_cast_inner).ptr_to(); |
54a0048b | 740 | let addr = ptrcast(const_get_elt(v, &[abi::FAT_PTR_ADDR as u32]), |
62682a34 SL |
741 | ptr_ty); |
742 | if type_is_fat_ptr(cx.tcx(), t_cast) { | |
54a0048b | 743 | let info = const_get_elt(v, &[abi::FAT_PTR_EXTRA as u32]); |
b039eaaf | 744 | return Ok(C_struct(cx, &[addr, info], false)) |
62682a34 | 745 | } else { |
b039eaaf | 746 | return Ok(addr); |
62682a34 SL |
747 | } |
748 | } | |
c1a9b12d | 749 | unsafe { match ( |
e9174d1e SL |
750 | CastTy::from_ty(t_expr).expect("bad input type for cast"), |
751 | CastTy::from_ty(t_cast).expect("bad output type for cast"), | |
c1a9b12d SL |
752 | ) { |
753 | (CastTy::Int(IntTy::CEnum), CastTy::Int(_)) => { | |
754 | let repr = adt::represent_type(cx, t_expr); | |
54a0048b | 755 | let discr = adt::const_get_discrim(&repr, v); |
9cc50fc6 | 756 | let iv = C_integral(cx.int_type(), discr.0, false); |
7453a54e | 757 | let s = adt::is_discr_signed(&repr) as Bool; |
c1a9b12d SL |
758 | llvm::LLVMConstIntCast(iv, llty.to_ref(), s) |
759 | }, | |
760 | (CastTy::Int(_), CastTy::Int(_)) => { | |
761 | let s = t_expr.is_signed() as Bool; | |
762 | llvm::LLVMConstIntCast(v, llty.to_ref(), s) | |
763 | }, | |
764 | (CastTy::Int(_), CastTy::Float) => { | |
765 | if t_expr.is_signed() { | |
766 | llvm::LLVMConstSIToFP(v, llty.to_ref()) | |
767 | } else { | |
768 | llvm::LLVMConstUIToFP(v, llty.to_ref()) | |
769 | } | |
770 | }, | |
771 | (CastTy::Float, CastTy::Float) => llvm::LLVMConstFPCast(v, llty.to_ref()), | |
772 | (CastTy::Float, CastTy::Int(IntTy::I)) => llvm::LLVMConstFPToSI(v, llty.to_ref()), | |
773 | (CastTy::Float, CastTy::Int(_)) => llvm::LLVMConstFPToUI(v, llty.to_ref()), | |
774 | (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_)) | |
775 | | (CastTy::RPtr(_), CastTy::Ptr(_)) => { | |
776 | ptrcast(v, llty) | |
777 | }, | |
778 | (CastTy::FnPtr, CastTy::FnPtr) => ptrcast(v, llty), // isn't this a coercion? | |
779 | (CastTy::Int(_), CastTy::Ptr(_)) => llvm::LLVMConstIntToPtr(v, llty.to_ref()), | |
780 | (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => { | |
781 | llvm::LLVMConstPtrToInt(v, llty.to_ref()) | |
782 | }, | |
783 | _ => { | |
54a0048b | 784 | span_bug!(e.span, "bad combination of types for cast") |
c1a9b12d SL |
785 | }, |
786 | } } // unsafe { match ( ... ) { | |
787 | }, | |
e9174d1e | 788 | hir::ExprAddrOf(hir::MutImmutable, ref sub) => { |
c1a9b12d SL |
789 | // If this is the address of some static, then we need to return |
790 | // the actual address of the static itself (short circuit the rest | |
791 | // of const eval). | |
792 | let mut cur = sub; | |
793 | loop { | |
794 | match cur.node { | |
e9174d1e | 795 | hir::ExprBlock(ref blk) => { |
85aaf69f SL |
796 | if let Some(ref sub) = blk.expr { |
797 | cur = sub; | |
798 | } else { | |
799 | break; | |
800 | } | |
c1a9b12d SL |
801 | }, |
802 | _ => break, | |
803 | } | |
804 | } | |
3157f602 | 805 | if let Some(Def::Static(def_id, _)) = cx.tcx().expect_def_or_none(cur.id) { |
54a0048b | 806 | get_static(cx, def_id).val |
c1a9b12d SL |
807 | } else { |
808 | // If this isn't the address of a static, then keep going through | |
809 | // normal constant evaluation. | |
54a0048b | 810 | let (v, ty) = const_expr(cx, &sub, param_substs, fn_args, trueconst)?; |
b039eaaf | 811 | addr_of(cx, v, type_of::align_of(cx, ty), "ref") |
c1a9b12d SL |
812 | } |
813 | }, | |
e9174d1e | 814 | hir::ExprAddrOf(hir::MutMutable, ref sub) => { |
54a0048b | 815 | let (v, ty) = const_expr(cx, &sub, param_substs, fn_args, trueconst)?; |
b039eaaf | 816 | addr_of_mut(cx, v, type_of::align_of(cx, ty), "ref_mut_slice") |
c1a9b12d | 817 | }, |
e9174d1e | 818 | hir::ExprTup(ref es) => { |
c1a9b12d | 819 | let repr = adt::represent_type(cx, ety); |
54a0048b | 820 | let vals = map_list(&es[..])?; |
7453a54e | 821 | adt::trans_const(cx, &repr, Disr(0), &vals[..]) |
c1a9b12d | 822 | }, |
e9174d1e | 823 | hir::ExprStruct(_, ref fs, ref base_opt) => { |
c1a9b12d SL |
824 | let repr = adt::represent_type(cx, ety); |
825 | ||
826 | let base_val = match *base_opt { | |
54a0048b | 827 | Some(ref base) => Some(const_expr( |
b039eaaf | 828 | cx, |
7453a54e | 829 | &base, |
b039eaaf SL |
830 | param_substs, |
831 | fn_args, | |
832 | trueconst, | |
54a0048b | 833 | )?), |
1a4d82fc | 834 | None => None |
c1a9b12d SL |
835 | }; |
836 | ||
e9174d1e SL |
837 | let VariantInfo { discr, fields } = VariantInfo::of_node(cx.tcx(), ety, e.id); |
838 | let cs = fields.iter().enumerate().map(|(ix, &Field(f_name, _))| { | |
b039eaaf SL |
839 | match (fs.iter().find(|f| f_name == f.name.node), base_val) { |
840 | (Some(ref f), _) => { | |
7453a54e | 841 | const_expr(cx, &f.expr, param_substs, fn_args, trueconst).map(|(l, _)| l) |
b039eaaf | 842 | }, |
54a0048b SL |
843 | (_, Some((bv, _))) => Ok(adt::const_get_field(&repr, bv, discr, ix)), |
844 | (_, None) => span_bug!(e.span, "missing struct field"), | |
c1a9b12d | 845 | } |
b039eaaf SL |
846 | }) |
847 | .collect::<Vec<Result<_, ConstEvalFailure>>>() | |
848 | .into_iter() | |
849 | .collect::<Result<Vec<_>,ConstEvalFailure>>(); | |
54a0048b | 850 | let cs = cs?; |
e9174d1e SL |
851 | if ety.is_simd() { |
852 | C_vector(&cs[..]) | |
853 | } else { | |
7453a54e | 854 | adt::trans_const(cx, &repr, discr, &cs[..]) |
e9174d1e | 855 | } |
c1a9b12d | 856 | }, |
e9174d1e | 857 | hir::ExprVec(ref es) => { |
c1a9b12d | 858 | let unit_ty = ety.sequence_element_type(cx.tcx()); |
85aaf69f | 859 | let llunitty = type_of::type_of(cx, unit_ty); |
c1a9b12d | 860 | let vs = es.iter() |
b039eaaf SL |
861 | .map(|e| const_expr( |
862 | cx, | |
7453a54e | 863 | &e, |
b039eaaf SL |
864 | param_substs, |
865 | fn_args, | |
866 | trueconst, | |
867 | ).map(|(l, _)| l)) | |
868 | .collect::<Vec<Result<_, ConstEvalFailure>>>() | |
869 | .into_iter() | |
870 | .collect::<Result<Vec<_>, ConstEvalFailure>>(); | |
54a0048b | 871 | let vs = vs?; |
85aaf69f SL |
872 | // If the vector contains enums, an LLVM array won't work. |
873 | if vs.iter().any(|vi| val_ty(*vi) != llunitty) { | |
874 | C_struct(cx, &vs[..], false) | |
875 | } else { | |
876 | C_array(llunitty, &vs[..]) | |
877 | } | |
c1a9b12d | 878 | }, |
e9174d1e | 879 | hir::ExprRepeat(ref elem, ref count) => { |
c1a9b12d | 880 | let unit_ty = ety.sequence_element_type(cx.tcx()); |
1a4d82fc | 881 | let llunitty = type_of::type_of(cx, unit_ty); |
5bcae85e | 882 | let n = eval_length(cx.tcx(), count, "repeat count").unwrap(); |
54a0048b | 883 | let unit_val = const_expr(cx, &elem, param_substs, fn_args, trueconst)?.0; |
c1a9b12d | 884 | let vs = vec![unit_val; n]; |
85aaf69f SL |
885 | if val_ty(unit_val) != llunitty { |
886 | C_struct(cx, &vs[..], false) | |
1a4d82fc | 887 | } else { |
85aaf69f | 888 | C_array(llunitty, &vs[..]) |
1a4d82fc | 889 | } |
c1a9b12d | 890 | }, |
e9174d1e | 891 | hir::ExprPath(..) => { |
3157f602 | 892 | match cx.tcx().expect_def(e.id) { |
7453a54e | 893 | Def::Local(_, id) => { |
62682a34 SL |
894 | if let Some(val) = fn_args.and_then(|args| args.get(&id).cloned()) { |
895 | val | |
896 | } else { | |
54a0048b | 897 | span_bug!(e.span, "const fn argument not found") |
62682a34 SL |
898 | } |
899 | } | |
54a0048b | 900 | Def::Fn(..) | Def::Method(..) => C_nil(cx), |
7453a54e | 901 | Def::Const(def_id) | Def::AssociatedConst(def_id) => { |
54a0048b | 902 | load_const(cx, get_const_val(cx, def_id, e, param_substs)?, |
7453a54e | 903 | ety) |
1a4d82fc | 904 | } |
7453a54e | 905 | Def::Variant(enum_did, variant_did) => { |
e9174d1e | 906 | let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did); |
5bcae85e | 907 | match vinfo.kind { |
e9174d1e SL |
908 | ty::VariantKind::Unit => { |
909 | let repr = adt::represent_type(cx, ety); | |
7453a54e | 910 | adt::trans_const(cx, &repr, Disr::from(vinfo.disr_val), &[]) |
e9174d1e | 911 | } |
54a0048b | 912 | ty::VariantKind::Tuple => C_nil(cx), |
b039eaaf | 913 | ty::VariantKind::Struct => { |
54a0048b | 914 | span_bug!(e.span, "path-expr refers to a dict variant!") |
e9174d1e | 915 | } |
1a4d82fc JJ |
916 | } |
917 | } | |
54a0048b SL |
918 | // Unit struct or ctor. |
919 | Def::Struct(..) => C_null(type_of::type_of(cx, ety)), | |
1a4d82fc | 920 | _ => { |
54a0048b SL |
921 | span_bug!(e.span, "expected a const, fn, struct, \ |
922 | or variant def") | |
1a4d82fc JJ |
923 | } |
924 | } | |
c1a9b12d | 925 | }, |
e9174d1e | 926 | hir::ExprCall(ref callee, ref args) => { |
c1a9b12d SL |
927 | let mut callee = &**callee; |
928 | loop { | |
929 | callee = match callee.node { | |
e9174d1e | 930 | hir::ExprBlock(ref block) => match block.expr { |
7453a54e | 931 | Some(ref tail) => &tail, |
c1a9b12d SL |
932 | None => break, |
933 | }, | |
934 | _ => break, | |
935 | }; | |
936 | } | |
54a0048b | 937 | let arg_vals = map_list(args)?; |
3157f602 | 938 | match cx.tcx().expect_def(callee.id) { |
7453a54e | 939 | Def::Fn(did) | Def::Method(did) => { |
54a0048b | 940 | const_fn_call( |
b039eaaf | 941 | cx, |
b039eaaf | 942 | did, |
54a0048b | 943 | cx.tcx().node_id_item_substs(callee.id).substs, |
b039eaaf SL |
944 | &arg_vals, |
945 | param_substs, | |
946 | trueconst, | |
54a0048b | 947 | )? |
c1a9b12d | 948 | } |
7453a54e | 949 | Def::Struct(..) => { |
e9174d1e | 950 | if ety.is_simd() { |
c1a9b12d SL |
951 | C_vector(&arg_vals[..]) |
952 | } else { | |
953 | let repr = adt::represent_type(cx, ety); | |
7453a54e | 954 | adt::trans_const(cx, &repr, Disr(0), &arg_vals[..]) |
c1a9b12d SL |
955 | } |
956 | } | |
7453a54e | 957 | Def::Variant(enum_did, variant_did) => { |
c1a9b12d | 958 | let repr = adt::represent_type(cx, ety); |
e9174d1e | 959 | let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did); |
c1a9b12d | 960 | adt::trans_const(cx, |
7453a54e | 961 | &repr, |
9cc50fc6 | 962 | Disr::from(vinfo.disr_val), |
c1a9b12d SL |
963 | &arg_vals[..]) |
964 | } | |
54a0048b | 965 | _ => span_bug!(e.span, "expected a struct, variant, or const fn def"), |
c1a9b12d SL |
966 | } |
967 | }, | |
e9174d1e | 968 | hir::ExprMethodCall(_, _, ref args) => { |
54a0048b | 969 | let arg_vals = map_list(args)?; |
c1a9b12d | 970 | let method_call = ty::MethodCall::expr(e.id); |
54a0048b | 971 | let method = cx.tcx().tables.borrow().method_map[&method_call]; |
a7813a04 | 972 | const_fn_call(cx, method.def_id, method.substs, |
54a0048b | 973 | &arg_vals, param_substs, trueconst)? |
c1a9b12d | 974 | }, |
54a0048b | 975 | hir::ExprType(ref e, _) => const_expr(cx, &e, param_substs, fn_args, trueconst)?.0, |
e9174d1e | 976 | hir::ExprBlock(ref block) => { |
1a4d82fc | 977 | match block.expr { |
54a0048b | 978 | Some(ref expr) => const_expr( |
b039eaaf | 979 | cx, |
7453a54e | 980 | &expr, |
b039eaaf SL |
981 | param_substs, |
982 | fn_args, | |
983 | trueconst, | |
54a0048b | 984 | )?.0, |
c1a9b12d SL |
985 | None => C_nil(cx), |
986 | } | |
987 | }, | |
a7813a04 | 988 | hir::ExprClosure(_, ref decl, ref body, _) => { |
c1a9b12d | 989 | match ety.sty { |
a7813a04 | 990 | ty::TyClosure(def_id, substs) => { |
9cc50fc6 SL |
991 | closure::trans_closure_expr(closure::Dest::Ignore(cx), |
992 | decl, | |
993 | body, | |
994 | e.id, | |
995 | def_id, | |
54a0048b | 996 | substs); |
c1a9b12d SL |
997 | } |
998 | _ => | |
54a0048b | 999 | span_bug!( |
c1a9b12d | 1000 | e.span, |
54a0048b | 1001 | "bad type for closure expr: {:?}", ety) |
1a4d82fc | 1002 | } |
85aaf69f | 1003 | C_null(type_of::type_of(cx, ety)) |
c1a9b12d | 1004 | }, |
54a0048b SL |
1005 | _ => span_bug!(e.span, |
1006 | "bad constant expression type in consts::const_expr"), | |
b039eaaf | 1007 | }) |
1a4d82fc | 1008 | } |
b039eaaf | 1009 | |
54a0048b SL |
1010 | pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) |
1011 | -> Datum<'tcx, Lvalue> { | |
1012 | let ty = ccx.tcx().lookup_item_type(def_id).ty; | |
1013 | ||
a7813a04 | 1014 | let instance = Instance::mono(ccx.shared(), def_id); |
54a0048b SL |
1015 | if let Some(&g) = ccx.instances().borrow().get(&instance) { |
1016 | return Datum::new(g, ty, Lvalue::new("static")); | |
1017 | } | |
1018 | ||
1019 | let g = if let Some(id) = ccx.tcx().map.as_local_node_id(def_id) { | |
5bcae85e | 1020 | |
54a0048b | 1021 | let llty = type_of::type_of(ccx, ty); |
5bcae85e | 1022 | let (g, attrs) = match ccx.tcx().map.get(id) { |
54a0048b | 1023 | hir_map::NodeItem(&hir::Item { |
5bcae85e | 1024 | ref attrs, span, node: hir::ItemStatic(..), .. |
54a0048b | 1025 | }) => { |
5bcae85e SL |
1026 | let sym = ccx.symbol_map() |
1027 | .get(TransItem::Static(id)) | |
1028 | .expect("Local statics should always be in the SymbolMap"); | |
1029 | // Make sure that this is never executed for something inlined. | |
1030 | assert!(!ccx.tcx().map.is_inlined_node_id(id)); | |
1031 | ||
1032 | let defined_in_current_codegen_unit = ccx.codegen_unit() | |
1033 | .items() | |
1034 | .contains_key(&TransItem::Static(id)); | |
1035 | if defined_in_current_codegen_unit { | |
1036 | if declare::get_declared_value(ccx, sym).is_none() { | |
1037 | span_bug!(span, "trans: Static not properly pre-defined?"); | |
1038 | } | |
1039 | } else { | |
1040 | if declare::get_declared_value(ccx, sym).is_some() { | |
1041 | span_bug!(span, "trans: Conflicting symbol names for static?"); | |
1042 | } | |
1043 | } | |
1044 | ||
1045 | let g = declare::define_global(ccx, sym, llty).unwrap(); | |
1046 | ||
1047 | (g, attrs) | |
54a0048b SL |
1048 | } |
1049 | ||
1050 | hir_map::NodeForeignItem(&hir::ForeignItem { | |
3157f602 | 1051 | ref attrs, span, node: hir::ForeignItemStatic(..), .. |
54a0048b | 1052 | }) => { |
5bcae85e | 1053 | let sym = instance.symbol_name(ccx.shared()); |
54a0048b SL |
1054 | let g = if let Some(name) = |
1055 | attr::first_attr_value_str_by_name(&attrs, "linkage") { | |
1056 | // If this is a static with a linkage specified, then we need to handle | |
1057 | // it a little specially. The typesystem prevents things like &T and | |
1058 | // extern "C" fn() from being non-null, so we can't just declare a | |
1059 | // static and call it a day. Some linkages (like weak) will make it such | |
1060 | // that the static actually has a null value. | |
1061 | let linkage = match base::llvm_linkage_by_name(&name) { | |
1062 | Some(linkage) => linkage, | |
1063 | None => { | |
1064 | ccx.sess().span_fatal(span, "invalid linkage specified"); | |
1065 | } | |
1066 | }; | |
1067 | let llty2 = match ty.sty { | |
1068 | ty::TyRawPtr(ref mt) => type_of::type_of(ccx, mt.ty), | |
1069 | _ => { | |
1070 | ccx.sess().span_fatal(span, "must have type `*const T` or `*mut T`"); | |
1071 | } | |
1072 | }; | |
1073 | unsafe { | |
1074 | // Declare a symbol `foo` with the desired linkage. | |
3157f602 | 1075 | let g1 = declare::declare_global(ccx, &sym, llty2); |
5bcae85e | 1076 | llvm::LLVMSetLinkage(g1, linkage); |
54a0048b SL |
1077 | |
1078 | // Declare an internal global `extern_with_linkage_foo` which | |
1079 | // is initialized with the address of `foo`. If `foo` is | |
1080 | // discarded during linking (for example, if `foo` has weak | |
1081 | // linkage and there are no definitions), then | |
1082 | // `extern_with_linkage_foo` will instead be initialized to | |
1083 | // zero. | |
1084 | let mut real_name = "_rust_extern_with_linkage_".to_string(); | |
3157f602 | 1085 | real_name.push_str(&sym); |
54a0048b SL |
1086 | let g2 = declare::define_global(ccx, &real_name, llty).unwrap_or_else(||{ |
1087 | ccx.sess().span_fatal(span, | |
5bcae85e | 1088 | &format!("symbol `{}` is already defined", &sym)) |
54a0048b | 1089 | }); |
5bcae85e | 1090 | llvm::LLVMSetLinkage(g2, llvm::InternalLinkage); |
54a0048b SL |
1091 | llvm::LLVMSetInitializer(g2, g1); |
1092 | g2 | |
1093 | } | |
1094 | } else { | |
1095 | // Generate an external declaration. | |
3157f602 | 1096 | declare::declare_global(ccx, &sym, llty) |
54a0048b SL |
1097 | }; |
1098 | ||
5bcae85e | 1099 | (g, attrs) |
54a0048b SL |
1100 | } |
1101 | ||
1102 | item => bug!("get_static: expected static, found {:?}", item) | |
5bcae85e SL |
1103 | }; |
1104 | ||
1105 | for attr in attrs { | |
1106 | if attr.check_name("thread_local") { | |
1107 | llvm::set_thread_local(g, true); | |
1108 | } | |
54a0048b | 1109 | } |
5bcae85e SL |
1110 | |
1111 | g | |
54a0048b | 1112 | } else { |
5bcae85e SL |
1113 | let sym = instance.symbol_name(ccx.shared()); |
1114 | ||
54a0048b SL |
1115 | // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? |
1116 | // FIXME(nagisa): investigate whether it can be changed into define_global | |
3157f602 | 1117 | let g = declare::declare_global(ccx, &sym, type_of::type_of(ccx, ty)); |
54a0048b SL |
1118 | // Thread-local statics in some other crate need to *always* be linked |
1119 | // against in a thread-local fashion, so we need to be sure to apply the | |
1120 | // thread-local attribute locally if it was present remotely. If we | |
1121 | // don't do this then linker errors can be generated where the linker | |
1122 | // complains that one object files has a thread local version of the | |
1123 | // symbol and another one doesn't. | |
1124 | for attr in ccx.tcx().get_attrs(def_id).iter() { | |
1125 | if attr.check_name("thread_local") { | |
1126 | llvm::set_thread_local(g, true); | |
1127 | } | |
1128 | } | |
1129 | if ccx.use_dll_storage_attrs() { | |
5bcae85e SL |
1130 | unsafe { |
1131 | llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); | |
1132 | } | |
54a0048b SL |
1133 | } |
1134 | g | |
1135 | }; | |
1136 | ||
1137 | ccx.instances().borrow_mut().insert(instance, g); | |
a7813a04 | 1138 | ccx.statics().borrow_mut().insert(g, def_id); |
54a0048b SL |
1139 | Datum::new(g, ty, Lvalue::new("static")) |
1140 | } | |
1141 | ||
c1a9b12d | 1142 | pub fn trans_static(ccx: &CrateContext, |
e9174d1e SL |
1143 | m: hir::Mutability, |
1144 | expr: &hir::Expr, | |
c1a9b12d | 1145 | id: ast::NodeId, |
9cc50fc6 | 1146 | attrs: &[ast::Attribute]) |
b039eaaf | 1147 | -> Result<ValueRef, ConstEvalErr> { |
1a4d82fc JJ |
1148 | unsafe { |
1149 | let _icx = push_ctxt("trans_static"); | |
54a0048b SL |
1150 | let def_id = ccx.tcx().map.local_def_id(id); |
1151 | let datum = get_static(ccx, def_id); | |
c1a9b12d | 1152 | |
a7813a04 XL |
1153 | let check_attrs = |attrs: &[ast::Attribute]| { |
1154 | let default_to_mir = ccx.sess().opts.debugging_opts.orbit; | |
1155 | let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" }; | |
1156 | default_to_mir ^ attrs.iter().any(|item| item.check_name(invert)) | |
1157 | }; | |
1158 | let use_mir = check_attrs(ccx.tcx().map.attrs(id)); | |
1159 | ||
1160 | let v = if use_mir { | |
1161 | ::mir::trans_static_initializer(ccx, def_id) | |
1162 | } else { | |
1163 | let empty_substs = ccx.tcx().mk_substs(Substs::empty()); | |
1164 | const_expr(ccx, expr, empty_substs, None, TrueConst::Yes) | |
1165 | .map(|(v, _)| v) | |
1166 | }.map_err(|e| e.into_inner())?; | |
c1a9b12d | 1167 | |
1a4d82fc JJ |
1168 | // boolean SSA values are i1, but they have to be stored in i8 slots, |
1169 | // otherwise some LLVM optimization passes don't work as expected | |
54a0048b SL |
1170 | let mut val_llty = val_ty(v); |
1171 | let v = if val_llty == Type::i1(ccx) { | |
1172 | val_llty = Type::i8(ccx); | |
1173 | llvm::LLVMConstZExt(v, val_llty.to_ref()) | |
1a4d82fc JJ |
1174 | } else { |
1175 | v | |
1176 | }; | |
c1a9b12d | 1177 | |
54a0048b SL |
1178 | let llty = type_of::type_of(ccx, datum.ty); |
1179 | let g = if val_llty == llty { | |
1180 | datum.val | |
c1a9b12d SL |
1181 | } else { |
1182 | // If we created the global with the wrong type, | |
1183 | // correct the type. | |
1184 | let empty_string = CString::new("").unwrap(); | |
54a0048b | 1185 | let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(datum.val)); |
c1a9b12d | 1186 | let name_string = CString::new(name_str_ref.to_bytes()).unwrap(); |
54a0048b | 1187 | llvm::LLVMSetValueName(datum.val, empty_string.as_ptr()); |
5bcae85e | 1188 | let new_g = llvm::LLVMRustGetOrInsertGlobal( |
54a0048b | 1189 | ccx.llmod(), name_string.as_ptr(), val_llty.to_ref()); |
c1a9b12d SL |
1190 | // To avoid breaking any invariants, we leave around the old |
1191 | // global for the moment; we'll replace all references to it | |
1192 | // with the new global later. (See base::trans_crate.) | |
54a0048b | 1193 | ccx.statics_to_rauw().borrow_mut().push((datum.val, new_g)); |
c1a9b12d SL |
1194 | new_g |
1195 | }; | |
54a0048b | 1196 | llvm::LLVMSetAlignment(g, type_of::align_of(ccx, datum.ty)); |
1a4d82fc JJ |
1197 | llvm::LLVMSetInitializer(g, v); |
1198 | ||
1199 | // As an optimization, all shared statics which do not have interior | |
1200 | // mutability are placed into read-only memory. | |
e9174d1e | 1201 | if m != hir::MutMutable { |
54a0048b | 1202 | let tcontents = datum.ty.type_contents(ccx.tcx()); |
1a4d82fc | 1203 | if !tcontents.interior_unsafe() { |
c1a9b12d | 1204 | llvm::LLVMSetGlobalConstant(g, llvm::True); |
1a4d82fc JJ |
1205 | } |
1206 | } | |
c1a9b12d | 1207 | |
1a4d82fc | 1208 | debuginfo::create_global_var_metadata(ccx, id, g); |
c1a9b12d SL |
1209 | |
1210 | if attr::contains_name(attrs, | |
1211 | "thread_local") { | |
1212 | llvm::set_thread_local(g, true); | |
1213 | } | |
5bcae85e SL |
1214 | |
1215 | base::set_link_section(ccx, g, attrs); | |
1216 | ||
b039eaaf | 1217 | Ok(g) |
1a4d82fc JJ |
1218 | } |
1219 | } |