Skip to content

Commit 4689242

Browse files
authored
(c2rust-analyze) Cleanup/simplify visit_cast (extracted from #883) (#900)
This cleans up and simplifies some of the code from #883 in preparation for the string cast PRs, #739 and #741. It extracts things into a separate `visit_cast` method, simplifies a few things, and clarifies exactly which `Ty`s and `LTy`s are from and to in a cast. This makes it easier to understand and read, and makes it simpler to rebase #739 onto it.
2 parents 8731279 + df6a469 commit 4689242

File tree

1 file changed

+48
-55
lines changed

1 file changed

+48
-55
lines changed

c2rust-analyze/src/dataflow/type_check.rs

Lines changed: 48 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::DataflowConstraints;
22
use crate::c_void_casts::CVoidCastDirection;
33
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};
55
use assert_matches::assert_matches;
66
use rustc_hir::def_id::DefId;
77
use rustc_middle::mir::{
@@ -42,7 +42,7 @@ struct TypeChecker<'tcx, 'a> {
4242
equiv_constraints: Vec<(PointerId, PointerId)>,
4343
}
4444

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 {
4646
// TODO: implement
4747
true
4848
}
@@ -101,6 +101,49 @@ impl<'tcx> TypeChecker<'tcx, '_> {
101101
}
102102
}
103103

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+
104147
pub fn visit_rvalue(&mut self, rv: &Rvalue<'tcx>, rvalue_lty: LTy<'tcx>) {
105148
let rv_desc = describe_rvalue(rv);
106149
eprintln!("visit_rvalue({rv:?}), desc = {rv_desc:?}");
@@ -148,59 +191,9 @@ impl<'tcx> TypeChecker<'tcx, '_> {
148191
Rvalue::Len(pl) => {
149192
self.visit_place(pl, Mutability::Not);
150193
}
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);
204197
}
205198
Rvalue::BinaryOp(BinOp::Offset, _) => todo!("visit_rvalue BinOp::Offset"),
206199
Rvalue::BinaryOp(_, ref ops) => {

0 commit comments

Comments
 (0)