@@ -73,9 +73,15 @@ pub fn const_vec(cx: @crate_ctxt, e: @ast::expr, es: &[@ast::expr])
7373 let vec_ty = ty:: expr_ty ( cx. tcx , e) ;
7474 let unit_ty = ty:: sequence_element_type ( cx. tcx , vec_ty) ;
7575 let llunitty = type_of:: type_of ( cx, unit_ty) ;
76- let v = C_array ( llunitty, es. map ( |e| const_expr ( cx, * e) ) ) ;
7776 let unit_sz = machine:: llsize_of ( cx, llunitty) ;
7877 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+ } ;
7985 return ( v, sz, llunitty) ;
8086 }
8187}
@@ -279,15 +285,17 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
279285 // call. Despite that being "a const", it's not the kind of
280286 // const you can ask for the integer-value of, evidently. This
281287 // 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.
291299 //
292300 // In the future, what we should be doing here is the
293301 // moral equivalent of:
@@ -299,7 +307,7 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
299307 // not want to consider sizeof() a constant expression
300308 // we can get the value (as a number) out of.
301309
302- let len = llvm:: LLVMGetArrayLength ( val_ty ( arr) ) as u64 ;
310+ let len = llvm:: LLVMGetNumOperands ( arr) as u64 ;
303311 let len = match ty:: get ( bt) . sty {
304312 ty:: ty_estr( * ) => { assert len > 0 ; len - 1 } ,
305313 _ => len
@@ -346,10 +354,8 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
346354 }
347355 ast:: expr_addr_of( ast:: m_imm, sub) => {
348356 let cv = const_expr ( cx, sub) ;
349- let subty = ty:: expr_ty ( cx. tcx , sub) ,
350- llty = type_of:: type_of ( cx, subty) ;
351357 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)
353359 } ;
354360 llvm:: LLVMSetInitializer ( gv, cv) ;
355361 llvm:: LLVMSetGlobalConstant ( gv, True ) ;
@@ -377,8 +383,7 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
377383 }
378384 } )
379385 } ;
380- let llty = type_of:: type_of ( cx, ety) ;
381- C_named_struct ( llty, [ C_struct ( cs) ] )
386+ C_struct ( [ C_struct ( cs) ] )
382387 }
383388 ast:: expr_vec( es, ast:: m_imm) => {
384389 let ( v, _, _) = const_vec ( cx, e, es) ;
@@ -434,7 +439,13 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
434439 let lldiscrim = base:: get_discrim_val ( cx, e. span ,
435440 enum_did,
436441 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] )
438449 }
439450 Some ( ast:: def_struct( _) ) => {
440451 let ety = ty:: expr_ty ( cx. tcx , e) ;
@@ -450,14 +461,12 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
450461 ast:: expr_call ( callee, args, _) => {
451462 match cx. tcx . def_map . find ( & callee. id ) {
452463 Some ( ast:: def_struct( def_id) ) => {
453- let ety = ty:: expr_ty ( cx. tcx , e) ;
454- let llty = type_of:: type_of ( cx, ety) ;
455464 let llstructbody =
456465 C_struct ( args. map ( |a| const_expr ( cx, * a) ) ) ;
457466 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 ) ] )
459468 } else {
460- C_named_struct ( llty , ~[ llstructbody ] )
469+ C_struct ( ~[ llstructbody ] )
461470 }
462471 }
463472 Some ( ast:: def_variant( tid, vid) ) => {
@@ -470,7 +479,20 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
470479
471480 // FIXME (#1645): enum body alignment is generaly wrong.
472481 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] )
474496 } else if size == 0 {
475497 C_struct ( ~[ discrim] )
476498 } else {
0 commit comments