Skip to content

Commit

Permalink
function hypothetical lifetimes
Browse files Browse the repository at this point in the history
  • Loading branch information
aneksteind committed Jul 27, 2023
1 parent b30931e commit 108e7b4
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 47 deletions.
143 changes: 131 additions & 12 deletions c2rust-analyze/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::pointer_id::{
PointerTableMut,
};
use crate::util::{self, describe_rvalue, PhantomLifetime, RvalueDesc};
use crate::AssignPointerIds;
use crate::{fn_body_owners_postorder, AssignPointerIds};
use assert_matches::assert_matches;
use bitflags::bitflags;
use indexmap::IndexSet;
Expand All @@ -29,6 +29,7 @@ use rustc_middle::ty::FieldDef;
use rustc_middle::ty::GenericArgKind;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::Instance;
use rustc_middle::ty::RegionKind;
use rustc_middle::ty::Ty;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::TyKind;
Expand Down Expand Up @@ -264,17 +265,22 @@ impl<'tcx> Debug for AdtMetadataTable<'tcx> {
None
}
});

write!(f, "struct {:}", tcx.item_name(*k))?;
write!(f, "<")?;
let lifetime_params_str = adt
.lifetime_params
.iter()
.map(|p| format!("{:?}", p))
.chain(other_param_names)
.collect::<Vec<_>>()
.join(",");
write!(f, "{lifetime_params_str:}")?;
writeln!(f, "> {{")?;
if !adt.lifetime_params.is_empty() {
write!(f, "<")?;
let lifetime_params_str = adt
.lifetime_params
.iter()
.map(|p| format!("{:?}", p))
.chain(other_param_names)
.collect::<Vec<_>>()
.join(",");
write!(f, "{lifetime_params_str:}")?;
write!(f, ">")?;
}
writeln!(f, " {{")?;

for (fdid, fmeta) in &adt.field_info {
write!(f, "\t{:}: ", tcx.item_name(*fdid))?;
let field_string_lty = fmt_string(fmeta.origin_args);
Expand Down Expand Up @@ -318,6 +324,8 @@ pub struct GlobalAnalysisCtxt<'tcx> {

pub adt_metadata: AdtMetadataTable<'tcx>,

pub fn_origins: FnOriginMap<'tcx>,

pub foreign_mentioned_tys: HashSet<DefId>,
}

Expand Down Expand Up @@ -376,6 +384,113 @@ pub struct AnalysisCtxtData<'tcx> {
string_literal_locs: Vec<Location>,
}

pub struct FnOriginMap<'tcx> {
pub fn_info: HashMap<
DefId,
(
// fn lifetime params
Vec<OriginParam>,
// inputs
Vec<LabeledTy<'tcx, &'tcx [OriginArg<'tcx>]>>,
// output
LabeledTy<'tcx, &'tcx [OriginArg<'tcx>]>,
),
>,
}

fn fn_origin_args_params<'tcx>(
tcx: TyCtxt<'tcx>,
adt_metadata_table: &AdtMetadataTable,
) -> FnOriginMap<'tcx> {
let fn_dids = fn_body_owners_postorder(tcx);

let mut fn_info = HashMap::new();

