Change:
The attached source produces code that misbehaves on some platforms that are picky about memory access alignment. The code should exit with code 2, but on both Emscripten-generated JavaScript and ARMv5, it finishes with exit code 1 to indicate that the field is incorrectly tested as equal to . Changing the field to a type results in proper execution on these platforms. All optimization levels seem to cause it. Libraries that make use of structs with fields followed by enums seem particularly prone to this problem. It all works fine on platforms that allow unaligned memory access like x86, ARMv6, etc. Expected output: (x86, ARMv6) Actual output: (ARMv5, Emscripten) Note that the same ARM binary runs on both ARMv5 and ARMv6 platforms, producing the different results. See also: ( and removed)
To quote myself:

Discussion:
CEnum(ity, min, max) => { assert_discr_in_range(ity, min, max, discr); Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true), <del> val) </del> <ins> val); </ins> } General(ity, ref cases, dtor) => { if dtor_active(dtor) {

Store(bcx, C_u8(bcx.ccx(), DTOR_NEEDED as usize), ptr); } Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true), <del> GEPi(bcx, val, &[0, 0])) </del> <ins> GEPi(bcx, val, &[0, 0])); </ins> } Univariant(ref st, dtor) => { assert_eq!(discr, 0);

RawNullablePointer { nndiscr, nnty, ..} => { if discr != nndiscr { let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty); <del> Store(bcx, C_null(llptrty), val) </del> <ins> Store(bcx, C_null(llptrty), val); </ins> } } StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { if discr != nndiscr { let llptrptr = GEPi(bcx, val, &discrfield[..]); let llptrty = val_ty(llptrptr).element_type(); <del> Store(bcx, C_null(llptrty), llptrptr) </del> <ins> Store(bcx, C_null(llptrty), llptrptr); </ins> } } }

} let ptr = to_arg_ty_ptr(cx, ptr, t); <ins> let align = type_of::align_of(cx.ccx(), t); </ins> if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() { <del> return Load(cx, ptr); </del> <ins> let load = Load(cx, ptr); unsafe { llvm::LLVMSetAlignment(load, align); } return load; </ins> } unsafe {

Load(cx, ptr) }; <ins> unsafe { llvm::LLVMSetAlignment(val, align); } </ins> from_arg_ty(cx, val, t) } /// Helper for storing values in memory. Does the necessary conversion if the in-memory type /// differs from the type used for SSA values. pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) { <del> Store(cx, to_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t)); </del> <ins> if cx.unreachable.get() { return; } let store = Store(cx, to_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t)); unsafe { llvm::LLVMSetAlignment(store, type_of::align_of(cx.ccx(), t)); } </ins> } pub fn to_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {

} } <del> pub fn Store(cx: Block, val: ValueRef, ptr: ValueRef) { if cx.unreachable.get() { return; } </del> <ins> pub fn Store(cx: Block, val: ValueRef, ptr: ValueRef) -> ValueRef { if cx.unreachable.get() { return C_nil(cx.ccx()); } </ins> B(cx).store(val, ptr) } <del> pub fn VolatileStore(cx: Block, val: ValueRef, ptr: ValueRef) { if cx.unreachable.get() { return; } </del> <ins> pub fn VolatileStore(cx: Block, val: ValueRef, ptr: ValueRef) -> ValueRef { if cx.unreachable.get() { return C_nil(cx.ccx()); } </ins> B(cx).volatile_store(val, ptr) }

value } <del> pub fn store(&self, val: ValueRef, ptr: ValueRef) { </del> <ins> pub fn store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef { </ins> debug!("Store {} -> {}", self.ccx.tn().val_to_string(val), self.ccx.tn().val_to_string(ptr)); assert!(!self.llbuilder.is_null()); self.count_insn("store"); unsafe { <del> llvm::LLVMBuildStore(self.llbuilder, val, ptr); </del> <ins> llvm::LLVMBuildStore(self.llbuilder, val, ptr) </ins> } } <del> pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef) { </del> <ins> pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef { </ins> debug!("Store {} -> {}", self.ccx.tn().val_to_string(val), self.ccx.tn().val_to_string(ptr));

unsafe { let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr); llvm::LLVMSetVolatile(insn, llvm::True); <ins> insn </ins> } }

// appropriately sized integer and we have to convert it let tmp = builder.bitcast(llforeign_arg, type_of::arg_type_of(ccx, rust_ty).ptr_to()); <del> builder.load(tmp) </del> <ins> let load = builder.load(tmp); llvm::LLVMSetAlignment(load, type_of::align_of(ccx, rust_ty)); load </ins> } else { builder.load(llforeign_arg) }

(_, "volatile_load") => { let tp_ty = *substs.types.get(FnSpace, 0); let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty); <del> from_arg_ty(bcx, VolatileLoad(bcx, ptr), tp_ty) </del> <ins> let load = VolatileLoad(bcx, ptr); unsafe { llvm::LLVMSetAlignment(load, type_of::align_of(ccx, tp_ty)); } from_arg_ty(bcx, load, tp_ty) </ins> }, (_, "volatile_store") => { let tp_ty = *substs.types.get(FnSpace, 0); let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty); let val = to_arg_ty(bcx, llargs[1], tp_ty); <del> VolatileStore(bcx, val, ptr); </del> <ins> let store = VolatileStore(bcx, val, ptr); unsafe { llvm::LLVMSetAlignment(store, type_of::align_of(ccx, tp_ty)); } </ins> C_nil(ccx) },