@@ -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 {
@@ -419,6 +430,9 @@ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int,
419
430
let max_sz = cases. map ( |s| s. size ) . max ( ) ;
420
431
let body = build_const_struct ( ccx, case, vals) ;
421
432
433
+ // The unary packed struct has alignment 1 regardless of
434
+ // its contents, so it will always be located at the
435
+ // expected offset at runtime.
422
436
C_struct ( [ C_int ( ccx, discr) ,
423
437
C_packed_struct ( [ C_struct ( body) ] ) ,
424
438
padding ( max_sz - case. size ) ] )
@@ -429,6 +443,12 @@ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int,
429
443
/**
430
444
* Building structs is a little complicated, because we might need to
431
445
* insert padding if a field's value is less aligned than its type.
446
+ *
447
+ * Continuing the example from `trans_const`, a value of type `(u32,
448
+ * E)` should have the `E` at offset 8, but if that field's
449
+ * initializer is 4-byte aligned then simply translating the tuple as
450
+ * a two-element struct will locate it at offset 4, and accesses to it
451
+ * will read the wrong memory.
432
452
*/
433
453
fn build_const_struct ( ccx : @CrateContext , st : & Struct , vals : & [ ValueRef ] )
434
454
-> ~[ ValueRef ] {
0 commit comments