about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOlivier Goffart <ogoffart@woboq.com>2018-11-20 12:14:53 +0100
committerOlivier Goffart <ogoffart@woboq.com>2018-11-20 12:20:05 +0100
commit86d41350c790502d3a1227bab3433ac7472ccb4c (patch)
treefc9cdeb68f765fcf6ff051dcab7a925eddf17893
parent046e054a995c7b293e26968774ff88b38661cd3c (diff)
Fix invalid bitcast taking bool out of a union represented as a scalar
As reported in https://github.com/rust-lang/rust/pull/54668#issuecomment-440186476
-rw-r--r--src/librustc_codegen_ssa/mir/operand.rs14
-rw-r--r--src/test/codegen/union-abi.rs6
2 files changed, 17 insertions, 3 deletions
diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs
index d574d89d67e..859047f5491 100644
--- a/src/librustc_codegen_ssa/mir/operand.rs
+++ b/src/librustc_codegen_ssa/mir/operand.rs
@@ -243,14 +243,22 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
             _ => bug!("OperandRef::extract_field({:?}): not applicable", self)
         };
 
+        let bitcast = |bx: &mut Bx, val, ty| {
+            if ty == bx.cx().type_i1() {
+                bx.trunc(val, ty)
+            } else {
+                bx.bitcast(val, ty)
+            }
+        };
+
         // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
         match val {
             OperandValue::Immediate(ref mut llval) => {
-                *llval = bx.bitcast(*llval, bx.cx().immediate_backend_type(field));
+                *llval = bitcast(bx, *llval, bx.cx().immediate_backend_type(field));
             }
             OperandValue::Pair(ref mut a, ref mut b) => {
-                *a = bx.bitcast(*a, bx.cx().scalar_pair_element_backend_type(field, 0, true));
-                *b = bx.bitcast(*b, bx.cx().scalar_pair_element_backend_type(field, 1, true));
+                *a = bitcast(bx, *a, bx.cx().scalar_pair_element_backend_type(field, 0, true));
+                *b = bitcast(bx, *b, bx.cx().scalar_pair_element_backend_type(field, 1, true));
             }
             OperandValue::Ref(..) => bug!()
         }
diff --git a/src/test/codegen/union-abi.rs b/src/test/codegen/union-abi.rs
index 786968128ec..5a6df52502e 100644
--- a/src/test/codegen/union-abi.rs
+++ b/src/test/codegen/union-abi.rs
@@ -78,3 +78,9 @@ pub union CUnionU128{a:u128}
 #[no_mangle]
 pub fn test_CUnionU128(_: CUnionU128) { loop {} }
 
+pub union UnionBool { b:bool }
+// CHECK: define zeroext i1 @test_UnionBool(i8 %b)
+#[no_mangle]
+pub fn test_UnionBool(b: UnionBool) -> bool { unsafe { b.b }  }
+// CHECK: %0 = trunc i8 %b to i1
+