|
1 | 1 | use super::DataflowConstraints;
|
2 | 2 | use crate::c_void_casts::CVoidCastDirection;
|
3 | 3 | use crate::context::{AnalysisCtxt, LTy, PermissionSet, PointerId};
|
4 |
| -use crate::util::{self, describe_rvalue, ty_callee, Callee, RvalueDesc}; |
| 4 | +use crate::util::{describe_rvalue, is_null_const, ty_callee, Callee, RvalueDesc}; |
5 | 5 | use assert_matches::assert_matches;
|
6 | 6 | use rustc_hir::def_id::DefId;
|
7 | 7 | use rustc_middle::mir::{
|
@@ -42,7 +42,7 @@ struct TypeChecker<'tcx, 'a> {
|
42 | 42 | equiv_constraints: Vec<(PointerId, PointerId)>,
|
43 | 43 | }
|
44 | 44 |
|
45 |
| -fn is_castable_to<'tcx>(_t: LTy<'tcx>, _u: LTy<'tcx>) -> bool { |
| 45 | +fn is_castable_to<'tcx>(_from_lty: LTy<'tcx>, _to_lty: LTy<'tcx>) -> bool { |
46 | 46 | // TODO: implement
|
47 | 47 | true
|
48 | 48 | }
|
@@ -101,6 +101,49 @@ impl<'tcx> TypeChecker<'tcx, '_> {
|
101 | 101 | }
|
102 | 102 | }
|
103 | 103 |
|
| 104 | + fn visit_cast(&mut self, cast_kind: CastKind, op: &Operand<'tcx>, to_lty: LTy<'tcx>) { |
| 105 | + let to_ty = to_lty.ty; |
| 106 | + let from_lty = self.acx.type_of(op); |
| 107 | + |
| 108 | + match cast_kind { |
| 109 | + CastKind::PointerFromExposedAddress => { |
| 110 | + // We support only one case here, which is the case of null pointers |
| 111 | + // constructed via casts such as `0 as *const T` |
| 112 | + if !op.constant().copied().map(is_null_const).unwrap_or(false) { |
| 113 | + panic!("Creating non-null pointers from exposed addresses not supported"); |
| 114 | + } |
| 115 | + } |
| 116 | + CastKind::Pointer(PointerCast::Unsize) => { |
| 117 | + let pointee_to_ty = to_ty |
| 118 | + .builtin_deref(true) |
| 119 | + .unwrap_or_else(|| panic!("unsize cast has non-pointer output {:?}?", to_ty)) |
| 120 | + .ty; |
| 121 | + |
| 122 | + assert_matches!(from_lty.kind(), TyKind::Ref(..) | TyKind::RawPtr(..)); |
| 123 | + let pointee_from_lty = assert_matches!(from_lty.args, [lty] => lty); |
| 124 | + |
| 125 | + let elem_to_ty = assert_matches!(pointee_to_ty.kind(), &TyKind::Slice(ty) => ty); |
| 126 | + assert!(matches!(pointee_from_lty.kind(), TyKind::Array(..))); |
| 127 | + let elem_from_lty = assert_matches!(pointee_from_lty.args, [lty] => lty); |
| 128 | + assert_eq!(elem_from_lty.ty, elem_to_ty); |
| 129 | + assert_eq!(pointee_from_lty.label, PointerId::NONE); |
| 130 | + self.do_assign_pointer_ids(to_lty.label, from_lty.label); |
| 131 | + } |
| 132 | + CastKind::Pointer(..) => { |
| 133 | + // The source and target types are both pointers, and they have identical pointee types. |
| 134 | + // TODO: remove or move check to `is_castable_to` |
| 135 | + assert!(from_lty.args[0].ty == to_lty.args[0].ty); |
| 136 | + assert!(is_castable_to(from_lty, to_lty)); |
| 137 | + } |
| 138 | + _ => { |
| 139 | + // A cast such as `T as U` |
| 140 | + assert!(is_castable_to(from_lty, to_lty)); |
| 141 | + } |
| 142 | + } |
| 143 | + |
| 144 | + self.visit_operand(op) |
| 145 | + } |
| 146 | + |
104 | 147 | pub fn visit_rvalue(&mut self, rv: &Rvalue<'tcx>, rvalue_lty: LTy<'tcx>) {
|
105 | 148 | let rv_desc = describe_rvalue(rv);
|
106 | 149 | eprintln!("visit_rvalue({rv:?}), desc = {rv_desc:?}");
|
@@ -148,59 +191,9 @@ impl<'tcx> TypeChecker<'tcx, '_> {
|
148 | 191 | Rvalue::Len(pl) => {
|
149 | 192 | self.visit_place(pl, Mutability::Not);
|
150 | 193 | }
|
151 |
| - Rvalue::Cast(CastKind::PointerFromExposedAddress, ref op, _) => { |
152 |
| - // We support only one case here, which is the case of null pointers |
153 |
| - // constructed via casts such as `0 as *const T` |
154 |
| - if let Some(true) = op.constant().cloned().map(util::is_null_const) { |
155 |
| - self.visit_operand(op) |
156 |
| - } else { |
157 |
| - panic!("Creating non-null pointers from exposed addresses not supported"); |
158 |
| - } |
159 |
| - } |
160 |
| - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), ref op, ty) => { |
161 |
| - let pointee_ty = match *ty.kind() { |
162 |
| - TyKind::Ref(_, ty, _) => ty, |
163 |
| - TyKind::RawPtr(tm) => tm.ty, |
164 |
| - _ => unreachable!("unsize cast has non-pointer output {:?}?", ty), |
165 |
| - }; |
166 |
| - |
167 |
| - let op_lty = self.acx.type_of(op); |
168 |
| - assert_matches!(op_lty.kind(), TyKind::Ref(..) | TyKind::RawPtr(..)); |
169 |
| - |
170 |
| - let op_pointee_lty = assert_matches!(op_lty.args, [op_pointee_lty] => { |
171 |
| - op_pointee_lty |
172 |
| - }); |
173 |
| - |
174 |
| - assert_matches!(pointee_ty.kind(), TyKind::Slice(..)); |
175 |
| - if let TyKind::Slice(elem_ty) = *pointee_ty.kind() { |
176 |
| - assert!(matches!(op_pointee_lty.kind(), TyKind::Array(..))); |
177 |
| - let elem_lty = assert_matches!(op_pointee_lty.args, [elem_lty] => { |
178 |
| - elem_lty |
179 |
| - }); |
180 |
| - assert_eq!(elem_lty.ty, elem_ty); |
181 |
| - assert_eq!(op_pointee_lty.label, PointerId::NONE); |
182 |
| - self.do_assign_pointer_ids(rvalue_lty.label, op_lty.label); |
183 |
| - } |
184 |
| - |
185 |
| - self.visit_operand(op) |
186 |
| - } |
187 |
| - Rvalue::Cast(CastKind::Pointer(..), ref op, _) => { |
188 |
| - let op_lty = self.acx.type_of(op); |
189 |
| - |
190 |
| - // The source and target types are both pointers, and they have identical |
191 |
| - // pointee types. |
192 |
| - // TODO: remove or move check to `is_castable_to` |
193 |
| - assert!(op_lty.args[0].ty == rvalue_lty.args[0].ty); |
194 |
| - |
195 |
| - assert!(is_castable_to(op_lty, rvalue_lty)); |
196 |
| - self.visit_operand(op) |
197 |
| - } |
198 |
| - Rvalue::Cast(_cast_kind, ref op, _) => { |
199 |
| - // A cast such as `T as U` |
200 |
| - let casted_from = self.acx.type_of(op); |
201 |
| - let casted_to = rvalue_lty; |
202 |
| - assert!(is_castable_to(casted_from, casted_to)); |
203 |
| - self.visit_operand(op) |
| 194 | + Rvalue::Cast(cast_kind, ref op, ty) => { |
| 195 | + assert_eq!(ty, rvalue_lty.ty); |
| 196 | + self.visit_cast(cast_kind, op, rvalue_lty); |
204 | 197 | }
|
205 | 198 | Rvalue::BinaryOp(BinOp::Offset, _) => todo!("visit_rvalue BinOp::Offset"),
|
206 | 199 | Rvalue::BinaryOp(_, ref ops) => {
|
|
0 commit comments