]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/consts.rs
std: move StrUtil::as_c_str into StrSlice
[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::common::*;
23 use middle::trans::consts;
24 use middle::trans::expr;
25 use middle::trans::inline;
26 use middle::trans::machine;
27 use middle::trans::type_of;
28 use middle::ty;
29 use util::ppaux::{Repr, ty_to_str};
30
31 use middle::trans::type_::Type;
32
33 use std::libc::c_uint;
34 use syntax::{ast, ast_util, ast_map};
35
36 pub fn const_lit(cx: &mut CrateContext, e: &ast::expr, lit: ast::lit)
37     -> ValueRef {
38     let _icx = push_ctxt("trans_lit");
39     match lit.node {
40       ast::lit_int(i, t) => C_integral(Type::int_from_ty(cx, t), i as u64, true),
41       ast::lit_uint(u, t) => C_integral(Type::uint_from_ty(cx, t), u, false),
42       ast::lit_int_unsuffixed(i) => {
43         let lit_int_ty = ty::node_id_to_type(cx.tcx, e.id);
44         match ty::get(lit_int_ty).sty {
45           ty::ty_int(t) => {
46             C_integral(Type::int_from_ty(cx, t), i as u64, true)
47           }
48           ty::ty_uint(t) => {
49             C_integral(Type::uint_from_ty(cx, t), i as u64, false)
50           }
51           _ => cx.sess.span_bug(lit.span,
52                    fmt!("integer literal has type %s (expected int or uint)",
53                         ty_to_str(cx.tcx, lit_int_ty)))
54         }
55       }
56       ast::lit_float(fs, t) => C_floating(fs, Type::float_from_ty(cx, t)),
57       ast::lit_float_unsuffixed(fs) => {
58         let lit_float_ty = ty::node_id_to_type(cx.tcx, e.id);
59         match ty::get(lit_float_ty).sty {
60           ty::ty_float(t) => {
61             C_floating(fs, Type::float_from_ty(cx, t))
62           }
63           _ => {
64             cx.sess.span_bug(lit.span,
65                              "floating point literal doesn't have the right type");
66           }
67         }
68       }
69       ast::lit_bool(b) => C_bool(b),
70       ast::lit_nil => C_nil(),
71       ast::lit_str(s) => C_estr_slice(cx, s)
72     }
73 }
74
75 pub fn const_ptrcast(cx: &mut CrateContext, a: ValueRef, t: Type) -> ValueRef {
76     unsafe {
77         let b = llvm::LLVMConstPointerCast(a, t.ptr_to().to_ref());
78         assert!(cx.const_globals.insert(b as int, a));
79         b
80     }
81 }
82
83 pub fn const_vec(cx: @mut CrateContext, e: &ast::expr, es: &[@ast::expr])
84     -> (ValueRef, ValueRef, Type) {
85     unsafe {
86         let vec_ty = ty::expr_ty(cx.tcx, e);
87         let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty);
88         let llunitty = type_of::type_of(cx, unit_ty);
89         let unit_sz = machine::llsize_of(cx, llunitty);
90         let sz = llvm::LLVMConstMul(C_uint(cx, es.len()), unit_sz);
91         let vs = es.map(|e| const_expr(cx, *e));
92         // If the vector contains enums, an LLVM array won't work.
93         let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
94             C_struct(vs)
95         } else {
96             C_array(llunitty, vs)
97         };
98         return (v, sz, llunitty);
99     }
100 }
101
102 fn const_addr_of(cx: &mut CrateContext, cv: ValueRef) -> ValueRef {
103     unsafe {
104         let gv = do "const".as_c_str |name| {
105             llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name)
106         };
107         llvm::LLVMSetInitializer(gv, cv);
108         llvm::LLVMSetGlobalConstant(gv, True);
109         SetLinkage(gv, PrivateLinkage);
110         gv
111     }
112 }
113
114 fn const_deref_ptr(cx: &mut CrateContext, v: ValueRef) -> ValueRef {
115     let v = match cx.const_globals.find(&(v as int)) {
116         Some(&v) => v,
117         None => v
118     };
119     unsafe {
120         assert_eq!(llvm::LLVMIsGlobalConstant(v), True);
121         llvm::LLVMGetInitializer(v)
122     }
123 }
124
125 fn const_deref_newtype(cx: &mut CrateContext, v: ValueRef, t: ty::t)
126     -> ValueRef {
127     let repr = adt::represent_type(cx, t);
128     adt::const_get_field(cx, repr, v, 0, 0)
129 }
130
131 fn const_deref(cx: &mut CrateContext, v: ValueRef, t: ty::t, explicit: bool)
132     -> (ValueRef, ty::t) {
133     match ty::deref(cx.tcx, t, explicit) {
134         Some(ref mt) => {
135             assert!(mt.mutbl != ast::m_mutbl);
136             let dv = match ty::get(t).sty {
137                 ty::ty_ptr(*) | ty::ty_rptr(*) => {
138                      const_deref_ptr(cx, v)
139                 }
140                 ty::ty_enum(*) | ty::ty_struct(*) => {
141                     const_deref_newtype(cx, v, t)
142                 }
143                 _ => {
144                     cx.sess.bug(fmt!("Unexpected dereferenceable type %s",
145                                      ty_to_str(cx.tcx, t)))
146                 }
147             };
148             (dv, mt.ty)
149         }
150         None => {
151             cx.sess.bug(fmt!("Can't dereference const of type %s",
152                              ty_to_str(cx.tcx, t)))
153         }
154     }
155 }
156
157 pub fn get_const_val(cx: @mut CrateContext, mut def_id: ast::def_id) -> ValueRef {
158     let contains_key = cx.const_values.contains_key(&def_id.node);
159     if !ast_util::is_local(def_id) || !contains_key {
160         if !ast_util::is_local(def_id) {
161             def_id = inline::maybe_instantiate_inline(cx, def_id);
162         }
163         match cx.tcx.items.get_copy(&def_id.node) {
164             ast_map::node_item(@ast::item {
165                 node: ast::item_static(_, ast::m_imm, _), _
166             }, _) => {
167                 trans_const(cx, ast::m_imm, def_id.node);
168             }
169             _ => cx.tcx.sess.bug("expected a const to be an item")
170         }
171     }
172     cx.const_values.get_copy(&def_id.node)
173 }
174
175 pub fn const_expr(cx: @mut CrateContext, e: @ast::expr) -> ValueRef {
176     let mut llconst = const_expr_unadjusted(cx, e);
177     let ety = ty::expr_ty(cx.tcx, e);
178     let adjustment = cx.tcx.adjustments.find_copy(&e.id);
179     match adjustment {
180         None => { }
181         Some(@ty::AutoAddEnv(ty::re_static, ast::BorrowedSigil)) => {
182             llconst = C_struct([llconst, C_null(Type::opaque_box(cx).ptr_to())])
183         }
184         Some(@ty::AutoAddEnv(ref r, ref s)) => {
185             cx.sess.span_bug(e.span, fmt!("unexpected static function: \
186                                            region %? sigil %?", *r, *s))
187         }
188         Some(@ty::AutoDerefRef(ref adj)) => {
189             let mut ty = ety;
190             let mut maybe_ptr = None;
191             for adj.autoderefs.times {
192                 let (dv, dt) = const_deref(cx, llconst, ty, false);
193                 maybe_ptr = Some(llconst);
194                 llconst = dv;
195                 ty = dt;
196             }
197
198             match adj.autoref {
199                 None => { }
200                 Some(ref autoref) => {
201                     // Don't copy data to do a deref+ref.
202                     let llptr = match maybe_ptr {
203                         Some(ptr) => ptr,
204                         None => const_addr_of(cx, llconst)
205                     };
206                     match *autoref {
207                         ty::AutoUnsafe(m) |
208                         ty::AutoPtr(ty::re_static, m) => {
209                             assert!(m != ast::m_mutbl);
210                             llconst = llptr;
211                         }
212                         ty::AutoBorrowVec(ty::re_static, m) => {
213                             assert!(m != ast::m_mutbl);
214                             let size = machine::llsize_of(cx,
215                                                           val_ty(llconst));
216                             assert_eq!(abi::slice_elt_base, 0);
217                             assert_eq!(abi::slice_elt_len, 1);
218                             llconst = C_struct([llptr, size]);
219                         }
220                         _ => {
221                             cx.sess.span_bug(e.span,
222                                              fmt!("unimplemented const \
223                                                    autoref %?", autoref))
224                         }
225                     }
226                 }
227             }
228         }
229     }
230
231     let ety_adjusted = ty::expr_ty_adjusted(cx.tcx, e);
232     let llty = type_of::sizing_type_of(cx, ety_adjusted);
233     let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
234     let tsize = machine::llsize_of_alloc(cx, llty);
235     if csize != tsize {
236         unsafe {
237             // XXX these values could use some context
238             llvm::LLVMDumpValue(llconst);
239             llvm::LLVMDumpValue(C_undef(llty));
240         }
241         cx.sess.bug(fmt!("const %s of type %s has size %u instead of %u",
242                          e.repr(cx.tcx), ty_to_str(cx.tcx, ety),
243                          csize, tsize));
244     }
245     llconst
246 }
247
248 fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::expr) -> ValueRef {
249     unsafe {
250         let _icx = push_ctxt("const_expr");
251         return match e.node {
252           ast::expr_lit(lit) => consts::const_lit(cx, e, *lit),
253           ast::expr_binary(_, b, e1, e2) => {
254             let te1 = const_expr(cx, e1);
255             let te2 = const_expr(cx, e2);
256
257             let te2 = base::cast_shift_const_rhs(b, te1, te2);
258
259             /* Neither type is bottom, and we expect them to be unified
260              * already, so the following is safe. */
261             let ty = ty::expr_ty(cx.tcx, e1);
262             let is_float = ty::type_is_fp(ty);
263             let signed = ty::type_is_signed(ty);
264             return match b {
265               ast::add   => {
266                 if is_float { llvm::LLVMConstFAdd(te1, te2) }
267                 else        { llvm::LLVMConstAdd(te1, te2) }
268               }
269               ast::subtract => {
270                 if is_float { llvm::LLVMConstFSub(te1, te2) }
271                 else        { llvm::LLVMConstSub(te1, te2) }
272               }
273               ast::mul    => {
274                 if is_float { llvm::LLVMConstFMul(te1, te2) }
275                 else        { llvm::LLVMConstMul(te1, te2) }
276               }
277               ast::div    => {
278                 if is_float    { llvm::LLVMConstFDiv(te1, te2) }
279                 else if signed { llvm::LLVMConstSDiv(te1, te2) }
280                 else           { llvm::LLVMConstUDiv(te1, te2) }
281               }
282               ast::rem    => {
283                 if is_float    { llvm::LLVMConstFRem(te1, te2) }
284                 else if signed { llvm::LLVMConstSRem(te1, te2) }
285                 else           { llvm::LLVMConstURem(te1, te2) }
286               }
287               ast::and    => llvm::LLVMConstAnd(te1, te2),
288               ast::or     => llvm::LLVMConstOr(te1, te2),
289               ast::bitxor => llvm::LLVMConstXor(te1, te2),
290               ast::bitand => llvm::LLVMConstAnd(te1, te2),
291               ast::bitor  => llvm::LLVMConstOr(te1, te2),
292               ast::shl    => llvm::LLVMConstShl(te1, te2),
293               ast::shr    => {
294                 if signed { llvm::LLVMConstAShr(te1, te2) }
295                 else      { llvm::LLVMConstLShr(te1, te2) }
296               }
297               ast::eq     => {
298                   if is_float { ConstFCmp(RealOEQ, te1, te2) }
299                   else        { ConstICmp(IntEQ, te1, te2)   }
300               },
301               ast::lt     => {
302                   if is_float { ConstFCmp(RealOLT, te1, te2) }
303                   else        {
304                       if signed { ConstICmp(IntSLT, te1, te2) }
305                       else      { ConstICmp(IntULT, te1, te2) }
306                   }
307               },
308               ast::le     => {
309                   if is_float { ConstFCmp(RealOLE, te1, te2) }
310                   else        {
311                       if signed { ConstICmp(IntSLE, te1, te2) }
312                       else      { ConstICmp(IntULE, te1, te2) }
313                   }
314               },
315               ast::ne     => {
316                   if is_float { ConstFCmp(RealONE, te1, te2) }
317                   else        { ConstICmp(IntNE, te1, te2) }
318               },
319               ast::ge     => {
320                   if is_float { ConstFCmp(RealOGE, te1, te2) }
321                   else        {
322                       if signed { ConstICmp(IntSGE, te1, te2) }
323                       else      { ConstICmp(IntUGE, te1, te2) }
324                   }
325               },
326               ast::gt     => {
327                   if is_float { ConstFCmp(RealOGT, te1, te2) }
328                   else        {
329                       if signed { ConstICmp(IntSGT, te1, te2) }
330                       else      { ConstICmp(IntUGT, te1, te2) }
331                   }
332               },
333             };
334           },
335           ast::expr_unary(_, u, e) => {
336             let te = const_expr(cx, e);
337             let ty = ty::expr_ty(cx.tcx, e);
338             let is_float = ty::type_is_fp(ty);
339             return match u {
340               ast::box(_)  |
341               ast::uniq |
342               ast::deref  => {
343                 let (dv, _dt) = const_deref(cx, te, ty, true);
344                 dv
345               }
346               ast::not    => {
347                 match ty::get(ty).sty {
348                     ty::ty_bool => {
349                         // Somewhat questionable, but I believe this is
350                         // correct.
351                         let te = llvm::LLVMConstTrunc(te, Type::i1().to_ref());
352                         let te = llvm::LLVMConstNot(te);
353                         llvm::LLVMConstZExt(te, Type::bool().to_ref())
354                     }
355                     _ => llvm::LLVMConstNot(te),
356                 }
357               }
358               ast::neg    => {
359                 if is_float { llvm::LLVMConstFNeg(te) }
360                 else        { llvm::LLVMConstNeg(te) }
361               }
362             }
363           }
364           ast::expr_field(base, field, _) => {
365               let bt = ty::expr_ty_adjusted(cx.tcx, base);
366               let brepr = adt::represent_type(cx, bt);
367               let bv = const_expr(cx, base);
368               do expr::with_field_tys(cx.tcx, bt, None) |discr, field_tys| {
369                   let ix = ty::field_idx_strict(cx.tcx, field, field_tys);
370                   adt::const_get_field(cx, brepr, bv, discr, ix)
371               }
372           }
373
374           ast::expr_index(_, base, index) => {
375               let bt = ty::expr_ty_adjusted(cx.tcx, base);
376               let bv = const_expr(cx, base);
377               let iv = match const_eval::eval_const_expr(cx.tcx, index) {
378                   const_eval::const_int(i) => i as u64,
379                   const_eval::const_uint(u) => u,
380                   _ => cx.sess.span_bug(index.span,
381                                         "index is not an integer-constant expression")
382               };
383               let (arr, len) = match ty::get(bt).sty {
384                   ty::ty_evec(_, vstore) | ty::ty_estr(vstore) =>
385                       match vstore {
386                       ty::vstore_fixed(u) =>
387                           (bv, C_uint(cx, u)),
388
389                       ty::vstore_slice(_) => {
390                           let unit_ty = ty::sequence_element_type(cx.tcx, bt);
391                           let llunitty = type_of::type_of(cx, unit_ty);
392                           let unit_sz = machine::llsize_of(cx, llunitty);
393
394                           let e1 = const_get_elt(cx, bv, [0]);
395                           (const_deref_ptr(cx, e1),
396                            llvm::LLVMConstUDiv(const_get_elt(cx, bv, [1]),
397                                                unit_sz))
398                       },
399                       _ => cx.sess.span_bug(base.span,
400                                             "index-expr base must be fixed-size or slice")
401                   },
402                   _ =>  cx.sess.span_bug(base.span,
403                                          "index-expr base must be a vector or string type")
404               };
405
406               let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
407               let len = match ty::get(bt).sty {
408                   ty::ty_estr(*) => {assert!(len > 0); len - 1},
409                   _ => len
410               };
411               if iv >= len {
412                   // FIXME #3170: report this earlier on in the const-eval
413                   // pass. Reporting here is a bit late.
414                   cx.sess.span_err(e.span,
415                                    "const index-expr is out of bounds");
416               }
417               const_get_elt(cx, arr, [iv as c_uint])
418           }
419           ast::expr_cast(base, _) => {
420             let ety = ty::expr_ty(cx.tcx, e);
421             let llty = type_of::type_of(cx, ety);
422             let basety = ty::expr_ty(cx.tcx, base);
423             let v = const_expr(cx, base);
424             match (expr::cast_type_kind(basety),
425                    expr::cast_type_kind(ety)) {
426
427               (expr::cast_integral, expr::cast_integral) => {
428                 let s = ty::type_is_signed(basety) as Bool;
429                 llvm::LLVMConstIntCast(v, llty.to_ref(), s)
430               }
431               (expr::cast_integral, expr::cast_float) => {
432                 if ty::type_is_signed(basety) {
433                     llvm::LLVMConstSIToFP(v, llty.to_ref())
434                 } else {
435                     llvm::LLVMConstUIToFP(v, llty.to_ref())
436                 }
437               }
438               (expr::cast_float, expr::cast_float) => {
439                 llvm::LLVMConstFPCast(v, llty.to_ref())
440               }
441               (expr::cast_float, expr::cast_integral) => {
442                 if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty.to_ref()) }
443                 else { llvm::LLVMConstFPToUI(v, llty.to_ref()) }
444               }
445               (expr::cast_enum, expr::cast_integral) |
446               (expr::cast_enum, expr::cast_float)  => {
447                 let repr = adt::represent_type(cx, basety);
448                 let discr = adt::const_get_discrim(cx, repr, v);
449                 let iv = C_int(cx, discr);
450                 let ety_cast = expr::cast_type_kind(ety);
451                 match ety_cast {
452                     expr::cast_integral => {
453                         let s = ty::type_is_signed(ety) as Bool;
454                         llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
455                     }
456                     expr::cast_float => llvm::LLVMConstUIToFP(iv, llty.to_ref()),
457                     _ => cx.sess.bug("enum cast destination is not \
458                                       integral or float")
459                 }
460               }
461               (expr::cast_pointer, expr::cast_pointer) => {
462                 llvm::LLVMConstPointerCast(v, llty.to_ref())
463               }
464               (expr::cast_integral, expr::cast_pointer) => {
465                 llvm::LLVMConstIntToPtr(v, llty.to_ref())
466               }
467               _ => {
468                 cx.sess.impossible_case(e.span,
469                                         "bad combination of types for cast")
470               }
471             }
472           }
473           ast::expr_addr_of(ast::m_imm, sub) => {
474               let e = const_expr(cx, sub);
475               const_addr_of(cx, e)
476           }
477           ast::expr_tup(ref es) => {
478               let ety = ty::expr_ty(cx.tcx, e);
479               let repr = adt::represent_type(cx, ety);
480               let vals = es.map(|&e| const_expr(cx, e));
481               adt::trans_const(cx, repr, 0, vals)
482           }
483           ast::expr_struct(_, ref fs, None) => {
484               let ety = ty::expr_ty(cx.tcx, e);
485               let repr = adt::represent_type(cx, ety);
486               let tcx = cx.tcx;
487               do expr::with_field_tys(tcx, ety, Some(e.id))
488                   |discr, field_tys| {
489                   let cs = field_tys.map(|field_ty| {
490                       match fs.iter().find_(|f| field_ty.ident == f.ident) {
491                           Some(f) => const_expr(cx, (*f).expr),
492                           None => {
493                               cx.tcx.sess.span_bug(e.span, "missing struct field");
494                           }
495                       }
496                   });
497                   adt::trans_const(cx, repr, discr, cs)
498               }
499           }
500           ast::expr_vec(ref es, ast::m_imm) => {
501             let (v, _, _) = const_vec(cx, e, *es);
502             v
503           }
504           ast::expr_vstore(sub, ast::expr_vstore_slice) => {
505             match sub.node {
506               ast::expr_lit(ref lit) => {
507                 match lit.node {
508                   ast::lit_str(*) => { const_expr(cx, sub) }
509                   _ => { cx.sess.span_bug(e.span, "bad const-slice lit") }
510                 }
511               }
512               ast::expr_vec(ref es, ast::m_imm) => {
513                 let (cv, sz, llunitty) = const_vec(cx, e, *es);
514                 let llty = val_ty(cv);
515                 let gv = do "const".as_c_str |name| {
516                     llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
517                 };
518                 llvm::LLVMSetInitializer(gv, cv);
519                 llvm::LLVMSetGlobalConstant(gv, True);
520                 SetLinkage(gv, PrivateLinkage);
521                 let p = const_ptrcast(cx, gv, llunitty);
522                 C_struct([p, sz])
523               }
524               _ => cx.sess.span_bug(e.span, "bad const-slice expr")
525             }
526           }
527           ast::expr_path(ref pth) => {
528             assert_eq!(pth.types.len(), 0);
529             let tcx = cx.tcx;
530             match tcx.def_map.find(&e.id) {
531                 Some(&ast::def_fn(def_id, _purity)) => {
532                     if !ast_util::is_local(def_id) {
533                         let ty = csearch::get_type(cx.tcx, def_id).ty;
534                         base::trans_external_path(cx, def_id, ty)
535                     } else {
536                         assert!(ast_util::is_local(def_id));
537                         base::get_item_val(cx, def_id.node)
538                     }
539                 }
540                 Some(&ast::def_static(def_id, false)) => {
541                     get_const_val(cx, def_id)
542                 }
543                 Some(&ast::def_variant(enum_did, variant_did)) => {
544                     let ety = ty::expr_ty(cx.tcx, e);
545                     let repr = adt::represent_type(cx, ety);
546                     let vinfo = ty::enum_variant_with_id(cx.tcx,
547                                                          enum_did,
548                                                          variant_did);
549                     adt::trans_const(cx, repr, vinfo.disr_val, [])
550                 }
551                 Some(&ast::def_struct(_)) => {
552                     let ety = ty::expr_ty(cx.tcx, e);
553                     let llty = type_of::type_of(cx, ety);
554                     C_null(llty)
555                 }
556                 _ => {
557                     cx.sess.span_bug(e.span, "expected a const, fn, struct, or variant def")
558                 }
559             }
560           }
561           ast::expr_call(callee, ref args, _) => {
562               let tcx = cx.tcx;
563               match tcx.def_map.find(&callee.id) {
564                   Some(&ast::def_struct(_)) => {
565                       let ety = ty::expr_ty(cx.tcx, e);
566                       let repr = adt::represent_type(cx, ety);
567                       let arg_vals = args.map(|a| const_expr(cx, *a));
568                       adt::trans_const(cx, repr, 0, arg_vals)
569                   }
570                   Some(&ast::def_variant(enum_did, variant_did)) => {
571                       let ety = ty::expr_ty(cx.tcx, e);
572                       let repr = adt::represent_type(cx, ety);
573                       let vinfo = ty::enum_variant_with_id(cx.tcx,
574                                                            enum_did,
575                                                            variant_did);
576                       let arg_vals = args.map(|a| const_expr(cx, *a));
577                       adt::trans_const(cx, repr, vinfo.disr_val, arg_vals)
578                   }
579                   _ => cx.sess.span_bug(e.span, "expected a struct or variant def")
580               }
581           }
582           ast::expr_paren(e) => { return const_expr(cx, e); }
583           _ => cx.sess.span_bug(e.span,
584                   "bad constant expression type in consts::const_expr")
585         };
586     }
587 }
588
589 pub fn trans_const(ccx: @mut CrateContext, m: ast::mutability, id: ast::node_id) {
590     unsafe {
591         let _icx = push_ctxt("trans_const");
592         let g = base::get_item_val(ccx, id);
593         // At this point, get_item_val has already translated the
594         // constant's initializer to determine its LLVM type.
595         let v = ccx.const_values.get_copy(&id);
596         llvm::LLVMSetInitializer(g, v);
597         if m != ast::m_mutbl {
598             llvm::LLVMSetGlobalConstant(g, True);
599         }
600     }
601 }