|
2 | 2 | //!
|
3 | 3 | //! Currently, this pass only propagates scalar values.
|
4 | 4 |
|
5 |
| -use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable}; |
| 5 | +use rustc_const_eval::interpret::{ |
| 6 | + ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Pointer, PointerArithmetic, Projectable, |
| 7 | +}; |
6 | 8 | use rustc_data_structures::fx::FxHashMap;
|
7 | 9 | use rustc_hir::def::DefKind;
|
8 | 10 | use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar};
|
@@ -935,12 +937,64 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
|
935 | 937 | }
|
936 | 938 |
|
937 | 939 | fn binary_ptr_op(
|
938 |
| - _ecx: &InterpCx<'mir, 'tcx, Self>, |
939 |
| - _bin_op: BinOp, |
940 |
| - _left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, |
941 |
| - _right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, |
| 940 | + ecx: &InterpCx<'mir, 'tcx, Self>, |
| 941 | + bin_op: BinOp, |
| 942 | + left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, |
| 943 | + right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, |
942 | 944 | ) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> {
|
943 |
| - throw_machine_stop_str!("can't do pointer arithmetic"); |
| 945 | + use rustc_middle::mir::BinOp::*; |
| 946 | + Ok(match bin_op { |
| 947 | + Eq | Ne | Lt | Le | Gt | Ge => { |
| 948 | + assert_eq!(left.layout.abi, right.layout.abi); // types an differ, e.g. fn ptrs with different `for` |
| 949 | + let size = ecx.pointer_size(); |
| 950 | + // Just compare the bits. ScalarPairs are compared lexicographically. |
| 951 | + // We thus always compare pairs and simply fill scalars up with 0. |
| 952 | + let left = match **left { |
| 953 | + Immediate::Scalar(l) => (l.to_bits(size)?, 0), |
| 954 | + Immediate::ScalarPair(l1, l2) => (l1.to_bits(size)?, l2.to_bits(size)?), |
| 955 | + Immediate::Uninit => panic!("we should never see uninit data here"), |
| 956 | + }; |
| 957 | + let right = match **right { |
| 958 | + Immediate::Scalar(r) => (r.to_bits(size)?, 0), |
| 959 | + Immediate::ScalarPair(r1, r2) => (r1.to_bits(size)?, r2.to_bits(size)?), |
| 960 | + Immediate::Uninit => panic!("we should never see uninit data here"), |
| 961 | + }; |
| 962 | + let res = match bin_op { |
| 963 | + Eq => left == right, |
| 964 | + Ne => left != right, |
| 965 | + Lt => left < right, |
| 966 | + Le => left <= right, |
| 967 | + Gt => left > right, |
| 968 | + Ge => left >= right, |
| 969 | + _ => bug!(), |
| 970 | + }; |
| 971 | + (ImmTy::from_bool(res, *ecx.tcx), false) |
| 972 | + } |
| 973 | + |
| 974 | + // Some more operations are possible with atomics. |
| 975 | + // The return value always has the provenance of the *left* operand. |
| 976 | + Add | Sub | BitOr | BitAnd | BitXor => { |
| 977 | + assert!(left.layout.ty.is_unsafe_ptr()); |
| 978 | + assert!(right.layout.ty.is_unsafe_ptr()); |
| 979 | + let ptr = left.to_scalar().to_pointer(ecx)?; |
| 980 | + // We do the actual operation with usize-typed scalars. |
| 981 | + let usize_layout = ecx.layout_of(ecx.tcx.types.usize).unwrap(); |
| 982 | + let left = ImmTy::from_uint(ptr.addr().bytes(), usize_layout); |
| 983 | + let right = ImmTy::from_uint(right.to_scalar().to_target_usize(ecx)?, usize_layout); |
| 984 | + let (result, overflowing) = ecx.overflowing_binary_op(bin_op, &left, &right)?; |
| 985 | + // Construct a new pointer with the provenance of `ptr` (the LHS). |
| 986 | + let result_ptr = Pointer::new( |
| 987 | + ptr.provenance, |
| 988 | + Size::from_bytes(result.to_scalar().to_target_usize(ecx)?), |
| 989 | + ); |
| 990 | + ( |
| 991 | + ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, ecx), left.layout), |
| 992 | + overflowing, |
| 993 | + ) |
| 994 | + } |
| 995 | + |
| 996 | + _ => span_bug!(ecx.cur_span(), "Invalid operator on pointers: {:?}", bin_op), |
| 997 | + }) |
944 | 998 | }
|
945 | 999 |
|
946 | 1000 | fn expose_ptr(
|
|
0 commit comments