@@ -73,9 +73,15 @@ pub fn const_vec(cx: @crate_ctxt, e: @ast::expr, es: &[@ast::expr])
73
73
let vec_ty = ty:: expr_ty ( cx. tcx , e) ;
74
74
let unit_ty = ty:: sequence_element_type ( cx. tcx , vec_ty) ;
75
75
let llunitty = type_of:: type_of ( cx, unit_ty) ;
76
- let v = C_array ( llunitty, es. map ( |e| const_expr ( cx, * e) ) ) ;
77
76
let unit_sz = machine:: llsize_of ( cx, llunitty) ;
78
77
let sz = llvm:: LLVMConstMul ( C_uint ( cx, es. len ( ) ) , unit_sz) ;
78
+ let vs = es. map ( |e| const_expr ( cx, * e) ) ;
79
+ // If the vector contains enums, an LLVM array won't work.
80
+ let v = if vs. any ( |vi| val_ty ( * vi) != llunitty) {
81
+ C_struct ( vs)
82
+ } else {
83
+ C_array ( llunitty, vs)
84
+ } ;
79
85
return ( v, sz, llunitty) ;
80
86
}
81
87
}
@@ -279,15 +285,17 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
279
285
// call. Despite that being "a const", it's not the kind of
280
286
// const you can ask for the integer-value of, evidently. This
281
287
// might be an LLVM bug, not sure. In any case, to work around
282
- // this we drop down to the array-type level here and just ask
283
- // how long the array-type itself is, ignoring the length we
284
- // pulled out of the slice. This in turn only works because we
285
- // picked out the original globalvar via const_deref and so can
286
- // recover the array-size of the underlying array, and all this
287
- // will hold together exactly as long as we _don't_ support
288
- // const sub-slices (that is, slices that represent something
289
- // other than a whole array). At that point we'll have more and
290
- // uglier work to do here, but for now this should work.
288
+ // this we obtain the initializer and count how many elements it
289
+ // has, ignoring the length we pulled out of the slice. (Note
290
+ // that the initializer might be a struct rather than an array,
291
+ // if enums are involved.) This only works because we picked out
292
+ // the original globalvar via const_deref and so can recover the
293
+ // array-size of the underlying array (or the element count of
294
+ // the underlying struct), and all this will hold together
295
+ // exactly as long as we _don't_ support const sub-slices (that
296
+ // is, slices that represent something other than a whole
297
+ // array). At that point we'll have more and uglier work to do
298
+ // here, but for now this should work.
291
299
//
292
300
// In the future, what we should be doing here is the
293
301
// moral equivalent of:
@@ -299,7 +307,7 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
299
307
// not want to consider sizeof() a constant expression
300
308
// we can get the value (as a number) out of.
301
309
302
- let len = llvm:: LLVMGetArrayLength ( val_ty ( arr) ) as u64 ;
310
+ let len = llvm:: LLVMGetNumOperands ( arr) as u64 ;
303
311
let len = match ty:: get ( bt) . sty {
304
312
ty:: ty_estr( * ) => { assert len > 0 ; len - 1 } ,
305
313
_ => len
@@ -346,10 +354,8 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
346
354
}
347
355
ast:: expr_addr_of( ast:: m_imm, sub) => {
348
356
let cv = const_expr ( cx, sub) ;
349
- let subty = ty:: expr_ty ( cx. tcx , sub) ,
350
- llty = type_of:: type_of ( cx, subty) ;
351
357
let gv = do str:: as_c_str ( "const" ) |name| {
352
- llvm:: LLVMAddGlobal ( cx. llmod , llty , name)
358
+ llvm:: LLVMAddGlobal ( cx. llmod , val_ty ( cv ) , name)
353
359
} ;
354
360
llvm:: LLVMSetInitializer ( gv, cv) ;
355
361
llvm:: LLVMSetGlobalConstant ( gv, True ) ;
@@ -377,8 +383,7 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
377
383
}
378
384
} )
379
385
} ;
380
- let llty = type_of:: type_of ( cx, ety) ;
381
- C_named_struct ( llty, [ C_struct ( cs) ] )
386
+ C_struct ( [ C_struct ( cs) ] )
382
387
}
383
388
ast:: expr_vec( es, ast:: m_imm) => {
384
389
let ( v, _, _) = const_vec ( cx, e, es) ;
@@ -434,7 +439,13 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
434
439
let lldiscrim = base:: get_discrim_val ( cx, e. span ,
435
440
enum_did,
436
441
variant_did) ;
437
- C_struct ( ~[ lldiscrim] )
442
+ // However, we still have to pad it out to the
443
+ // size of the full enum; see the expr_call case,
444
+ // below.
445
+ let ety = ty:: expr_ty ( cx. tcx , e) ;
446
+ let size = machine:: static_size_of_enum ( cx, ety) ;
447
+ let padding = C_null ( T_array ( T_i8 ( ) , size) ) ;
448
+ C_struct ( ~[ lldiscrim, padding] )
438
449
}
439
450
Some ( ast:: def_struct( _) ) => {
440
451
let ety = ty:: expr_ty ( cx. tcx , e) ;
@@ -450,14 +461,12 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
450
461
ast:: expr_call ( callee, args, _) => {
451
462
match cx. tcx . def_map . find ( & callee. id ) {
452
463
Some ( ast:: def_struct( def_id) ) => {
453
- let ety = ty:: expr_ty ( cx. tcx , e) ;
454
- let llty = type_of:: type_of ( cx, ety) ;
455
464
let llstructbody =
456
465
C_struct ( args. map ( |a| const_expr ( cx, * a) ) ) ;
457
466
if ty:: ty_dtor ( cx. tcx , def_id) . is_present ( ) {
458
- C_named_struct ( llty , ~[ llstructbody, C_u8 ( 0 ) ] )
467
+ C_struct ( ~[ llstructbody, C_u8 ( 0 ) ] )
459
468
} else {
460
- C_named_struct ( llty , ~[ llstructbody ] )
469
+ C_struct ( ~[ llstructbody ] )
461
470
}
462
471
}
463
472
Some ( ast:: def_variant( tid, vid) ) => {
@@ -470,7 +479,20 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
470
479
471
480
// FIXME (#1645): enum body alignment is generaly wrong.
472
481
if !degen {
473
- C_packed_struct ( ~[ discrim, c_args] )
482
+ // Pad out the data to the size of its type_of;
483
+ // this is necessary if the enum is contained
484
+ // within an aggregate (tuple, struct, vector) so
485
+ // that the next element is at the right offset.
486
+ let actual_size =
487
+ machine:: llsize_of_real ( cx, llvm:: LLVMTypeOf ( c_args) ) ;
488
+ let padding =
489
+ C_null ( T_array ( T_i8 ( ) , size - actual_size) ) ;
490
+ // A packed_struct has an alignment of 1; thus,
491
+ // wrapping one around c_args will misalign it the
492
+ // same way we normally misalign enum bodies
493
+ // without affecting its internal alignment or
494
+ // changing the alignment of the enum.
495
+ C_struct ( ~[ discrim, C_packed_struct ( ~[ c_args] ) , padding] )
474
496
} else if size == 0 {
475
497
C_struct ( ~[ discrim] )
476
498
} else {
0 commit comments