]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/consts.rs
rollup merge of #17370 : klutzy/win64-backtrace
[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::vec;
37 use libc::c_uint;
38 use syntax::{ast, ast_util};
39 use syntax::ptr::P;
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: &[P<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!("cannot 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::AdjustAddEnv(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::AdjustAddEnv(store) => {
220                     cx.sess()
221                       .span_bug(e.span,
222                                 format!("unexpected static function: {:?}",
223                                         store).as_slice())
224                 }
225                 ty::AdjustDerefRef(ref adj) => {
226                     let mut ty = ety;
227                     // Save the last autoderef in case we can avoid it.
228                     if adj.autoderefs > 0 {
229                         for _ in range(0, adj.autoderefs-1) {
230                             let (dv, dt) = const_deref(cx, llconst, ty, false);
231                             llconst = dv;
232                             ty = dt;
233                         }
234                     }
235
236                     match adj.autoref {
237                         None => {
238                             let (dv, dt) = const_deref(cx, llconst, ty, false);
239                             llconst = dv;
240
241                             // If we derefed a fat pointer then we will have an
242                             // open type here. So we need to update the type with
243                             // the one returned from const_deref.
244                             ety_adjusted = dt;
245                         }
246                         Some(ref autoref) => {
247                             match *autoref {
248                                 ty::AutoUnsafe(_, None) |
249                                 ty::AutoPtr(ty::ReStatic, _, None) => {
250                                     // Don't copy data to do a deref+ref
251                                     // (i.e., skip the last auto-deref).
252                                     if adj.autoderefs == 0 {
253                                         inlineable = false;
254                                         llconst = const_addr_of(cx, llconst, ast::MutImmutable);
255                                     }
256                                 }
257                                 ty::AutoPtr(ty::ReStatic, _, Some(box ty::AutoUnsize(..))) => {
258                                     if adj.autoderefs > 0 {
259                                         // Seeing as we are deref'ing here and take a reference
260                                         // again to make the pointer part of the far pointer below,
261                                         // we just skip the whole thing. We still need the type
262                                         // though. This works even if we don't need to deref
263                                         // because of byref semantics. Note that this is not just
264                                         // an optimisation, it is necessary for mutable vectors to
265                                         // work properly.
266                                         let (_, dt) = const_deref(cx, llconst, ty, false);
267                                         ty = dt;
268                                     } else {
269                                         llconst = const_addr_of(cx, llconst, ast::MutImmutable)
270                                     }
271
272                                     match ty::get(ty).sty {
273                                         ty::ty_vec(unit_ty, Some(len)) => {
274                                             inlineable = false;
275                                             let llunitty = type_of::type_of(cx, unit_ty);
276                                             let llptr = const_ptrcast(cx, llconst, llunitty);
277                                             assert_eq!(abi::slice_elt_base, 0);
278                                             assert_eq!(abi::slice_elt_len, 1);
279                                             llconst = C_struct(cx, [
280                                                 llptr,
281                                                 C_uint(cx, len)
282                                             ], false);
283                                         }
284                                         _ => cx.sess().span_bug(e.span,
285                                             format!("unimplemented type in const unsize: {}",
286                                                     ty_to_string(cx.tcx(), ty)).as_slice())
287                                     }
288                                 }
289                                 _ => {
290                                     cx.sess()
291                                       .span_bug(e.span,
292                                                 format!("unimplemented const \
293                                                          autoref {:?}",
294                                                         autoref).as_slice())
295                                 }
296                             }
297                         }
298                     }
299                 }
300             }
301         }
302     }
303
304     let llty = type_of::sizing_type_of(cx, ety_adjusted);
305     let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
306     let tsize = machine::llsize_of_alloc(cx, llty);
307     if csize != tsize {
308         unsafe {
309             // FIXME these values could use some context
310             llvm::LLVMDumpValue(llconst);
311             llvm::LLVMDumpValue(C_undef(llty));
312         }
313         cx.sess().bug(format!("const {} of type {} has size {} instead of {}",
314                          e.repr(cx.tcx()), ty_to_string(cx.tcx(), ety),
315                          csize, tsize).as_slice());
316     }
317     (llconst, inlineable, ety_adjusted)
318 }
319
320 // the bool returned is whether this expression can be inlined into other crates
321 // if it's assigned to a static.
322 fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
323                          is_local: bool) -> (ValueRef, bool) {
324     let map_list = |exprs: &[P<ast::Expr>]| {
325         exprs.iter().map(|e| first_two(const_expr(cx, &**e, is_local)))
326              .fold((Vec::new(), true),
327                    |(l, all_inlineable), (val, inlineable)| {
328                 (l.append_one(val), all_inlineable && inlineable)
329              })
330     };
331     unsafe {
332         let _icx = push_ctxt("const_expr");
333         return match e.node {
334           ast::ExprLit(ref lit) => {
335               (consts::const_lit(cx, e, &**lit), true)
336           }
337           ast::ExprBinary(b, ref e1, ref e2) => {
338             let (te1, _, _) = const_expr(cx, &**e1, is_local);
339             let (te2, _, _) = const_expr(cx, &**e2, is_local);
340
341             let te2 = base::cast_shift_const_rhs(b, te1, te2);
342
343             /* Neither type is bottom, and we expect them to be unified
344              * already, so the following is safe. */
345             let ty = ty::expr_ty(cx.tcx(), &**e1);
346             let is_float = ty::type_is_fp(ty);
347             let signed = ty::type_is_signed(ty);
348             return (match b {
349               ast::BiAdd   => {
350                 if is_float { llvm::LLVMConstFAdd(te1, te2) }
351                 else        { llvm::LLVMConstAdd(te1, te2) }
352               }
353               ast::BiSub => {
354                 if is_float { llvm::LLVMConstFSub(te1, te2) }
355                 else        { llvm::LLVMConstSub(te1, te2) }
356               }
357               ast::BiMul    => {
358                 if is_float { llvm::LLVMConstFMul(te1, te2) }
359                 else        { llvm::LLVMConstMul(te1, te2) }
360               }
361               ast::BiDiv    => {
362                 if is_float    { llvm::LLVMConstFDiv(te1, te2) }
363                 else if signed { llvm::LLVMConstSDiv(te1, te2) }
364                 else           { llvm::LLVMConstUDiv(te1, te2) }
365               }
366               ast::BiRem    => {
367                 if is_float    { llvm::LLVMConstFRem(te1, te2) }
368                 else if signed { llvm::LLVMConstSRem(te1, te2) }
369                 else           { llvm::LLVMConstURem(te1, te2) }
370               }
371               ast::BiAnd    => llvm::LLVMConstAnd(te1, te2),
372               ast::BiOr     => llvm::LLVMConstOr(te1, te2),
373               ast::BiBitXor => llvm::LLVMConstXor(te1, te2),
374               ast::BiBitAnd => llvm::LLVMConstAnd(te1, te2),
375               ast::BiBitOr  => llvm::LLVMConstOr(te1, te2),
376               ast::BiShl    => llvm::LLVMConstShl(te1, te2),
377               ast::BiShr    => {
378                 if signed { llvm::LLVMConstAShr(te1, te2) }
379                 else      { llvm::LLVMConstLShr(te1, te2) }
380               }
381               ast::BiEq     => {
382                   if is_float { ConstFCmp(RealOEQ, te1, te2) }
383                   else        { ConstICmp(IntEQ, te1, te2)   }
384               },
385               ast::BiLt     => {
386                   if is_float { ConstFCmp(RealOLT, te1, te2) }
387                   else        {
388                       if signed { ConstICmp(IntSLT, te1, te2) }
389                       else      { ConstICmp(IntULT, te1, te2) }
390                   }
391               },
392               ast::BiLe     => {
393                   if is_float { ConstFCmp(RealOLE, te1, te2) }
394                   else        {
395                       if signed { ConstICmp(IntSLE, te1, te2) }
396                       else      { ConstICmp(IntULE, te1, te2) }
397                   }
398               },
399               ast::BiNe     => {
400                   if is_float { ConstFCmp(RealONE, te1, te2) }
401                   else        { ConstICmp(IntNE, te1, te2) }
402               },
403               ast::BiGe     => {
404                   if is_float { ConstFCmp(RealOGE, te1, te2) }
405                   else        {
406                       if signed { ConstICmp(IntSGE, te1, te2) }
407                       else      { ConstICmp(IntUGE, te1, te2) }
408                   }
409               },
410               ast::BiGt     => {
411                   if is_float { ConstFCmp(RealOGT, te1, te2) }
412                   else        {
413                       if signed { ConstICmp(IntSGT, te1, te2) }
414                       else      { ConstICmp(IntUGT, te1, te2) }
415                   }
416               },
417             }, true)
418           },
419           ast::ExprUnary(u, ref e) => {
420             let (te, _, _) = const_expr(cx, &**e, is_local);
421             let ty = ty::expr_ty(cx.tcx(), &**e);
422             let is_float = ty::type_is_fp(ty);
423             return (match u {
424               ast::UnBox | ast::UnUniq | ast::UnDeref => {
425                 let (dv, _dt) = const_deref(cx, te, ty, true);
426                 dv
427               }
428               ast::UnNot    => llvm::LLVMConstNot(te),
429               ast::UnNeg    => {
430                 if is_float { llvm::LLVMConstFNeg(te) }
431                 else        { llvm::LLVMConstNeg(te) }
432               }
433             }, true)
434           }
435           ast::ExprField(ref base, field, _) => {
436               let (bv, inlineable, bt) = const_expr(cx, &**base, is_local);
437               let brepr = adt::represent_type(cx, bt);
438               expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| {
439                   let ix = ty::field_idx_strict(cx.tcx(), field.node.name, field_tys);
440                   (adt::const_get_field(cx, &*brepr, bv, discr, ix), inlineable)
441               })
442           }
443           ast::ExprTupField(ref base, idx, _) => {
444               let (bv, inlineable, bt) = const_expr(cx, &**base, is_local);
445               let brepr = adt::represent_type(cx, bt);
446               expr::with_field_tys(cx.tcx(), bt, None, |discr, _| {
447                   (adt::const_get_field(cx, &*brepr, bv, discr, idx.node), inlineable)
448               })
449           }
450
451           ast::ExprIndex(ref base, ref index) => {
452               let (bv, inlineable, bt) = const_expr(cx, &**base, is_local);
453               let iv = match const_eval::eval_const_expr(cx.tcx(), &**index) {
454                   const_eval::const_int(i) => i as u64,
455                   const_eval::const_uint(u) => u,
456                   _ => cx.sess().span_bug(index.span,
457                                           "index is not an integer-constant expression")
458               };
459               let (arr, len) = match ty::get(bt).sty {
460                   ty::ty_vec(_, Some(u)) => (bv, C_uint(cx, u)),
461                   ty::ty_open(ty) => match ty::get(ty).sty {
462                       ty::ty_vec(_, None) | ty::ty_str => {
463                           let e1 = const_get_elt(cx, bv, [0]);
464                           (const_deref_ptr(cx, e1), const_get_elt(cx, bv, [1]))
465                       },
466                       _ => cx.sess().span_bug(base.span,
467                                               format!("index-expr base must be a vector \
468                                                        or string type, found {}",
469                                                       ty_to_string(cx.tcx(), bt)).as_slice())
470                   },
471                   ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
472                       ty::ty_vec(_, Some(u)) => {
473                           (const_deref_ptr(cx, bv), C_uint(cx, u))
474                       },
475                       _ => cx.sess().span_bug(base.span,
476                                               format!("index-expr base must be a vector \
477                                                        or string type, found {}",
478                                                       ty_to_string(cx.tcx(), bt)).as_slice())
479                   },
480                   _ => cx.sess().span_bug(base.span,
481                                           format!("index-expr base must be a vector \
482                                                    or string type, found {}",
483                                                   ty_to_string(cx.tcx(), bt)).as_slice())
484               };
485
486               let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
487               let len = match ty::get(bt).sty {
488                   ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
489                       ty::ty_str => {
490                           assert!(len > 0);
491                           len - 1
492                       }
493                       _ => len
494                   },
495                   _ => len
496               };
497               if iv >= len {
498                   // FIXME #3170: report this earlier on in the const-eval
499                   // pass. Reporting here is a bit late.
500                   cx.sess().span_err(e.span,
501                                      "const index-expr is out of bounds");
502               }
503               (const_get_elt(cx, arr, [iv as c_uint]), inlineable)
504           }
505           ast::ExprCast(ref base, _) => {
506             let ety = ty::expr_ty(cx.tcx(), e);
507             let llty = type_of::type_of(cx, ety);
508             let (v, inlineable, basety) = const_expr(cx, &**base, is_local);
509             return (match (expr::cast_type_kind(cx.tcx(), basety),
510                            expr::cast_type_kind(cx.tcx(), ety)) {
511
512               (expr::cast_integral, expr::cast_integral) => {
513                 let s = ty::type_is_signed(basety) as Bool;
514                 llvm::LLVMConstIntCast(v, llty.to_ref(), s)
515               }
516               (expr::cast_integral, expr::cast_float) => {
517                 if ty::type_is_signed(basety) {
518                     llvm::LLVMConstSIToFP(v, llty.to_ref())
519                 } else {
520                     llvm::LLVMConstUIToFP(v, llty.to_ref())
521                 }
522               }
523               (expr::cast_float, expr::cast_float) => {
524                 llvm::LLVMConstFPCast(v, llty.to_ref())
525               }
526               (expr::cast_float, expr::cast_integral) => {
527                 if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty.to_ref()) }
528                 else { llvm::LLVMConstFPToUI(v, llty.to_ref()) }
529               }
530               (expr::cast_enum, expr::cast_integral) => {
531                 let repr = adt::represent_type(cx, basety);
532                 let discr = adt::const_get_discrim(cx, &*repr, v);
533                 let iv = C_integral(cx.int_type(), discr, false);
534                 let ety_cast = expr::cast_type_kind(cx.tcx(), ety);
535                 match ety_cast {
536                     expr::cast_integral => {
537                         let s = ty::type_is_signed(ety) as Bool;
538                         llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
539                     }
540                     _ => cx.sess().bug("enum cast destination is not \
541                                         integral")
542                 }
543               }
544               (expr::cast_pointer, expr::cast_pointer) => {
545                 llvm::LLVMConstPointerCast(v, llty.to_ref())
546               }
547               (expr::cast_integral, expr::cast_pointer) => {
548                 llvm::LLVMConstIntToPtr(v, llty.to_ref())
549               }
550               _ => {
551                 cx.sess().impossible_case(e.span,
552                                           "bad combination of types for cast")
553               }
554             }, inlineable)
555           }
556           ast::ExprAddrOf(mutbl, ref sub) => {
557               let (e, _, _) = const_expr(cx, &**sub, is_local);
558               (const_addr_of(cx, e, mutbl), false)
559           }
560           ast::ExprTup(ref es) => {
561               let ety = ty::expr_ty(cx.tcx(), e);
562               let repr = adt::represent_type(cx, ety);
563               let (vals, inlineable) = map_list(es.as_slice());
564               (adt::trans_const(cx, &*repr, 0, vals.as_slice()), inlineable)
565           }
566           ast::ExprStruct(_, ref fs, ref base_opt) => {
567               let ety = ty::expr_ty(cx.tcx(), e);
568               let repr = adt::represent_type(cx, ety);
569               let tcx = cx.tcx();
570
571               let base_val = match *base_opt {
572                 Some(ref base) => Some(const_expr(cx, &**base, is_local)),
573                 None => None
574               };
575
576               expr::with_field_tys(tcx, ety, Some(e.id), |discr, field_tys| {
577                   let (cs, inlineable) = vec::unzip(field_tys.iter().enumerate()
578                       .map(|(ix, &field_ty)| {
579                       match fs.iter().find(|f| field_ty.ident.name == f.ident.node.name) {
580                           Some(ref f) => first_two(const_expr(cx, &*f.expr, is_local)),
581                           None => {
582                               match base_val {
583                                 Some((bv, inlineable, _)) => {
584                                     (adt::const_get_field(cx, &*repr, bv, discr, ix),
585                                      inlineable)
586                                 }
587                                 None => cx.sess().span_bug(e.span, "missing struct field")
588                               }
589                           }
590                       }
591                   }));
592                   (adt::trans_const(cx, &*repr, discr, cs.as_slice()),
593                    inlineable.iter().fold(true, |a, &b| a && b))
594               })
595           }
596           ast::ExprVec(ref es) => {
597             let (v, _, inlineable) = const_vec(cx,
598                                                e,
599                                                es.as_slice(),
600                                                is_local);
601             (v, inlineable)
602           }
603           ast::ExprRepeat(ref elem, ref count) => {
604             let vec_ty = ty::expr_ty(cx.tcx(), e);
605             let unit_ty = ty::sequence_element_type(cx.tcx(), vec_ty);
606             let llunitty = type_of::type_of(cx, unit_ty);
607             let n = match const_eval::eval_const_expr(cx.tcx(), &**count) {
608                 const_eval::const_int(i)  => i as uint,
609                 const_eval::const_uint(i) => i as uint,
610                 _ => cx.sess().span_bug(count.span, "count must be integral const expression.")
611             };
612             let vs = Vec::from_elem(n, const_expr(cx, &**elem, is_local).val0());
613             let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
614                 C_struct(cx, vs.as_slice(), false)
615             } else {
616                 C_array(llunitty, vs.as_slice())
617             };
618             (v, true)
619           }
620           ast::ExprPath(ref pth) => {
621             // Assert that there are no type parameters in this path.
622             assert!(pth.segments.iter().all(|seg| seg.types.is_empty()));
623
624             let opt_def = cx.tcx().def_map.borrow().find_copy(&e.id);
625             match opt_def {
626                 Some(def::DefFn(def_id, _fn_style)) => {
627                     if !ast_util::is_local(def_id) {
628                         let ty = csearch::get_type(cx.tcx(), def_id).ty;
629                         (base::trans_external_path(cx, def_id, ty), true)
630                     } else {
631                         assert!(ast_util::is_local(def_id));
632                         (base::get_item_val(cx, def_id.node), true)
633                     }
634                 }
635                 Some(def::DefStatic(def_id, false)) => {
636                     get_const_val(cx, def_id)
637                 }
638                 Some(def::DefVariant(enum_did, variant_did, _)) => {
639                     let ety = ty::expr_ty(cx.tcx(), e);
640                     let repr = adt::represent_type(cx, ety);
641                     let vinfo = ty::enum_variant_with_id(cx.tcx(),
642                                                          enum_did,
643                                                          variant_did);
644                     (adt::trans_const(cx, &*repr, vinfo.disr_val, []), true)
645                 }
646                 Some(def::DefStruct(_)) => {
647                     let ety = ty::expr_ty(cx.tcx(), e);
648                     let llty = type_of::type_of(cx, ety);
649                     (C_null(llty), true)
650                 }
651                 _ => {
652                     cx.sess().span_bug(e.span, "expected a const, fn, struct, or variant def")
653                 }
654             }
655           }
656           ast::ExprCall(ref callee, ref args) => {
657               let opt_def = cx.tcx().def_map.borrow().find_copy(&callee.id);
658               match opt_def {
659                   Some(def::DefStruct(_)) => {
660                       let ety = ty::expr_ty(cx.tcx(), e);
661                       let repr = adt::represent_type(cx, ety);
662                       let (arg_vals, inlineable) = map_list(args.as_slice());
663                       (adt::trans_const(cx, &*repr, 0, arg_vals.as_slice()),
664                        inlineable)
665                   }
666                   Some(def::DefVariant(enum_did, variant_did, _)) => {
667                       let ety = ty::expr_ty(cx.tcx(), e);
668                       let repr = adt::represent_type(cx, ety);
669                       let vinfo = ty::enum_variant_with_id(cx.tcx(),
670                                                            enum_did,
671                                                            variant_did);
672                       let (arg_vals, inlineable) = map_list(args.as_slice());
673                       (adt::trans_const(cx,
674                                         &*repr,
675                                         vinfo.disr_val,
676                                         arg_vals.as_slice()), inlineable)
677                   }
678                   _ => cx.sess().span_bug(e.span, "expected a struct or variant def")
679               }
680           }
681           ast::ExprParen(ref e) => first_two(const_expr(cx, &**e, is_local)),
682           ast::ExprBlock(ref block) => {
683             match block.expr {
684                 Some(ref expr) => first_two(const_expr(cx, &**expr, is_local)),
685                 None => (C_nil(cx), true)
686             }
687           }
688           _ => cx.sess().span_bug(e.span,
689                   "bad constant expression type in consts::const_expr")
690         };
691     }
692 }
693
694 pub fn trans_const(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) {
695     unsafe {
696         let _icx = push_ctxt("trans_const");
697         let g = base::get_item_val(ccx, id);
698         // At this point, get_item_val has already translated the
699         // constant's initializer to determine its LLVM type.
700         let v = ccx.const_values().borrow().get_copy(&id);
701         llvm::LLVMSetInitializer(g, v);
702
703         // `get_item_val` left `g` with external linkage, but we just set an
704         // initializer for it.  But we don't know yet if `g` should really be
705         // defined in this compilation unit, so we set its linkage to
706         // `AvailableExternallyLinkage`.  (It's still a definition, but acts
707         // like a declaration for most purposes.)  If `g` really should be
708         // declared here, then `trans_item` will fix up the linkage later on.
709         llvm::SetLinkage(g, llvm::AvailableExternallyLinkage);
710
711         if m != ast::MutMutable {
712             llvm::LLVMSetGlobalConstant(g, True);
713         }
714         debuginfo::create_global_var_metadata(ccx, id, g);
715     }
716 }