for fn_did in fn_dids {
let fn_ty = tcx.type_of(fn_did);

// gather existing OriginParams
let mut origin_params = vec![];
if let TyKind::FnDef(_, substs) = fn_ty.kind() {
for sub in substs.iter() {
match sub.unpack() {
GenericArgKind::Lifetime(re) => match re.kind() {
RegionKind::ReEarlyBound(eb) => origin_params.push(OriginParam::Actual(eb)),
_ => (),
},
_ => (),
}
}
}

let mut arg_origin_args = vec![];

// gather new and existing OriginArgs and push new OriginParams
let sig = tcx.erase_late_bound_regions(tcx.fn_sig(fn_did));
let ltcx = LabeledTyCtxt::<'tcx, &[OriginArg<'tcx>]>::new(tcx);
let mut next_hypo_origin_id = 0;
let mut origin_lty = |ty: Ty<'tcx>| {
ltcx.label(ty, &mut |ty| {
let mut origin_args = vec![];
match ty.kind() {
TyKind::RawPtr(_ty) => {
let origin_arg = OriginArg::Hypothetical(next_hypo_origin_id);
next_hypo_origin_id += 1;
origin_args.push(origin_arg);

if let Ok(origin_param) = OriginParam::try_from(&origin_arg) {
origin_params.push(origin_param);
}
}
TyKind::Ref(reg, _ty, _mutability) => {
origin_args.push(OriginArg::Actual(*reg));
}
TyKind::Adt(adt_def, substs) => {
for sub in substs.iter() {
if let GenericArgKind::Lifetime(r) = sub.unpack() {
origin_args.push(OriginArg::Actual(r));
}
}
if let Some(adt_metadata) =
adt_metadata_table.table.get(&adt_def.did()).cloned()
{
for adt_param in adt_metadata.lifetime_params.iter() {
if let OriginParam::Hypothetical(_) = adt_param {
let origin_param =
OriginParam::Hypothetical(next_hypo_origin_id);
origin_params.push(origin_param);
origin_args.push(OriginArg::Hypothetical(next_hypo_origin_id));
next_hypo_origin_id += 1;
}
}
}
}
_ => (),
}

if origin_args.is_empty() {
return &[];
}
let origin_args: Vec<_> = origin_args.into_iter().collect();
ltcx.arena().alloc_slice(&origin_args[..])
})
};
for ty in sig.inputs().iter() {
let arg_lty = origin_lty(*ty);
arg_origin_args.push(arg_lty);
}

let output_lty = origin_lty(sig.output());

fn_info.insert(
fn_did.to_def_id(),
(origin_params, arg_origin_args, output_lty),
);
}

FnOriginMap { fn_info }
}

