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