@@ -394,9 +394,20 @@ pub fn trans_drop_flag_ptr(bcx: block, r: &Repr, val: ValueRef) -> ValueRef {
394
394
* alignment!) from the representation's `type_of`, so it needs a
395
395
* pointer cast before use.
396
396
*
397
- * Currently it has the same size as the type, but this may be changed
398
- * in the future to avoid allocating unnecessary space after values of
399
- * shorter-than-maximum cases.
397
+ * The LLVM type system does not directly support unions, and only
398
+ * pointers can be bitcast, so a constant (and, by extension, the
399
+ * GlobalVariable initialized by it) will have a type that can vary
400
+ * depending on which case of an enum it is.
401
+ *
402
+ * To understand the alignment situation, consider `enum E { V64(u64),
403
+ * V32(u32, u32) }` on win32. The type should have 8-byte alignment
404
+ * to accommodate the u64 (currently it doesn't; this is a known bug),
405
+ * but `V32(x, y)` would have LLVM type `{i32, i32, i32}`, which is
406
+ * 4-byte aligned.
407
+ *
408
+ * Currently the returned value has the same size as the type, but
409
+ * this may be changed in the future to avoid allocating unnecessary
410
+ * space after values of shorter-than-maximum cases.
400
411
*/
401
412
pub fn trans_const ( ccx : @CrateContext , r : & Repr , discr : int ,
402
413
vals : & [ ValueRef ] ) -> ValueRef {
@@ -424,6 +435,9 @@ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int,
424
435
let max_sz = cases. map ( |s| s. size ) . max ( ) ;
425
436
let body = build_const_struct ( ccx, case, vals) ;
426
437
438
+ // The unary packed struct has alignment 1 regardless of
439
+ // its contents, so it will always be located at the
440
+ // expected offset at runtime.
427
441
C_struct ( [ C_int ( ccx, discr) ,
428
442
C_packed_struct ( [ C_struct ( body) ] ) ,
429
443
padding ( max_sz - case. size ) ] )
@@ -434,6 +448,12 @@ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int,
434
448
/**
435
449
* Building structs is a little complicated, because we might need to
436
450
* insert padding if a field's value is less aligned than its type.
451
+ *
452
+ * Continuing the example from `trans_const`, a value of type `(u32,
453
+ * E)` should have the `E` at offset 8, but if that field's
454
+ * initializer is 4-byte aligned then simply translating the tuple as
455
+ * a two-element struct will locate it at offset 4, and accesses to it
456
+ * will read the wrong memory.
437
457
*/
438
458
fn build_const_struct ( ccx : @CrateContext , st : & Struct , vals : & [ ValueRef ] )
439
459
-> ~[ ValueRef ] {
0 commit comments