Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions c2rust-analyze/src/analyze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ fn label_string_literals<'tcx>(
}

fn label_rvalue_tys<'tcx>(acx: &mut AnalysisCtxt<'_, 'tcx>, mir: &Body<'tcx>) {
for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
for (bb, bb_data) in mir.basic_blocks.iter_enumerated() {
for (i, stmt) in bb_data.statements.iter().enumerate() {
let (_, rv) = match &stmt.kind {
StatementKind::Assign(x) => &**x,
Expand Down Expand Up @@ -214,10 +214,12 @@ fn label_rvalue_tys<'tcx>(acx: &mut AnalysisCtxt<'_, 'tcx>, mir: &Body<'tcx>) {
Rvalue::Cast(_, _, ty) => {
acx.assign_pointer_ids_with_info(*ty, PointerInfo::ANNOTATED)
}
Rvalue::Use(Operand::Constant(c)) => match label_string_literals(acx, c, loc) {
Some(lty) => lty,
None => continue,
},
Rvalue::Use(Operand::Constant(c)) => {
match label_string_literals(acx, c.as_ref(), loc) {
Some(lty) => lty,
None => continue,
}
}
_ => continue,
};

Expand All @@ -242,7 +244,7 @@ fn update_pointer_info<'tcx>(acx: &mut AnalysisCtxt<'_, 'tcx>, mir: &Body<'tcx>)
let mut write_count = HashMap::with_capacity(mir.local_decls.len());
let mut rhs_is_ref = HashSet::new();

for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
for (bb, bb_data) in mir.basic_blocks.iter_enumerated() {
for (i, stmt) in bb_data.statements.iter().enumerate() {
let (pl, rv) = match &stmt.kind {
StatementKind::Assign(x) => &**x,
Expand Down Expand Up @@ -296,7 +298,7 @@ fn foreign_mentioned_tys(tcx: TyCtxt) -> HashSet<DefId> {
for ty in tcx
.hir_crate_items(())
.foreign_items()
.map(|item| item.def_id.to_def_id())
.map(|item| item.owner_id.def_id.to_def_id())
.filter_map(|did| match tcx.def_kind(did) {
DefKind::Fn | DefKind::AssocFn => Some(tcx.mk_fn_ptr(tcx.fn_sig(did))),
DefKind::Static(_) => Some(tcx.type_of(did)),
Expand Down Expand Up @@ -1708,7 +1710,7 @@ fn assign_pointer_ids<'tcx>(
for did in tcx
.hir_crate_items(())
.foreign_items()
.map(|item| item.def_id.to_def_id())
.map(|item| item.owner_id.def_id.to_def_id())
.filter(|did| matches!(tcx.def_kind(did), DefKind::Fn | DefKind::AssocFn))
{
let sig = tcx.erase_late_bound_regions(tcx.fn_sig(did));
Expand Down
2 changes: 1 addition & 1 deletion c2rust-analyze/src/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ fn run_polonius<'tcx>(
//pretty::write_mir_fn(tcx, mir, &mut |_, _| Ok(()), &mut std::io::stdout()).unwrap();

// Populate `cfg_edge`
for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
for (bb, bb_data) in mir.basic_blocks.iter_enumerated() {
debug!("{:?}:", bb);

for idx in 0..bb_data.statements.len() {
Expand Down
2 changes: 1 addition & 1 deletion c2rust-analyze/src/borrowck/type_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ pub fn visit_body<'tcx>(
static_origin,
};

for (block, bb_data) in mir.basic_blocks().iter_enumerated() {
for (block, bb_data) in mir.basic_blocks.iter_enumerated() {
for (idx, stmt) in bb_data.statements.iter().enumerate() {
let loc = Location {
block,
Expand Down
17 changes: 13 additions & 4 deletions c2rust-analyze/src/dataflow/type_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ impl<'tcx> TypeChecker<'tcx, '_> {
// They don't involve arbitrary raw ptr to raw ptr casts
// ([PointerCast::MutToConstPointer`] doesn't allow changing types),
// which we need to check for safe transmutability,
// and which are (currently) covered in [`CastKind::Misc`].
// and which are covered by ptr-to-ptr cast kinds below.
// That's why there's a `match` here that does nothing;
// it ensures if [`PointerCast`] is changed in a future `rustc` version,
// this won't compile until we've checked that this reasoning is still accurate.
Expand All @@ -192,7 +192,7 @@ impl<'tcx> TypeChecker<'tcx, '_> {
self.do_assign_pointer_ids(to_lty.label, from_lty.label)
// TODO add other dataflow constraints
}
CastKind::Misc => {
CastKind::PtrToPtr | CastKind::FnPtrToPtr => {
match is_transmutable_ptr_cast(from_ty, to_ty) {
Some(true) => {
self.do_assign_pointer_ids(to_lty.label, from_lty.label);
Expand All @@ -206,6 +206,11 @@ impl<'tcx> TypeChecker<'tcx, '_> {
None => {} // not a ptr cast (no dataflow constraints needed); let rustc typeck this
};
}
CastKind::DynStar
| CastKind::IntToInt
| CastKind::FloatToInt
| CastKind::FloatToFloat
| CastKind::IntToFloat => {}
}

self.visit_operand(op)
Expand Down Expand Up @@ -729,7 +734,11 @@ impl<'tcx> TypeChecker<'tcx, '_> {
op = rhs_op;
continue;
}
Rvalue::Cast(CastKind::Misc, ref rhs_op, _) => {
Rvalue::Cast(
CastKind::PtrToPtr | CastKind::FnPtrToPtr,
ref rhs_op,
_,
) => {
// Allow casting from `usize` to `size_t`, for example.
//
// Note: we currently don't check that the cast preserves the
Expand Down Expand Up @@ -761,7 +770,7 @@ impl<'tcx> TypeChecker<'tcx, '_> {
}

fn visit_common<'tcx>(tc: &mut TypeChecker<'tcx, '_>, mir: &Body<'tcx>) {
for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
for (bb, bb_data) in mir.basic_blocks.iter_enumerated() {
for (i, stmt) in bb_data.statements.iter().enumerate() {
tc.visit_statement(
stmt,
Expand Down
6 changes: 1 addition & 5 deletions c2rust-analyze/src/last_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,7 @@ impl ActionsBuilder {
StatementKind::Retag(..) => panic!("unexpected StatementKind::Retag"),
StatementKind::AscribeUserType(..) => {}
StatementKind::Coverage(..) => {}
StatementKind::CopyNonOverlapping(ref cno) => {
self.push_operand(&cno.src, loc, WhichPlace::Operand(0));
self.push_operand(&cno.dst, loc, WhichPlace::Operand(0));
self.push_operand(&cno.count, loc, WhichPlace::Operand(0));
}
StatementKind::Intrinsic(..) => {}
StatementKind::Nop => {}
}
}
Expand Down
2 changes: 1 addition & 1 deletion c2rust-analyze/src/pointee_type/type_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ pub fn visit<'tcx>(
vars,
};

for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
for (bb, bb_data) in mir.basic_blocks.iter_enumerated() {
for (i, stmt) in bb_data.statements.iter().enumerate() {
tc.visit_statement(
stmt,
Expand Down
2 changes: 1 addition & 1 deletion c2rust-analyze/src/recent_writes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ fn calc_recent_writes(mir: &Body) -> RecentWrites {
/// Initial phase of `calc_recent_writes`: scan each block and record any writes and any address-of
/// operations found within that block.
fn scan_blocks(mir: &Body, rw: &mut RecentWrites) {
for (block, bb_data) in mir.basic_blocks().iter_enumerated() {
for (block, bb_data) in mir.basic_blocks.iter_enumerated() {
for (statement_index, stmt) in bb_data.statements.iter().enumerate() {
let loc = Location {
block,
Expand Down
9 changes: 8 additions & 1 deletion c2rust-analyze/src/rewrite/expr/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,13 @@ impl<'tcx> ConvertVisitor<'tcx> {
(&Box(e), 0) => e,
(&Array(es), i) => &es[i],
(&Call(_, args), i) => &args[i],
(&MethodCall(_, args, _), i) => &args[i],
(&MethodCall(_, recv, args, _), i) => {
if i == 0 {
recv
} else {
&args[i - 1]
}
}
(&Tup(es), i) => &es[i],
(&Binary(_, x, _), 0) => x,
(&Binary(_, _, y), 1) => y,
Expand Down Expand Up @@ -728,6 +734,7 @@ fn apply_adjustment<'tcx>(
Rewrite::Cast(Box::new(rw), Box::new(ty_rw))
}
Adjust::Pointer(cast) => todo!("Adjust::Pointer({:?})", cast),
Adjust::DynStar => todo!("Adjust::DynStar"),
}
}

Expand Down
5 changes: 3 additions & 2 deletions c2rust-analyze/src/rewrite/expr/mir_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ impl<'a, 'tcx> ExprRewriteVisitor<'a, 'tcx> {
StatementKind::Retag(..) => {}
StatementKind::AscribeUserType(..) => {}
StatementKind::Coverage(..) => {}
StatementKind::CopyNonOverlapping(..) => todo!("statement {:?}", stmt),
StatementKind::Intrinsic(..) => todo!("statement {:?}", stmt),
StatementKind::Nop => {}
}
}
Expand Down Expand Up @@ -1268,6 +1268,7 @@ impl<'a, 'tcx> ExprRewriteVisitor<'a, 'tcx> {
});
}
PlaceElem::Downcast(_, _) => {}
PlaceElem::OpaqueCast(_) => {}
}
}

Expand Down Expand Up @@ -2089,7 +2090,7 @@ pub fn gen_mir_rewrites<'tcx>(

let mut v = ExprRewriteVisitor::new(acx, asn, pointee_types, last_use, &mut out, mir);

for (bb_id, bb) in mir.basic_blocks().iter_enumerated() {
for (bb_id, bb) in mir.basic_blocks.iter_enumerated() {
for (i, stmt) in bb.statements.iter().enumerate() {
let loc = Location {
block: bb_id,
Expand Down
2 changes: 1 addition & 1 deletion c2rust-analyze/src/rewrite/expr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ fn debug_print_unlower_map<'tcx>(
};

eprintln!("unlowering for {:?}:", mir.source);
for (bb_id, bb) in mir.basic_blocks().iter_enumerated() {
for (bb_id, bb) in mir.basic_blocks.iter_enumerated() {
eprintln!(" block {bb_id:?}:");
for (i, stmt) in bb.statements.iter().enumerate() {
let loc = Location {
Expand Down
19 changes: 13 additions & 6 deletions c2rust-analyze/src/rewrite/expr/unlower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ impl<'a, 'tcx> UnlowerVisitor<'a, 'tcx> {
return;
}

hir::ExprKind::Call(_, args) | hir::ExprKind::MethodCall(_, args, _) => {
hir::ExprKind::Call(_, _args) | hir::ExprKind::MethodCall(_, _, _args, _) => {
// Handle adjustments on the call's output first.
let (_mir_pl, mut cursor) = match self.make_visit_expr_cursor(&locs) {
Some(x @ (pl, _)) if is_var(pl) => x,
Expand Down Expand Up @@ -313,10 +313,17 @@ impl<'a, 'tcx> UnlowerVisitor<'a, 'tcx> {
self.finish_visit_expr_cursor(ex, cursor);

self.record(loc, &[SubLoc::Rvalue], ex);
for (i, (arg, mir_arg)) in args.iter().zip(mir_args).enumerate() {
let hir_args: Vec<&hir::Expr<'tcx>> = match ex.kind {
hir::ExprKind::Call(_, call_args) => call_args.iter().collect(),
hir::ExprKind::MethodCall(_, recv, call_args, _) => {
std::iter::once(recv).chain(call_args.iter()).collect()
}
_ => unreachable!(),
};
for (i, (arg, mir_arg)) in hir_args.iter().zip(mir_args).enumerate() {
let sub_loc = vec![SubLoc::Rvalue, SubLoc::CallArg(i)];
self.record_operand(loc, &sub_loc, arg, mir_arg);
self.visit_expr_operand(arg, loc, sub_loc, mir_arg, &[]);
self.record_operand(loc, &sub_loc, *arg, mir_arg);
self.visit_expr_operand(*arg, loc, sub_loc, mir_arg, &[]);
}

if !extra_locs.is_empty() {
Expand All @@ -326,7 +333,7 @@ impl<'a, 'tcx> UnlowerVisitor<'a, 'tcx> {
// of the child's statements can be processed together.
if matches!(ex.kind, hir::ExprKind::MethodCall(..)) {
self.append_extra_locations
.entry(args[0].hir_id)
.entry(hir_args[0].hir_id)
.or_insert_with(Vec::new)
.extend_from_slice(extra_locs);
} else {
Expand Down Expand Up @@ -1067,7 +1074,7 @@ fn filter_term(_term: &mir::Terminator) -> bool {
fn build_span_index(mir: &Body<'_>) -> SpanIndex<Location> {
debug!("building span index for {:?}:", mir.source);
let mut span_index_items = Vec::new();
for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
for (bb, bb_data) in mir.basic_blocks.iter_enumerated() {
for (i, stmt) in bb_data.statements.iter().enumerate() {
if !filter_stmt(stmt) {
continue;
Expand Down
8 changes: 5 additions & 3 deletions c2rust-analyze/src/rewrite/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::type_desc::{self, TypeDesc};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Expr, ExprKind, FnRetTy};
use rustc_hir::{Expr, ExprKind, FnRetTy, OwnerId};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{DefIdTree, TyCtxt, TypeckResults};
use rustc_span::Span;
Expand Down Expand Up @@ -91,7 +91,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ShimCallVisitor<'a, 'tcx> {
}
}

ExprKind::MethodCall(ps, _, _) => {
ExprKind::MethodCall(ps, _, _, _) => {
if let Some(def_id) = self.typeck_results.type_dependent_def_id(ex.hir_id) {
self.handle_def_mention(def_id, ps.ident.span);
}
Expand Down Expand Up @@ -190,7 +190,9 @@ pub fn gen_shim_definition_rewrite<'tcx>(
) -> (Span, Rewrite) {
let tcx = gacx.tcx;

let owner_node = tcx.hir().expect_owner(def_id.as_local().unwrap());
let owner_node = tcx.hir().expect_owner(OwnerId {
def_id: def_id.as_local().unwrap(),
});
let insert_span = owner_node.span().shrink_to_hi();

let fn_decl = owner_node.fn_decl().unwrap();
Expand Down
2 changes: 1 addition & 1 deletion c2rust-analyze/src/rewrite/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ fn hir_generic_ty_args<'tcx>(ty: &hir::Ty<'tcx>) -> Option<Vec<&'tcx hir::Ty<'tc
args.args
.iter()
.filter_map(|arg| match arg {
hir::GenericArg::Type(ty) => Some(ty),
hir::GenericArg::Type(ty) => Some(*ty),
_ => None,
})
.collect()
Expand Down
4 changes: 2 additions & 2 deletions c2rust-analyze/src/trivial.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use log::debug;
use rustc_middle::ty::{self, Binder, EarlyBinder, FnSig, GenSig, Subst, Ty, TyCtxt};
use rustc_middle::ty::{self, Binder, EarlyBinder, FnSig, GenSig, Ty, TyCtxt};

pub trait IsTrivial<'tcx> {
/// Something [`is_trivial`] if it has no effect on pointer permissions,
Expand Down Expand Up @@ -84,7 +84,7 @@ impl<'tcx> IsTrivial<'tcx> for Ty<'tcx> {
}

// don't know, as `dyn Trait` could be anything
ty::Dynamic(trait_ty, _reg) => {
ty::Dynamic(trait_ty, _reg, _) => {
debug!("unsure how to check `dyn Trait` for accessible pointers, so assuming non-trivial: ty = {self:?}, trait_ty = {trait_ty:?}");
false
}
Expand Down
13 changes: 9 additions & 4 deletions c2rust-analyze/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use rustc_middle::mir::{
Body, Constant, Field, Local, Mutability, Operand, PlaceElem, PlaceRef, ProjectionElem, Rvalue,
};
use rustc_middle::ty::{
self, AdtDef, DefIdTree, EarlyBinder, FnSig, GenericArg, List, Subst, SubstsRef, Ty, TyCtxt,
TyKind, UintTy,
self, AdtDef, DefIdTree, EarlyBinder, FnSig, GenericArg, List, SubstsRef, Ty, TyCtxt, TyKind,
UintTy,
};
use rustc_span::symbol::{sym, Symbol};
use rustc_type_ir::IntTy;
Expand Down Expand Up @@ -252,7 +252,11 @@ pub fn ty_callee<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Callee<'tcx> {
}
}

fn builtin_callee<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, substs: SubstsRef<'tcx>) -> Option<Callee> {
fn builtin_callee<'tcx>(
tcx: TyCtxt<'tcx>,
did: DefId,
substs: SubstsRef<'tcx>,
) -> Option<Callee<'tcx>> {
let name = tcx.item_name(did);

match name.as_str() {
Expand Down Expand Up @@ -434,6 +438,7 @@ pub fn lty_project<'tcx, L: Debug>(
}
ProjectionElem::Subslice { .. } => todo!("type_of Subslice"),
ProjectionElem::Downcast(..) => todo!("type_of Downcast"),
ProjectionElem::OpaqueCast(_) => lty,
}
}

Expand Down Expand Up @@ -576,7 +581,7 @@ pub fn has_test_attr(tcx: TyCtxt, ldid: LocalDefId, attr: TestAttr) -> bool {

for attr in tcx.get_attrs_unchecked(ldid.to_def_id()) {
let path = match attr.kind {
AttrKind::Normal(ref item, _) => &item.path,
AttrKind::Normal(ref item) => &item.item.path,
AttrKind::DocComment(..) => continue,
};
let (a, b) = match &path.segments[..] {
Expand Down
3 changes: 3 additions & 0 deletions c2rust-analyze/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ impl Analyze {
"--edition",
&crate_options.edition.to_string(),
])
// FileCheck tests assert against debug diagnostics from c2rust-analyze.
// Force a stable log level regardless of the outer test runner environment.
.env("RUST_LOG", "debug")
.stdout(output_stdout)
.stderr(output_stderr);
cmd.envs(args.env.iter().map(|EnvVar { var, value }| (var, value)));
Expand Down
2 changes: 1 addition & 1 deletion c2rust-analyze/tests/filecheck/aggregate1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ struct S<'a> {
pub fn aggregate() {
// CHECK-DAG: pseudo-assigning fields Label { origin: Some(Origin([[R_U32_ORIGIN:[0-9]+]])){{.*}}}#&'a u32{{.*}}= Label { origin: Some(Origin({{.*}})){{.*}}&u32
// CHECK-DAG: pseudo-assigning fields Label { origin: Some(Origin([[R_U32_ORIGIN:[0-9]+]])){{.*}}}#&'a u32{{.*}}= Label { origin: Some(Origin({{.*}})){{.*}}&u32
// CHECK-DAG: Aggregate literal label: Label{{.*}}origin_params: [('a, Origin([[R_U32_ORIGIN]])), ('h0, Origin({{.*}})]{{.*}}#S[]
// CHECK-DAG: Aggregate literal label: Label{{.*}}#S<'_>[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how much we care about these.

let x = 0;
let ref_x = &x;
let i = S {
Expand Down
8 changes: 4 additions & 4 deletions c2rust-analyze/tests/filecheck/trivial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,19 @@ pub fn main() {
f!(i32); // CHECK: fn(i32) {main::f} is trivial: true
f!(usize); // CHECK: fn(usize) {main::f} is trivial: true
f!(f64); // CHECK: fn(f64) {main::f} is trivial: true
f!(&str); // CHECK: for<'r> fn(&'r str) {main::f} is trivial: true
f!(&str); // CHECK: for<'{{[a-z0-9]+}}> fn(&'{{[a-z0-9]+}} str) {main::f} is trivial: true

f!((&str, i32)); // CHECK: for<'r> fn((&'r str, i32)) {main::f} is trivial: true
f!((&str, i32)); // CHECK: for<'{{[a-z0-9]+}}> fn((&'{{[a-z0-9]+}} str, i32)) {main::f} is trivial: true
f!([usize; 0]); // CHECK: fn([usize; 0]) {main::f} is trivial: true
f!([char; 3]); // CHECK: fn([char; 3]) {main::f} is trivial: true
f!(&[u8; 3]); // for<'r> fn(&'r [u8; 3]) {main::f} is trivial: true

f!(&Path); // CHECK: for<'r> fn(&'r std::path::Path) {main::f} is trivial: true
f!(&Path); // CHECK: for<'{{[a-z0-9]+}}> fn(&'{{[a-z0-9]+}} std::path::Path) {main::f} is trivial: true
f!(Cell<()>); // CHECK: fn(std::cell::Cell<()>) {main::f} is trivial: true
f!(RefCell<()>); // CHECK: fn(std::cell::RefCell<()>) {main::f} is trivial: true
f!(AtomicBool); // CHECK: fn(std::sync::atomic::AtomicBool) {main::f} is trivial: true

f!(Trivial); // CHECK: for<'r> fn(Trivial<'r>) {main::f} is trivial: true
f!(Trivial); // CHECK: for<'{{[a-z0-9]+}}> fn(Trivial<'{{[a-z0-9]+}}>) {main::f} is trivial: true

// TODO(kkysen) Test self-referential/recursive types through references (see #834).
// Since transpiled types shouldn't have references, only pointers,
Expand Down
Loading