fn construct_adt_metadata<'tcx>(tcx: TyCtxt<'tcx>) -> AdtMetadataTable {
let struct_dids: Vec<_> = tcx
.hir_crate_items(())
Expand Down Expand Up @@ -551,6 +666,8 @@ fn construct_adt_metadata<'tcx>(tcx: TyCtxt<'tcx>) -> AdtMetadataTable {

impl<'tcx> GlobalAnalysisCtxt<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>) -> GlobalAnalysisCtxt<'tcx> {
let adt_metadata = construct_adt_metadata(tcx);
let fn_origins = fn_origin_args_params(tcx, &adt_metadata);
GlobalAnalysisCtxt {
tcx,
lcx: LabeledTyCtxt::new(tcx),
Expand All @@ -564,7 +681,8 @@ impl<'tcx> GlobalAnalysisCtxt<'tcx> {
field_ltys: HashMap::new(),
static_tys: HashMap::new(),
addr_of_static: HashMap::new(),
adt_metadata: construct_adt_metadata(tcx),
adt_metadata,
fn_origins,
foreign_mentioned_tys: HashSet::new(),
}
}
Expand Down Expand Up @@ -612,6 +730,7 @@ impl<'tcx> GlobalAnalysisCtxt<'tcx> {
ref mut static_tys,
ref mut addr_of_static,
adt_metadata: _,
fn_origins: _,
foreign_mentioned_tys: _,
} = *self;

Expand Down
1 change: 0 additions & 1 deletion c2rust-analyze/src/labeled_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,6 @@ impl<'tcx, L: Copy> LabeledTyCtxt<'tcx, L> {
where
F: FnMut(LabeledTy<'tcx, L1>, LabeledTy<'tcx, L2>, &'tcx [LabeledTy<'tcx, L>]) -> L,
{
assert_eq!(lty1.ty, lty2.ty);
assert_eq!(lty1.args.len(), lty2.args.len());
let args = self.zip_args_with(lty1.args, lty2.args, func);
self.mk(lty1.ty, args, func(lty1, lty2, args))
Expand Down
19 changes: 18 additions & 1 deletion c2rust-analyze/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1199,6 +1199,19 @@ fn all_static_items(tcx: TyCtxt) -> Vec<DefId> {
order
}

fn is_impl_clone(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
let clone_trait_def_id = match tcx.lang_items().clone_trait() {
Some(def_id) => def_id,
None => return false,
};
if let Some(impl_def_id) = tcx.impl_of_method(def_id) {
if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) {
return trait_ref.def_id == clone_trait_def_id;
}
}
false
}

/// Return all `LocalDefId`s for all `fn`s that are `body_owners`, ordered according to a postorder
/// traversal of the graph of references between bodies. Also returns the callgraph itself, in the
/// form of a map from callee `LocalDefId` to a set of caller `LocalDefId`s.
Expand All @@ -1217,7 +1230,11 @@ fn fn_body_owners_postorder(tcx: TyCtxt) -> Vec<LocalDefId> {
}

match tcx.def_kind(root_ldid) {
DefKind::Fn | DefKind::AssocFn => {}
DefKind::Fn | DefKind::AssocFn => {
if is_impl_clone(tcx, root_ldid.to_def_id()) {
continue;
}
}
DefKind::AnonConst | DefKind::Const | DefKind::Static(_) => continue,
dk => panic!(
"unexpected def_kind {:?} for body_owner {:?}",
Expand Down
70 changes: 51 additions & 19 deletions c2rust-analyze/src/rewrite/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::collections::HashMap;
use std::ops::Index;

use crate::borrowck::{OriginArg, OriginParam};
use crate::context::{AnalysisCtxt, Assignment, FlagSet, LTy, PermissionSet};
use crate::context::{AnalysisCtxt, Assignment, FlagSet, GlobalAnalysisCtxt, LTy, PermissionSet};
use crate::labeled_ty::{LabeledTy, LabeledTyCtxt};
use crate::pointer_id::PointerId;
use crate::rewrite::Rewrite;
Expand Down Expand Up @@ -108,15 +108,15 @@ fn relabel_rewrites<'tcx, P, F>(
flags: &F,
lcx: LabeledTyCtxt<'tcx, RewriteLabel<'tcx>>,
lty: LTy<'tcx>,
adt_metadata: &AdtMetadataTable,
gacx: &GlobalAnalysisCtxt<'tcx>,
) -> RwLTy<'tcx>
where
P: Index<PointerId, Output = PermissionSet>,
F: Index<PointerId, Output = FlagSet>,
{
lcx.relabel_with_args(lty, &mut |pointer_lty, args| {
// FIXME: get function lifetime parameters and pass them to this
create_rewrite_label(pointer_lty, args, perms, flags, &[], adt_metadata)
create_rewrite_label(pointer_lty, args, perms, flags, &[], &gacx.adt_metadata)
})
}

Expand Down Expand Up @@ -573,7 +573,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for HirTyVisitor<'a, 'tcx> {
&self.asn.flags(),
self.rw_lcx,
lty,
&self.acx.gacx.adt_metadata,
&self.acx.gacx,
);
let hir_ty = hir_local.ty.unwrap();
self.handle_ty(rw_lty, hir_ty);
Expand Down Expand Up @@ -613,28 +613,60 @@ pub fn gen_ty_rewrites<'tcx>(
.fn_sig_by_hir_id(hir_id)
.unwrap_or_else(|| panic!("expected def {:?} to be a function", ldid));

let (origin_params, input_origin_args, output_origin_args) =
&acx.gacx.fn_origins.fn_info[&ldid.to_def_id()];
let hir_generics = acx.tcx().hir().get_generics(ldid);
if let Some(generics) = hir_generics {
let mut generics_rws: Vec<Rewrite> = vec![];
for p in origin_params {
generics_rws.push(Rewrite::PrintTy(format!("{p:?}")))
}
if !generics_rws.is_empty() {
v.hir_rewrites
.push((generics.span, Rewrite::TyGenericParams(generics_rws)))
}
}

let lty_sig = acx.gacx.fn_sigs.get(&ldid.to_def_id()).unwrap();
assert_eq!(lty_sig.inputs.len(), hir_sig.decl.inputs.len());
for (&lty, hir_ty) in lty_sig.inputs.iter().zip(hir_sig.decl.inputs.iter()) {
let rw_lty = relabel_rewrites(
&asn.perms(),
&asn.flags(),
rw_lcx,
lty,
&acx.gacx.adt_metadata,
);
for ((&lty, hir_ty), origin_args) in lty_sig
.inputs
.iter()
.zip(hir_sig.decl.inputs.iter())
.zip(input_origin_args.iter())
{
let rw_lty =
rw_lcx.zip_labels_with(lty, &origin_args, &mut |pointer_lty, lifetime_lty, args| {
create_rewrite_label(
pointer_lty,
args,
&asn.perms(),
&asn.flags(),
lifetime_lty.label,
&acx.gacx.adt_metadata,
)
});

v.handle_ty(rw_lty, hir_ty);
}

if let hir::FnRetTy::Return(hir_ty) = hir_sig.decl.output {
let rw_lty = relabel_rewrites(
&asn.perms(),
&asn.flags(),
rw_lcx,
let output_rw_lty = rw_lcx.zip_labels_with(
lty_sig.output,
&acx.gacx.adt_metadata,
&output_origin_args,
&mut |pointer_lty, lifetime_lty, args| {
create_rewrite_label(
pointer_lty,
args,
&asn.perms(),
&asn.flags(),
lifetime_lty.label,
&acx.gacx.adt_metadata,
)
},
);
v.handle_ty(rw_lty, hir_ty);

v.handle_ty(output_rw_lty, hir_ty);
}

let hir_body_id = acx.tcx().hir().body_owned_by(ldid);
Expand Down Expand Up @@ -668,7 +700,7 @@ pub fn dump_rewritten_local_tys<'tcx>(
&asn.flags(),
rw_lcx,
acx.local_tys[local],
&acx.gacx.adt_metadata,
&acx.gacx,
);
let ty = mk_rewritten_ty(rw_lcx, rw_lty);
eprintln!(
Expand Down
4 changes: 2 additions & 2 deletions c2rust-analyze/tests/filecheck/call_cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ unsafe fn pass_slice(x: *mut i32) -> *mut i32 {
}


// CHECK-LABEL: fn f(x: &mut (i32))
// CHECK-LABEL: fn f<'h0>(x: &'h0 mut (i32))
unsafe fn f(x: *mut i32) {
// CHECK: use_single(core::ptr::addr_of_mut!(*(x)))
use_single(x);
Expand All @@ -44,7 +44,7 @@ unsafe fn f(x: *mut i32) {
use_single(y);
}

// CHECK-LABEL: fn g(x: &mut [(i32)])
// CHECK-LABEL: fn g<'h0>(x: &'h0 mut [(i32)])
unsafe fn g(x: *mut i32) {
// CHECK: use_single(core::ptr::addr_of_mut!(*&mut (x)[0]))
use_single(x);
Expand Down
3 changes: 2 additions & 1 deletion c2rust-analyze/tests/filecheck/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extern "C" {
fn bar(f: Foo);
}

// CHECK-LABEL: pub unsafe fn cell_as_mut_as_cell(mut x: &core::cell::Cell<(i32)>, mut f: Foo) {
// CHECK-LABEL: pub unsafe fn cell_as_mut_as_cell<'h0,'h1>(mut x: &'h0 core::cell::Cell<(i32)>, mut f: Foo<'h1>) {
pub unsafe fn cell_as_mut_as_cell(mut x: *mut i32, mut f: Foo) {
let z = x;
let r = x;
Expand All @@ -43,6 +43,7 @@ pub struct fdnode {
pub ctx: *mut u8,
}

// CHECK-LABEL: unsafe extern "C" fn server_free<'h0,'h1>(fdn: &'h0 (fdnode<'h1>)) {
unsafe extern "C" fn server_free(fdn: *mut fdnode) {
let _fdn2 = fdn as *const fdnode;
}
Loading

0 comments on commit 108e7b4

Please sign in to comment.