diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 7602956cb8e32..3a7fa040e4f8c 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -1682,20 +1682,70 @@ fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -// Important to get types for both lhs and rhs, because one might be _|_ -// and the other not. -fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - binop_expr: &hir::Expr, - binop_ty: Ty<'tcx>, - op: hir::BinOp, - lhs_t: Ty<'tcx>, - lhs: ValueRef, - rhs_t: Ty<'tcx>, - rhs: ValueRef) - -> DatumBlock<'blk, 'tcx, Expr> { - let _icx = push_ctxt("trans_eager_binop"); +fn trans_fat_ptr_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + binop_expr: &hir::Expr, + binop_ty: Ty<'tcx>, + op: hir::BinOp, + lhs: Datum<'tcx, Rvalue>, + rhs: Datum<'tcx, Rvalue>) + -> DatumBlock<'blk, 'tcx, Expr> +{ + let debug_loc = binop_expr.debug_loc(); + + let lhs_addr = Load(bcx, GEPi(bcx, lhs.val, &[0, abi::FAT_PTR_ADDR])); + let lhs_extra = Load(bcx, GEPi(bcx, lhs.val, &[0, abi::FAT_PTR_EXTRA])); + + let rhs_addr = Load(bcx, GEPi(bcx, rhs.val, &[0, abi::FAT_PTR_ADDR])); + let rhs_extra = Load(bcx, GEPi(bcx, rhs.val, &[0, abi::FAT_PTR_EXTRA])); + + let val = match op.node { + hir::BiEq => { + let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc); + let extra_eq = ICmp(bcx, llvm::IntEQ, lhs_extra, rhs_extra, debug_loc); + And(bcx, addr_eq, extra_eq, debug_loc) + } + hir::BiNe => { + let addr_eq = ICmp(bcx, llvm::IntNE, lhs_addr, rhs_addr, debug_loc); + let extra_eq = ICmp(bcx, llvm::IntNE, lhs_extra, rhs_extra, debug_loc); + Or(bcx, addr_eq, extra_eq, debug_loc) + } + hir::BiLe | hir::BiLt | hir::BiGe | hir::BiGt => { + // a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1) + let (op, strict_op) = match op.node { + hir::BiLt => (llvm::IntULT, llvm::IntULT), + hir::BiLe => (llvm::IntULE, llvm::IntULT), + hir::BiGt => (llvm::IntUGT, llvm::IntUGT), + hir::BiGe => (llvm::IntUGE, llvm::IntUGT), + _ => unreachable!() + }; + + let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc); + let extra_op = ICmp(bcx, op, lhs_extra, rhs_extra, debug_loc); + let addr_eq_extra_op = And(bcx, addr_eq, extra_op, debug_loc); + + let addr_strict = ICmp(bcx, strict_op, lhs_addr, rhs_addr, debug_loc); + Or(bcx, addr_strict, addr_eq_extra_op, debug_loc) + } + _ => { + bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop"); + } + }; + + immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock() +} + +fn trans_scalar_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + binop_expr: &hir::Expr, + binop_ty: Ty<'tcx>, + op: hir::BinOp, + lhs: Datum<'tcx, Rvalue>, + rhs: Datum<'tcx, Rvalue>) + -> DatumBlock<'blk, 'tcx, Expr> +{ + let _icx = push_ctxt("trans_scalar_binop"); let tcx = bcx.tcx(); + let lhs_t = lhs.ty; assert!(!lhs_t.is_simd()); let is_float = lhs_t.is_fp(); let is_signed = lhs_t.is_signed(); @@ -1704,6 +1754,8 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let binop_debug_loc = binop_expr.debug_loc(); let mut bcx = bcx; + let lhs = lhs.to_llscalarish(bcx); + let rhs = rhs.to_llscalarish(bcx); let val = match op.node { hir::BiAdd => { if is_float { @@ -1745,7 +1797,7 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, op, lhs, rhs, - rhs_t); + lhs_t); if is_signed { SDiv(bcx, lhs, rhs, binop_debug_loc) } else { @@ -1796,7 +1848,7 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Only zero-check integers; fp %0 is NaN bcx = base::fail_if_zero_or_overflows(bcx, expr_info(binop_expr), - op, lhs, rhs, rhs_t); + op, lhs, rhs, lhs_t); if is_signed { SRem(bcx, lhs, rhs, binop_debug_loc) } else { @@ -1896,23 +1948,26 @@ fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } _ => { let mut bcx = bcx; - let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs)); - let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs)); let binop_ty = expr_ty(bcx, expr); - debug!("trans_binary (expr {}): lhs_datum={}", - expr.id, - lhs_datum.to_string(ccx)); - let lhs_ty = lhs_datum.ty; - let lhs = lhs_datum.to_llscalarish(bcx); - - debug!("trans_binary (expr {}): rhs_datum={}", - expr.id, - rhs_datum.to_string(ccx)); - let rhs_ty = rhs_datum.ty; - let rhs = rhs_datum.to_llscalarish(bcx); - trans_eager_binop(bcx, expr, binop_ty, op, - lhs_ty, lhs, rhs_ty, rhs) + let lhs = unpack_datum!(bcx, trans(bcx, lhs)); + let lhs = unpack_datum!(bcx, lhs.to_rvalue_datum(bcx, "binop_lhs")); + debug!("trans_binary (expr {}): lhs={}", + expr.id, lhs.to_string(ccx)); + let rhs = unpack_datum!(bcx, trans(bcx, rhs)); + let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "binop_rhs")); + debug!("trans_binary (expr {}): rhs={}", + expr.id, rhs.to_string(ccx)); + + if type_is_fat_ptr(ccx.tcx(), lhs.ty) { + assert!(type_is_fat_ptr(ccx.tcx(), rhs.ty), + "built-in binary operators on fat pointers are homogeneous"); + trans_fat_ptr_binop(bcx, expr, binop_ty, op, lhs, rhs) + } else { + assert!(!type_is_fat_ptr(ccx.tcx(), rhs.ty), + "built-in binary operators on fat pointers are homogeneous"); + trans_scalar_binop(bcx, expr, binop_ty, op, lhs, rhs) + } } } } @@ -2123,21 +2178,19 @@ fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, assert!(!bcx.tcx().is_method_call(expr.id)); // Evaluate LHS (destination), which should be an lvalue - let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op")); - assert!(!bcx.fcx.type_needs_drop(dst_datum.ty)); - let dst_ty = dst_datum.ty; - let dst = load_ty(bcx, dst_datum.val, dst_datum.ty); + let dst = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op")); + assert!(!bcx.fcx.type_needs_drop(dst.ty)); + let lhs = load_ty(bcx, dst.val, dst.ty); + let lhs = immediate_rvalue(lhs, dst.ty); - // Evaluate RHS - let rhs_datum = unpack_datum!(bcx, trans(bcx, &*src)); - let rhs_ty = rhs_datum.ty; - let rhs = rhs_datum.to_llscalarish(bcx); + // Evaluate RHS - FIXME(#28160) this sucks + let rhs = unpack_datum!(bcx, trans(bcx, &*src)); + let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "assign_op_rhs")); // Perform computation and store the result let result_datum = unpack_datum!( - bcx, trans_eager_binop(bcx, expr, dst_datum.ty, op, - dst_ty, dst, rhs_ty, rhs)); - return result_datum.store_to(bcx, dst_datum.val); + bcx, trans_scalar_binop(bcx, expr, dst.ty, op, lhs, rhs)); + return result_datum.store_to(bcx, dst.val); } fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, diff --git a/src/test/run-pass/issue-27054-primitive-binary-ops.rs b/src/test/run-pass/issue-27054-primitive-binary-ops.rs new file mode 100644 index 0000000000000..a97a49a1a4a00 --- /dev/null +++ b/src/test/run-pass/issue-27054-primitive-binary-ops.rs @@ -0,0 +1,14 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let x = &mut 1; + assert_eq!(*x + { *x=2; 1 }, 2); +} diff --git a/src/test/run-pass/raw-fat-ptr.rs b/src/test/run-pass/raw-fat-ptr.rs new file mode 100644 index 0000000000000..b4572f4577133 --- /dev/null +++ b/src/test/run-pass/raw-fat-ptr.rs @@ -0,0 +1,127 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// check raw fat pointer ops + +use std::mem; + +fn assert_inorder(a: &[T]) { + for i in 0..a.len() { + for j in 0..a.len() { + if i < j { + assert!(a[i] < a[j]); + assert!(a[i] <= a[j]); + assert!(!(a[i] == a[j])); + assert!(a[i] != a[j]); + assert!(!(a[i] >= a[j])); + assert!(!(a[i] > a[j])); + } else if i == j { + assert!(!(a[i] < a[j])); + assert!(a[i] <= a[j]); + assert!(a[i] == a[j]); + assert!(!(a[i] != a[j])); + assert!(a[i] >= a[j]); + assert!(!(a[i] > a[j])); + } else { + assert!(!(a[i] < a[j])); + assert!(!(a[i] <= a[j])); + assert!(!(a[i] == a[j])); + assert!(a[i] != a[j]); + assert!(a[i] >= a[j]); + assert!(a[i] > a[j]); + } + } + } +} + +trait Foo { fn foo(&self) -> usize; } +impl Foo for T { + fn foo(&self) -> usize { + mem::size_of::() + } +} + +struct S(u32, T); + +fn main() { + let mut array = [0,1,2,3,4]; + let mut array2 = [5,6,7,8,9]; + + // fat ptr comparison: addr then extra + + // check ordering for arrays + let mut ptrs: Vec<*const [u8]> = vec![ + &array[0..0], &array[0..1], &array, &array[1..] + ]; + + let array_addr = &array as *const [u8] as *const u8 as usize; + let array2_addr = &array2 as *const [u8] as *const u8 as usize; + if array2_addr < array_addr { + ptrs.insert(0, &array2); + } else { + ptrs.push(&array2); + } + assert_inorder(&ptrs); + + // check ordering for mut arrays + let mut ptrs: Vec<*mut [u8]> = vec![ + &mut array[0..0], &mut array[0..1], &mut array, &mut array[1..] + ]; + + let array_addr = &mut array as *mut [u8] as *mut u8 as usize; + let array2_addr = &mut array2 as *mut [u8] as *mut u8 as usize; + if array2_addr < array_addr { + ptrs.insert(0, &mut array2); + } else { + ptrs.push(&mut array2); + } + assert_inorder(&ptrs); + + let mut u8_ = (0u8, 1u8); + let mut u32_ = (4u32, 5u32); + + // check ordering for ptrs + let buf: &mut [*const Foo] = &mut [ + &u8_, &u8_.0, + &u32_, &u32_.0, + ]; + buf.sort_by(|u,v| { + let u : [*const (); 2] = unsafe { mem::transmute(*u) }; + let v : [*const (); 2] = unsafe { mem::transmute(*v) }; + u.cmp(&v) + }); + assert_inorder(buf); + + // check ordering for mut ptrs + let buf: &mut [*mut Foo] = &mut [ + &mut u8_, &mut u8_.0, + &mut u32_, &mut u32_.0, + ]; + buf.sort_by(|u,v| { + let u : [*const (); 2] = unsafe { mem::transmute(*u) }; + let v : [*const (); 2] = unsafe { mem::transmute(*v) }; + u.cmp(&v) + }); + assert_inorder(buf); + + // check ordering for structs containing arrays + let ss: (S<[u8; 2]>, + S<[u8; 3]>, + S<[u8; 2]>) = ( + S(7, [8, 9]), + S(10, [11, 12, 13]), + S(4, [5, 6]) + ); + assert_inorder(&[ + &ss.0 as *const S<[u8]>, + &ss.1 as *const S<[u8]>, + &ss.2 as *const S<[u8]> + ]); +}