@@ -43,6 +43,33 @@ fn const_vec(cx: @crate_ctxt, e: @ast::expr, es: &[@ast::expr])
43
43
return ( v, sz, llunitty) ;
44
44
}
45
45
46
+ fn const_deref( v: ValueRef ) -> ValueRef {
47
+ assert llvm:: LLVMIsGlobalConstant ( v) == True ;
48
+ llvm:: LLVMGetInitializer ( v)
49
+ }
50
+
51
+ fn const_get_elt( v: ValueRef , u: uint) -> ValueRef {
52
+ let u = u;
53
+ llvm : : LLVMConstExtractValue ( v, ptr:: addr_of( u) , 1 as c_uint)
54
+ }
55
+
56
+ fn const_autoderef( ty: ty:: t, v: ValueRef )
57
+ -> ( ty:: t, ValueRef ) {
58
+ let mut t1 = ty;
59
+ let mut v1 = v;
60
+ loop {
61
+ // Only rptrs can be autoderef'ed in a const context.
62
+ match ty:: get( ty) . struct {
63
+ ty:: ty_rptr( _, mt) => {
64
+ t1 = mt. ty ;
65
+ v1 = const_deref ( v1) ;
66
+ }
67
+ _ => return ( t1, v1)
68
+ }
69
+ }
70
+ }
71
+
72
+
46
73
fn const_expr( cx : @crate_ctxt , e : @ast:: expr ) -> ValueRef {
47
74
let _icx = cx. insn_ctxt ( ~"const_expr") ;
48
75
match e. node {
@@ -106,15 +133,74 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
106
133
return match u {
107
134
ast:: box( _) |
108
135
ast:: uniq( _) |
109
- ast:: deref => cx. sess . span_bug ( e. span ,
110
- ~"bad unop type in const_expr") ,
136
+ ast:: deref => const_deref ( te) ,
111
137
ast:: not => llvm:: LLVMConstNot ( te) ,
112
138
ast:: neg => {
113
139
if is_float { llvm:: LLVMConstFNeg ( te) }
114
140
else { llvm:: LLVMConstNeg ( te) }
115
141
}
116
142
}
117
143
}
144
+ ast:: expr_field( base, field, _) => {
145
+ let bt = ty:: expr_ty ( cx. tcx , base) ;
146
+ let bv = const_expr ( cx, base) ;
147
+ let ( bt, bv) = const_autoderef ( bt, bv) ;
148
+ let fields = match ty:: get ( bt) . struct {
149
+ ty:: ty_rec( fs) => fs,
150
+ ty:: ty_class( did, substs) =>
151
+ ty:: class_items_as_mutable_fields ( cx. tcx , did, substs) ,
152
+ _ => cx. sess . span_bug ( e. span ,
153
+ ~"field access on unknown type in const ") ,
154
+ } ;
155
+ let ix = field_idx_strict ( cx. tcx , e. span , field, fields) ;
156
+ const_get_elt ( bv, ix)
157
+ }
158
+
159
+ ast:: expr_index( base, index) => {
160
+ let bt = ty:: expr_ty ( cx. tcx , base) ;
161
+ let bv = const_expr ( cx, base) ;
162
+ let ( bt, bv) = const_autoderef ( bt, bv) ;
163
+ let iv = match const_eval:: eval_const_expr ( cx. tcx , index) {
164
+ const_eval:: const_int( i) => i as u64 ,
165
+ const_eval:: const_uint( u) => u,
166
+ _ => cx. sess . span_bug ( index. span ,
167
+ ~"index is not an integer-constant \
168
+ expression")
169
+ } ;
170
+ let ( arr, len) = match ty:: get ( bt) . struct {
171
+ ty:: ty_evec( _, vstore) | ty:: ty_estr( vstore) =>
172
+ match vstore {
173
+ ty:: vstore_fixed( u) =>
174
+ ( bv, C_uint ( cx, u) ) ,
175
+
176
+ ty:: vstore_slice( _) => {
177
+ let unit_ty = ty:: sequence_element_type ( cx. tcx , bt) ;
178
+ let llunitty = type_of:: type_of ( cx, unit_ty) ;
179
+ let unit_sz = shape:: llsize_of ( cx, llunitty) ;
180
+ ( const_deref ( const_get_elt ( bv, 0 ) ) ,
181
+ llvm:: LLVMConstUDiv ( const_get_elt ( bv, 1 ) ,
182
+ unit_sz) )
183
+ } ,
184
+ _ => cx. sess . span_bug ( base. span ,
185
+ ~"index-expr base must be \
186
+ fixed-size or slice")
187
+ } ,
188
+ _ => cx. sess . span_bug ( base. span ,
189
+ ~"index-expr base must be \
190
+ a vector or string type ")
191
+ } ;
192
+ let len = llvm:: LLVMConstIntGetZExtValue ( len) as u64 ;
193
+ let len = match ty:: get ( bt) . struct {
194
+ ty:: ty_estr( * ) => { assert len > 0 ; len - 1 } ,
195
+ _ => len
196
+ } ;
197
+ if iv >= len {
198
+ // Better late than never for reporting this?
199
+ cx. sess . span_err ( e. span ,
200
+ ~"const index-expr is out of bounds") ;
201
+ }
202
+ const_get_elt ( arr, iv as uint )
203
+ }
118
204
ast:: expr_cast( base, tp) => {
119
205
let ety = ty:: expr_ty ( cx. tcx , e) , llty = type_of:: type_of ( cx, ety) ;
120
206
let basety = ty:: expr_ty ( cx. tcx , base) ;
0 commit comments