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