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