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 lib::llvm::{llvm, ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True,
14 False};
15 use lib::llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE,
16 RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE};
17
18 use metadata::csearch;
19 use middle::const_eval;
20 use middle::trans::adt;
21 use middle::trans::base;
22 use middle::trans::base::push_ctxt;
23 use middle::trans::closure;
24 use middle::trans::common::*;
25 use middle::trans::consts;
26 use middle::trans::expr;
27 use middle::trans::inline;
28 use middle::trans::machine;
29 use middle::trans::type_::Type;
30 use middle::trans::type_of;
31 use middle::trans::debuginfo;
32 use middle::ty;
33 use util::ppaux::{Repr, ty_to_str};
34
35 use std::c_str::ToCStr;
36 use std::vec;
37 use std::vec::Vec;
38 use libc::c_uint;
39 use syntax::{ast, ast_util};
40
41 pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: ast::Lit)
42 -> ValueRef {
43 let _icx = push_ctxt("trans_lit");
44 match lit.node {
45 ast::LitChar(i) => C_integral(Type::char(cx), i as u64, false),
46 ast::LitInt(i, t) => C_integral(Type::int_from_ty(cx, t), i as u64, true),
47 ast::LitUint(u, t) => C_integral(Type::uint_from_ty(cx, t), u, false),
48 ast::LitIntUnsuffixed(i) => {
49 let lit_int_ty = ty::node_id_to_type(cx.tcx(), e.id);
50 match ty::get(lit_int_ty).sty {
51 ty::ty_int(t) => {
52 C_integral(Type::int_from_ty(cx, t), i as u64, true)
53 }
54 ty::ty_uint(t) => {
55 C_integral(Type::uint_from_ty(cx, t), i as u64, false)
56 }
57 _ => cx.sess().span_bug(lit.span,
58 format!("integer literal has type {} (expected int or uint)",
59 ty_to_str(cx.tcx(), lit_int_ty)))
60 }
61 }
62 ast::LitFloat(ref fs, t) => {
63 C_floating(fs.get(), Type::float_from_ty(cx, t))
64 }
65 ast::LitFloatUnsuffixed(ref fs) => {
66 let lit_float_ty = ty::node_id_to_type(cx.tcx(), e.id);
67 match ty::get(lit_float_ty).sty {
68 ty::ty_float(t) => {
69 C_floating(fs.get(), Type::float_from_ty(cx, t))
70 }
71 _ => {
72 cx.sess().span_bug(lit.span,
73 "floating point literal doesn't have the right type");
74 }
75 }
76 }
77 ast::LitBool(b) => C_bool(cx, b),
78 ast::LitNil => C_nil(cx),
79 ast::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()),
80 ast::LitBinary(ref data) => C_binary_slice(cx, data.as_slice()),
81 }
82 }
83
84 pub fn const_ptrcast(cx: &CrateContext, a: ValueRef, t: Type) -> ValueRef {
85 unsafe {
86 let b = llvm::LLVMConstPointerCast(a, t.ptr_to().to_ref());
87 assert!(cx.const_globals.borrow_mut().insert(b as int, a));
88 b
89 }
90 }
91
92 fn const_vec(cx: &CrateContext, e: &ast::Expr,
93 es: &[@ast::Expr], is_local: bool) -> (ValueRef, Type, bool) {
94 let vec_ty = ty::expr_ty(cx.tcx(), e);
95 let unit_ty = ty::sequence_element_type(cx.tcx(), vec_ty);
96 let llunitty = type_of::type_of(cx, unit_ty);
97 let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e, is_local)));
98 // If the vector contains enums, an LLVM array won't work.
99 let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
100 C_struct(cx, vs.as_slice(), false)
101 } else {
102 C_array(llunitty, vs.as_slice())
103 };
104 (v, llunitty, inlineable.iter().fold(true, |a, &b| a && b))
105 }
106
107 fn const_addr_of(cx: &CrateContext, cv: ValueRef) -> ValueRef {
108 unsafe {
109 let gv = "const".with_c_str(|name| {
110 llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name)
111 });
112 llvm::LLVMSetInitializer(gv, cv);
113 llvm::LLVMSetGlobalConstant(gv, True);
114 SetLinkage(gv, PrivateLinkage);
115 gv
116 }
117 }
118
119 fn const_deref_ptr(cx: &CrateContext, v: ValueRef) -> ValueRef {
120 let v = match cx.const_globals.borrow().find(&(v as int)) {
121 Some(&v) => v,
122 None => v
123 };
124 unsafe {
125 assert_eq!(llvm::LLVMIsGlobalConstant(v), True);
126 llvm::LLVMGetInitializer(v)
127 }
128 }
129
130 fn const_deref_newtype(cx: &CrateContext, v: ValueRef, t: ty::t)
131 -> ValueRef {
132 let repr = adt::represent_type(cx, t);
133 adt::const_get_field(cx, &*repr, v, 0, 0)
134 }
135
136 fn const_deref(cx: &CrateContext, v: ValueRef, t: ty::t, explicit: bool)
137 -> (ValueRef, ty::t) {
138 match ty::deref(t, explicit) {
139 Some(ref mt) => {
140 assert!(mt.mutbl != ast::MutMutable);
141 let dv = match ty::get(t).sty {
142 ty::ty_ptr(mt) | ty::ty_rptr(_, mt) => {
143 match ty::get(mt.ty).sty {
144 ty::ty_vec(_, None) | ty::ty_str => cx.sess().bug("unexpected slice"),
145 _ => const_deref_ptr(cx, v),
146 }
147 }
148 ty::ty_enum(..) | ty::ty_struct(..) => {
149 const_deref_newtype(cx, v, t)
150 }
151 _ => {
152 cx.sess().bug(format!("unexpected dereferenceable type {}",
153 ty_to_str(cx.tcx(), t)))
154 }
155 };
156 (dv, mt.ty)
157 }
158 None => {
159 cx.sess().bug(format!("can't dereference const of type {}",
160 ty_to_str(cx.tcx(), t)))
161 }
162 }
163 }
164
165 pub fn get_const_val(cx: &CrateContext,
166 mut def_id: ast::DefId) -> (ValueRef, bool) {
167 let contains_key = cx.const_values.borrow().contains_key(&def_id.node);
168 if !ast_util::is_local(def_id) || !contains_key {
169 if !ast_util::is_local(def_id) {
170 def_id = inline::maybe_instantiate_inline(cx, def_id);
171 }
172
173 match cx.tcx.map.expect_item(def_id.node).node {
174 ast::ItemStatic(_, ast::MutImmutable, _) => {
175 trans_const(cx, ast::MutImmutable, def_id.node);
176 }
177 _ => {}
178 }
179 }
180
181 (cx.const_values.borrow().get_copy(&def_id.node),
182 !cx.non_inlineable_statics.borrow().contains(&def_id.node))
183 }
184
185 pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool) {
186 let (llconst, inlineable) = const_expr_unadjusted(cx, e, is_local);
187 let mut llconst = llconst;
188 let mut inlineable = inlineable;
189 let ety = ty::expr_ty(cx.tcx(), e);
190 let ety_adjusted = ty::expr_ty_adjusted(cx.tcx(), e);
191 let opt_adj = cx.tcx.adjustments.borrow().find_copy(&e.id);
192 match opt_adj {
193 None => { }
194 Some(adj) => {
195 match adj {
196 ty::AutoAddEnv(ty::RegionTraitStore(ty::ReStatic, _)) => {
197 let def = ty::resolve_expr(cx.tcx(), e);
198 let wrapper = closure::get_wrapper_for_bare_fn(cx,
199 ety_adjusted,
200 def,
201 llconst,
202 is_local);
203 llconst = C_struct(cx, [wrapper, C_null(Type::i8p(cx))], false)
204 }
205 ty::AutoAddEnv(store) => {
206 cx.sess()
207 .span_bug(e.span,
208 format!("unexpected static function: {:?}",
209 store))
210 }
211 ty::AutoObject(..) => {
212 cx.sess()
213 .span_unimpl(e.span,
214 "unimplemented const coercion to trait \
215 object");
216 }
217 ty::AutoDerefRef(ref adj) => {
218 let mut ty = ety;
219 let mut maybe_ptr = None;
220 for _ in range(0, adj.autoderefs) {
221 let (dv, dt) = const_deref(cx, llconst, ty, false);
222 maybe_ptr = Some(llconst);
223 llconst = dv;
224 ty = dt;
225 }
226
227 match adj.autoref {
228 None => { }
229 Some(ref autoref) => {
230 // Don't copy data to do a deref+ref.
231 let llptr = match maybe_ptr {
232 Some(ptr) => ptr,
233 None => {
234 inlineable = false;
235 const_addr_of(cx, llconst)
236 }
237 };
238 match *autoref {
239 ty::AutoUnsafe(m) |
240 ty::AutoPtr(ty::ReStatic, m) => {
241 assert!(m != ast::MutMutable);
242 llconst = llptr;
243 }
244 ty::AutoBorrowVec(ty::ReStatic, m) => {
245 assert!(m != ast::MutMutable);
246 assert_eq!(abi::slice_elt_base, 0);
247 assert_eq!(abi::slice_elt_len, 1);
248 match ty::get(ty).sty {
249 ty::ty_vec(_, Some(len)) => {
250 llconst = C_struct(cx, [
251 llptr,
252 C_uint(cx, len)
253 ], false);
254 }
255 _ => {}
256 }
257 }
258 _ => {
259 cx.sess().span_bug(e.span,
260 format!("unimplemented \
261 const autoref \
262 {:?}",
263 autoref))
264 }
265 }
266 }
267 }
268 }
269 }
270 }
271 }
272
273 let llty = type_of::sizing_type_of(cx, ety_adjusted);
274 let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
275 let tsize = machine::llsize_of_alloc(cx, llty);
276 if csize != tsize {
277 unsafe {
278 // FIXME these values could use some context
279 llvm::LLVMDumpValue(llconst);
280 llvm::LLVMDumpValue(C_undef(llty));
281 }
282 cx.sess().bug(format!("const {} of type {} has size {} instead of {}",
283 e.repr(cx.tcx()), ty_to_str(cx.tcx(), ety),
284 csize, tsize));
285 }
286 (llconst, inlineable)
287 }
288
289 // the bool returned is whether this expression can be inlined into other crates
290 // if it's assigned to a static.
291 fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
292 is_local: bool) -> (ValueRef, bool) {
293 let map_list = |exprs: &[@ast::Expr]| {
294 exprs.iter().map(|&e| const_expr(cx, e, is_local))
295 .fold((Vec::new(), true),
296 |(l, all_inlineable), (val, inlineable)| {
297 (l.append_one(val), all_inlineable && inlineable)
298 })
299 };
300 unsafe {
301 let _icx = push_ctxt("const_expr");
302 return match e.node {
303 ast::ExprLit(lit) => {
304 (consts::const_lit(cx, e, (*lit).clone()), true)
305 }
306 ast::ExprBinary(b, e1, e2) => {
307 let (te1, _) = const_expr(cx, e1, is_local);
308 let (te2, _) = const_expr(cx, e2, is_local);
309
310 let te2 = base::cast_shift_const_rhs(b, te1, te2);
311
312 /* Neither type is bottom, and we expect them to be unified
313 * already, so the following is safe. */
314 let ty = ty::expr_ty(cx.tcx(), e1);
315 let is_float = ty::type_is_fp(ty);
316 let signed = ty::type_is_signed(ty);
317 return (match b {
318 ast::BiAdd => {
319 if is_float { llvm::LLVMConstFAdd(te1, te2) }
320 else { llvm::LLVMConstAdd(te1, te2) }
321 }
322 ast::BiSub => {
323 if is_float { llvm::LLVMConstFSub(te1, te2) }
324 else { llvm::LLVMConstSub(te1, te2) }
325 }
326 ast::BiMul => {
327 if is_float { llvm::LLVMConstFMul(te1, te2) }
328 else { llvm::LLVMConstMul(te1, te2) }
329 }
330 ast::BiDiv => {
331 if is_float { llvm::LLVMConstFDiv(te1, te2) }
332 else if signed { llvm::LLVMConstSDiv(te1, te2) }
333 else { llvm::LLVMConstUDiv(te1, te2) }
334 }
335 ast::BiRem => {
336 if is_float { llvm::LLVMConstFRem(te1, te2) }
337 else if signed { llvm::LLVMConstSRem(te1, te2) }
338 else { llvm::LLVMConstURem(te1, te2) }
339 }
340 ast::BiAnd => llvm::LLVMConstAnd(te1, te2),
341 ast::BiOr => llvm::LLVMConstOr(te1, te2),
342 ast::BiBitXor => llvm::LLVMConstXor(te1, te2),
343 ast::BiBitAnd => llvm::LLVMConstAnd(te1, te2),
344 ast::BiBitOr => llvm::LLVMConstOr(te1, te2),
345 ast::BiShl => llvm::LLVMConstShl(te1, te2),
346 ast::BiShr => {
347 if signed { llvm::LLVMConstAShr(te1, te2) }
348 else { llvm::LLVMConstLShr(te1, te2) }
349 }
350 ast::BiEq => {
351 if is_float { ConstFCmp(RealOEQ, te1, te2) }
352 else { ConstICmp(IntEQ, te1, te2) }
353 },
354 ast::BiLt => {
355 if is_float { ConstFCmp(RealOLT, te1, te2) }
356 else {
357 if signed { ConstICmp(IntSLT, te1, te2) }
358 else { ConstICmp(IntULT, te1, te2) }
359 }
360 },
361 ast::BiLe => {
362 if is_float { ConstFCmp(RealOLE, te1, te2) }
363 else {
364 if signed { ConstICmp(IntSLE, te1, te2) }
365 else { ConstICmp(IntULE, te1, te2) }
366 }
367 },
368 ast::BiNe => {
369 if is_float { ConstFCmp(RealONE, te1, te2) }
370 else { ConstICmp(IntNE, te1, te2) }
371 },
372 ast::BiGe => {
373 if is_float { ConstFCmp(RealOGE, te1, te2) }
374 else {
375 if signed { ConstICmp(IntSGE, te1, te2) }
376 else { ConstICmp(IntUGE, te1, te2) }
377 }
378 },
379 ast::BiGt => {
380 if is_float { ConstFCmp(RealOGT, te1, te2) }
381 else {
382 if signed { ConstICmp(IntSGT, te1, te2) }
383 else { ConstICmp(IntUGT, te1, te2) }
384 }
385 },
386 }, true)
387 },
388 ast::ExprUnary(u, e) => {
389 let (te, _) = const_expr(cx, e, is_local);
390 let ty = ty::expr_ty(cx.tcx(), e);
391 let is_float = ty::type_is_fp(ty);
392 return (match u {
393 ast::UnBox | ast::UnUniq | ast::UnDeref => {
394 let (dv, _dt) = const_deref(cx, te, ty, true);
395 dv
396 }
397 ast::UnNot => {
398 match ty::get(ty).sty {
399 ty::ty_bool => {
400 // Somewhat questionable, but I believe this is
401 // correct.
402 let te = llvm::LLVMConstTrunc(te, Type::i1(cx).to_ref());
403 let te = llvm::LLVMConstNot(te);
404 llvm::LLVMConstZExt(te, Type::bool(cx).to_ref())
405 }
406 _ => llvm::LLVMConstNot(te),
407 }
408 }
409 ast::UnNeg => {
410 if is_float { llvm::LLVMConstFNeg(te) }
411 else { llvm::LLVMConstNeg(te) }
412 }
413 }, true)
414 }
415 ast::ExprField(base, field, _) => {
416 let bt = ty::expr_ty_adjusted(cx.tcx(), base);
417 let brepr = adt::represent_type(cx, bt);
418 let (bv, inlineable) = const_expr(cx, base, is_local);
419 expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| {
420 let ix = ty::field_idx_strict(cx.tcx(), field.name, field_tys);
421 (adt::const_get_field(cx, &*brepr, bv, discr, ix), inlineable)
422 })
423 }
424
425 ast::ExprIndex(base, index) => {
426 let bt = ty::expr_ty_adjusted(cx.tcx(), base);
427 let (bv, inlineable) = const_expr(cx, base, is_local);
428 let iv = match const_eval::eval_const_expr(cx.tcx(), index) {
429 const_eval::const_int(i) => i as u64,
430 const_eval::const_uint(u) => u,
431 _ => cx.sess().span_bug(index.span,
432 "index is not an integer-constant expression")
433 };
434 let (arr, len) = match ty::get(bt).sty {
435 ty::ty_vec(_, Some(u)) => (bv, C_uint(cx, u)),
436 ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
437 ty::ty_vec(_, None) | ty::ty_str => {
438 let e1 = const_get_elt(cx, bv, [0]);
439 (const_deref_ptr(cx, e1), const_get_elt(cx, bv, [1]))
440 },
441 _ => cx.sess().span_bug(base.span,
442 "index-expr base must be a vector or string type")
443 },
444 _ => cx.sess().span_bug(base.span,
445 "index-expr base must be a vector or string type")
446 };
447
448 let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
449 let len = match ty::get(bt).sty {
450 ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
451 ty::ty_str => {
452 assert!(len > 0);
453 len - 1
454 }
455 _ => len
456 },
457 _ => len
458 };
459 if iv >= len {
460 // FIXME #3170: report this earlier on in the const-eval
461 // pass. Reporting here is a bit late.
462 cx.sess().span_err(e.span,
463 "const index-expr is out of bounds");
464 }
465 (const_get_elt(cx, arr, [iv as c_uint]), inlineable)
466 }
467 ast::ExprCast(base, _) => {
468 let ety = ty::expr_ty(cx.tcx(), e);
469 let llty = type_of::type_of(cx, ety);
470 let basety = ty::expr_ty(cx.tcx(), base);
471 let (v, inlineable) = const_expr(cx, base, is_local);
472 return (match (expr::cast_type_kind(basety),
473 expr::cast_type_kind(ety)) {
474
475 (expr::cast_integral, expr::cast_integral) => {
476 let s = ty::type_is_signed(basety) as Bool;
477 llvm::LLVMConstIntCast(v, llty.to_ref(), s)
478 }
479 (expr::cast_integral, expr::cast_float) => {
480 if ty::type_is_signed(basety) {
481 llvm::LLVMConstSIToFP(v, llty.to_ref())
482 } else {
483 llvm::LLVMConstUIToFP(v, llty.to_ref())
484 }
485 }
486 (expr::cast_float, expr::cast_float) => {
487 llvm::LLVMConstFPCast(v, llty.to_ref())
488 }
489 (expr::cast_float, expr::cast_integral) => {
490 if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty.to_ref()) }
491 else { llvm::LLVMConstFPToUI(v, llty.to_ref()) }
492 }
493 (expr::cast_enum, expr::cast_integral) |
494 (expr::cast_enum, expr::cast_float) => {
495 let repr = adt::represent_type(cx, basety);
496 let discr = adt::const_get_discrim(cx, &*repr, v);
497 let iv = C_integral(cx.int_type, discr, false);
498 let ety_cast = expr::cast_type_kind(ety);
499 match ety_cast {
500 expr::cast_integral => {
501 let s = ty::type_is_signed(ety) as Bool;
502 llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
503 }
504 expr::cast_float => llvm::LLVMConstUIToFP(iv, llty.to_ref()),
505 _ => cx.sess().bug("enum cast destination is not \
506 integral or float")
507 }
508 }
509 (expr::cast_pointer, expr::cast_pointer) => {
510 llvm::LLVMConstPointerCast(v, llty.to_ref())
511 }
512 (expr::cast_integral, expr::cast_pointer) => {
513 llvm::LLVMConstIntToPtr(v, llty.to_ref())
514 }
515 _ => {
516 cx.sess().impossible_case(e.span,
517 "bad combination of types for cast")
518 }
519 }, inlineable)
520 }
521 ast::ExprAddrOf(ast::MutImmutable, sub) => {
522 let (e, _) = const_expr(cx, sub, is_local);
523 (const_addr_of(cx, e), false)
524 }
525 ast::ExprTup(ref es) => {
526 let ety = ty::expr_ty(cx.tcx(), e);
527 let repr = adt::represent_type(cx, ety);
528 let (vals, inlineable) = map_list(es.as_slice());
529 (adt::trans_const(cx, &*repr, 0, vals.as_slice()), inlineable)
530 }
531 ast::ExprStruct(_, ref fs, ref base_opt) => {
532 let ety = ty::expr_ty(cx.tcx(), e);
533 let repr = adt::represent_type(cx, ety);
534 let tcx = cx.tcx();
535
536 let base_val = match *base_opt {
537 Some(base) => Some(const_expr(cx, base, is_local)),
538 None => None
539 };
540
541 expr::with_field_tys(tcx, ety, Some(e.id), |discr, field_tys| {
542 let (cs, inlineable) = vec::unzip(field_tys.iter().enumerate()
543 .map(|(ix, &field_ty)| {
544 match fs.iter().find(|f| field_ty.ident.name == f.ident.node.name) {
545 Some(f) => const_expr(cx, (*f).expr, is_local),
546 None => {
547 match base_val {
548 Some((bv, inlineable)) => {
549 (adt::const_get_field(cx, &*repr, bv, discr, ix),
550 inlineable)
551 }
552 None => cx.sess().span_bug(e.span, "missing struct field")
553 }
554 }
555 }
556 }));
557 (adt::trans_const(cx, &*repr, discr, cs.as_slice()),
558 inlineable.iter().fold(true, |a, &b| a && b))
559 })
560 }
561 ast::ExprVec(ref es) => {
562 let (v, _, inlineable) = const_vec(cx,
563 e,
564 es.as_slice(),
565 is_local);
566 (v, inlineable)
567 }
568 ast::ExprVstore(sub, store @ ast::ExprVstoreSlice) |
569 ast::ExprVstore(sub, store @ ast::ExprVstoreMutSlice) => {
570 match sub.node {
571 ast::ExprLit(ref lit) => {
572 match lit.node {
573 ast::LitStr(..) => { const_expr(cx, sub, is_local) }
574 _ => { cx.sess().span_bug(e.span, "bad const-slice lit") }
575 }
576 }
577 ast::ExprVec(ref es) => {
578 let (cv, llunitty, _) = const_vec(cx,
579 e,
580 es.as_slice(),
581 is_local);
582 let llty = val_ty(cv);
583 let gv = "const".with_c_str(|name| {
584 llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
585 });
586 llvm::LLVMSetInitializer(gv, cv);
587 llvm::LLVMSetGlobalConstant(gv,
588 if store == ast::ExprVstoreMutSlice { False } else { True });
589 SetLinkage(gv, PrivateLinkage);
590 let p = const_ptrcast(cx, gv, llunitty);
591 (C_struct(cx, [p, C_uint(cx, es.len())], false), false)
592 }
593 _ => cx.sess().span_bug(e.span, "bad const-slice expr")
594 }
595 }
596 ast::ExprRepeat(elem, count) => {
597 let vec_ty = ty::expr_ty(cx.tcx(), e);
598 let unit_ty = ty::sequence_element_type(cx.tcx(), vec_ty);
599 let llunitty = type_of::type_of(cx, unit_ty);
600 let n = match const_eval::eval_const_expr(cx.tcx(), count) {
601 const_eval::const_int(i) => i as uint,
602 const_eval::const_uint(i) => i as uint,
603 _ => cx.sess().span_bug(count.span, "count must be integral const expression.")
604 };
605 let vs = Vec::from_elem(n, const_expr(cx, elem, is_local).val0());
606 let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
607 C_struct(cx, vs.as_slice(), false)
608 } else {
609 C_array(llunitty, vs.as_slice())
610 };
611 (v, true)
612 }
613 ast::ExprPath(ref pth) => {
614 // Assert that there are no type parameters in this path.
615 assert!(pth.segments.iter().all(|seg| seg.types.is_empty()));
616
617 let opt_def = cx.tcx().def_map.borrow().find_copy(&e.id);
618 match opt_def {
619 Some(ast::DefFn(def_id, _fn_style)) => {
620 if !ast_util::is_local(def_id) {
621 let ty = csearch::get_type(cx.tcx(), def_id).ty;
622 (base::trans_external_path(cx, def_id, ty), true)
623 } else {
624 assert!(ast_util::is_local(def_id));
625 (base::get_item_val(cx, def_id.node), true)
626 }
627 }
628 Some(ast::DefStatic(def_id, false)) => {
629 get_const_val(cx, def_id)
630 }
631 Some(ast::DefVariant(enum_did, variant_did, _)) => {
632 let ety = ty::expr_ty(cx.tcx(), e);
633 let repr = adt::represent_type(cx, ety);
634 let vinfo = ty::enum_variant_with_id(cx.tcx(),
635 enum_did,
636 variant_did);
637 (adt::trans_const(cx, &*repr, vinfo.disr_val, []), true)
638 }
639 Some(ast::DefStruct(_)) => {
640 let ety = ty::expr_ty(cx.tcx(), e);
641 let llty = type_of::type_of(cx, ety);
642 (C_null(llty), true)
643 }
644 _ => {
645 cx.sess().span_bug(e.span, "expected a const, fn, struct, or variant def")
646 }
647 }
648 }
649 ast::ExprCall(callee, ref args) => {
650 let opt_def = cx.tcx().def_map.borrow().find_copy(&callee.id);
651 match opt_def {
652 Some(ast::DefStruct(_)) => {
653 let ety = ty::expr_ty(cx.tcx(), e);
654 let repr = adt::represent_type(cx, ety);
655 let (arg_vals, inlineable) = map_list(args.as_slice());
656 (adt::trans_const(cx, &*repr, 0, arg_vals.as_slice()),
657 inlineable)
658 }
659 Some(ast::DefVariant(enum_did, variant_did, _)) => {
660 let ety = ty::expr_ty(cx.tcx(), e);
661 let repr = adt::represent_type(cx, ety);
662 let vinfo = ty::enum_variant_with_id(cx.tcx(),
663 enum_did,
664 variant_did);
665 let (arg_vals, inlineable) = map_list(args.as_slice());
666 (adt::trans_const(cx,
667 &*repr,
668 vinfo.disr_val,
669 arg_vals.as_slice()), inlineable)
670 }
671 _ => cx.sess().span_bug(e.span, "expected a struct or variant def")
672 }
673 }
674 ast::ExprParen(e) => { const_expr(cx, e, is_local) }
675 _ => cx.sess().span_bug(e.span,
676 "bad constant expression type in consts::const_expr")
677 };
678 }
679 }
680
681 pub fn trans_const(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) {
682 unsafe {
683 let _icx = push_ctxt("trans_const");
684 let g = base::get_item_val(ccx, id);
685 // At this point, get_item_val has already translated the
686 // constant's initializer to determine its LLVM type.
687 let v = ccx.const_values.borrow().get_copy(&id);
688 llvm::LLVMSetInitializer(g, v);
689 if m != ast::MutMutable {
690 llvm::LLVMSetGlobalConstant(g, True);
691 }
692 debuginfo::create_global_var_metadata(ccx, id, g);
693 }
694 }
librustc/middle/trans/consts.rs:184:1-184:1 -fn- definition:
pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool) {
let (llconst, inlineable) = const_expr_unadjusted(cx, e, is_local);
let mut llconst = llconst;
references:- 17544: match fs.iter().find(|f| field_ty.ident.name == f.ident.node.name) {
545: Some(f) => const_expr(cx, (*f).expr, is_local),
546: None => {
--
604: };
605: let vs = Vec::from_elem(n, const_expr(cx, elem, is_local).val0());
606: let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
--
673: }
674: ast::ExprParen(e) => { const_expr(cx, e, is_local) }
675: _ => cx.sess().span_bug(e.span,
librustc/middle/trans/base.rs:
1880: // LLVM type is not fully determined by the Rust type.
1881: let (v, inlineable) = consts::const_expr(ccx, expr, is_local);
1882: ccx.const_values.borrow_mut().insert(id, v);
librustc/middle/trans/_match.rs:
321: range(l1, l2) => {
322: let (l1, _) = consts::const_expr(ccx, l1, true);
323: let (l2, _) = consts::const_expr(ccx, l2, true);
324: return range_result(Result::new(bcx, l1), Result::new(bcx, l2));
librustc/middle/trans/consts.rs:
388: ast::ExprUnary(u, e) => {
389: let (te, _) = const_expr(cx, e, is_local);
390: let ty = ty::expr_ty(cx.tcx(), e);
librustc/middle/trans/consts.rs:91:1-91:1 -fn- definition:
fn const_vec(cx: &CrateContext, e: &ast::Expr,
es: &[@ast::Expr], is_local: bool) -> (ValueRef, Type, bool) {
let vec_ty = ty::expr_ty(cx.tcx(), e);
references:- 2577: ast::ExprVec(ref es) => {
578: let (cv, llunitty, _) = const_vec(cx,
579: e,
librustc/middle/trans/consts.rs:118:1-118:1 -fn- definition:
fn const_deref_ptr(cx: &CrateContext, v: ValueRef) -> ValueRef {
let v = match cx.const_globals.borrow().find(&(v as int)) {
Some(&v) => v,
references:- 2144: ty::ty_vec(_, None) | ty::ty_str => cx.sess().bug("unexpected slice"),
145: _ => const_deref_ptr(cx, v),
146: }
--
438: let e1 = const_get_elt(cx, bv, [0]);
439: (const_deref_ptr(cx, e1), const_get_elt(cx, bv, [1]))
440: },
librustc/middle/trans/consts.rs:680:1-680:1 -fn- definition:
pub fn trans_const(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) {
unsafe {
let _icx = push_ctxt("trans_const");
references:- 2174: ast::ItemStatic(_, ast::MutImmutable, _) => {
175: trans_const(cx, ast::MutImmutable, def_id.node);
176: }
librustc/middle/trans/base.rs:
1629: ast::ItemStatic(_, m, expr) => {
1630: consts::trans_const(ccx, m, item.id);
1631: // Do static_assert checking. It can't really be done much earlier
librustc/middle/trans/consts.rs:106:1-106:1 -fn- definition:
fn const_addr_of(cx: &CrateContext, cv: ValueRef) -> ValueRef {
unsafe {
let gv = "const".with_c_str(|name| {
references:- 2522: let (e, _) = const_expr(cx, sub, is_local);
523: (const_addr_of(cx, e), false)
524: }
librustc/middle/trans/consts.rs:135:1-135:1 -fn- definition:
fn const_deref(cx: &CrateContext, v: ValueRef, t: ty::t, explicit: bool)
-> (ValueRef, ty::t) {
match ty::deref(t, explicit) {
references:- 2220: for _ in range(0, adj.autoderefs) {
221: let (dv, dt) = const_deref(cx, llconst, ty, false);
222: maybe_ptr = Some(llconst);
--
393: ast::UnBox | ast::UnUniq | ast::UnDeref => {
394: let (dv, _dt) = const_deref(cx, te, ty, true);
395: dv
librustc/middle/trans/consts.rs:40:1-40:1 -fn- definition:
pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: ast::Lit)
-> ValueRef {
let _icx = push_ctxt("trans_lit");
references:- 2303: ast::ExprLit(lit) => {
304: (consts::const_lit(cx, e, (*lit).clone()), true)
305: }
librustc/middle/trans/expr.rs:
1098: let ty = expr_ty(bcx, expr);
1099: let v = consts::const_lit(bcx.ccx(), expr, lit);
1100: immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock()
librustc/middle/trans/consts.rs:164:1-164:1 -fn- definition:
pub fn get_const_val(cx: &CrateContext,
mut def_id: ast::DefId) -> (ValueRef, bool) {
let contains_key = cx.const_values.borrow().contains_key(&def_id.node);
references:- 2librustc/middle/trans/_match.rs:
314: lit(ConstLit(lit_id)) => {
315: let (llval, _) = consts::get_const_val(bcx.ccx(), lit_id);
316: return single_result(Result::new(bcx, llval));
librustc/middle/trans/consts.rs:
628: Some(ast::DefStatic(def_id, false)) => {
629: get_const_val(cx, def_id)
630: }