Skip to content

Commit

Permalink
Add hypothetical lifetime parameters and arguments to function signat…
Browse files Browse the repository at this point in the history
…ures (#1000)

Fixes #921 and fixes #927
  • Loading branch information
aneksteind authored Aug 1, 2023
2 parents 157c741 + 1e5b3b5 commit 333d8ed
Show file tree
Hide file tree
Showing 13 changed files with 336 additions and 101 deletions.
139 changes: 127 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 @@ -266,17 +267,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 @@ -320,6 +326,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 @@ -378,6 +386,109 @@ pub struct AnalysisCtxtData<'tcx> {
string_literal_locs: Vec<Location>,
}

pub struct FnSigOrigins<'tcx> {
pub origin_params: Vec<OriginParam>,
pub inputs: Vec<LabeledTy<'tcx, &'tcx [OriginArg<'tcx>]>>,
pub output: LabeledTy<'tcx, &'tcx [OriginArg<'tcx>]>,
}

pub struct FnOriginMap<'tcx> {
pub fn_info: HashMap<DefId, FnSigOrigins<'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) => {
origin_args.push(OriginArg::Hypothetical(next_hypo_origin_id));
origin_params.push(OriginParam::Hypothetical(next_hypo_origin_id));
next_hypo_origin_id += 1;
}
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 = origin_lty(sig.output());

fn_info.insert(
fn_did.to_def_id(),
FnSigOrigins {
origin_params,
inputs: arg_origin_args,
output,
},
);
}

FnOriginMap { fn_info }
}

fn construct_adt_metadata<'tcx>(tcx: TyCtxt<'tcx>) -> AdtMetadataTable {
let struct_dids: Vec<_> = tcx
.hir_crate_items(())
Expand Down Expand Up @@ -553,6 +664,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 @@ -566,7 +679,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 @@ -614,6 +728,7 @@ impl<'tcx> GlobalAnalysisCtxt<'tcx> {
ref mut static_tys,
ref mut addr_of_static,
adt_metadata: _,
fn_origins: _,
foreign_mentioned_tys: _,
} = *self;

Expand Down
20 changes: 19 additions & 1 deletion c2rust-analyze/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![feature(rustc_private)]
#![feature(iter_order_by)]
extern crate either;
extern crate rustc_arena;
extern crate rustc_ast;
Expand Down Expand Up @@ -1291,6 +1292,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 @@ -1309,7 +1323,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
2 changes: 1 addition & 1 deletion c2rust-analyze/src/rewrite/apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ impl<S: Sink> Emitter<'_, S> {
}),
Rewrite::LitZero => self.emit_str("0"),

Rewrite::PrintTy(ref s) => self.emit_str(s),
Rewrite::Print(ref s) => self.emit_str(s),
Rewrite::TyGenericParams(ref rws) => {
self.emit_str("<")?;
for (index, rw) in rws.iter().enumerate() {
Expand Down
3 changes: 2 additions & 1 deletion c2rust-analyze/src/rewrite/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ pub enum Rewrite<S = Span> {

// Type builders
/// Emit a complete pretty-printed type, discarding the original annotation.
PrintTy(String),
Print(String),
/// `*const T`, `*mut T`
TyPtr(Box<Rewrite>, Mutability),
/// `&T`, `&mut T`
Expand All @@ -97,6 +97,7 @@ pub enum Rewrite<S = Span> {
/// `<'a, 'b, ...>`
/// needed for cases when the span of the ADT name
/// is different from ADT generic params
#[allow(dead_code)]
TyGenericParams(Vec<Rewrite>),

// `static` builders
Expand Down
Loading

0 comments on commit 333d8ed

Please sign in to comment.