Skip to content

Commit ec3e109

Browse files
authored
transpile: fixes before re-enabling --reorganize-definitions (#1452)
Most of the changes from #1414 with #1451 split out. In combination with #1451, supersedes #1414.
2 parents 702bdbb + d4b5e97 commit ec3e109

File tree

7 files changed

+278
-32
lines changed

7 files changed

+278
-32
lines changed

c2rust-transpile/src/rust_ast/item_store.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use indexmap::{IndexMap, IndexSet};
33
use syn::{ForeignItem, Ident, Item};
44

55
use std::borrow::Cow;
6+
use std::collections::HashSet;
67
use std::mem::swap;
78

89
#[derive(Debug)]
@@ -78,6 +79,19 @@ impl PathedMultiImports {
7879
})
7980
.collect()
8081
}
82+
83+
/// Remove all imports covered by the other [`PathedMultiImports`].
84+
pub fn remove(&mut self, other: &PathedMultiImports) {
85+
for (k, v) in &mut self.0 {
86+
// We don't consider attributes, just subtract leaf sets.
87+
let other_items = other
88+
.0
89+
.get(k)
90+
.map(|imports| imports.leaves.iter().collect::<HashSet<_>>())
91+
.unwrap_or_default();
92+
v.leaves.retain(|leaf| !other_items.contains(leaf));
93+
}
94+
}
8195
}
8296

8397
#[derive(Debug, Default)]

c2rust-transpile/src/translator/literals.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,10 @@ impl<'c> Translation<'c> {
334334
.borrow()
335335
.resolve_decl_name(union_id)
336336
.unwrap();
337+
if let Some(cur_file) = self.cur_file.get() {
338+
log::debug!("in file {cur_file} importing union {union_name}, id {union_id:?}");
339+
self.add_import(cur_file, union_id, &union_name);
340+
}
337341
match self.ast_context.index(union_field_id).kind {
338342
CDeclKind::Field { typ: field_ty, .. } => {
339343
let val = if ids.is_empty() {

c2rust-transpile/src/translator/mod.rs

Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use syn::{
1818
ForeignItemStatic, ForeignItemType, Ident, Item, ItemConst, ItemEnum, ItemExternCrate, ItemFn,
1919
ItemForeignMod, ItemImpl, ItemMacro, ItemMod, ItemStatic, ItemStruct, ItemTrait,
2020
ItemTraitAlias, ItemType, ItemUnion, ItemUse, Lit, MacroDelimiter, PathSegment, ReturnType,
21-
Stmt, Type, TypeTuple, Visibility,
21+
Stmt, Type, TypeTuple, UseTree, Visibility,
2222
};
2323
use syn::{BinOp, UnOp}; // To override `c_ast::{BinOp,UnOp}` from glob import.
2424

@@ -630,7 +630,7 @@ pub fn translate(
630630
}
631631

632632
{
633-
let convert_type = |decl_id: CDeclId, decl: &CDecl| {
633+
let export_type = |decl_id: CDeclId, decl: &CDecl| {
634634
let decl_file_id = t.ast_context.file_id(decl);
635635
if t.tcfg.reorganize_definitions {
636636
t.cur_file.set(decl_file_id);
@@ -664,6 +664,14 @@ pub fn translate(
664664
if t.tcfg.reorganize_definitions
665665
&& decl_file_id.map_or(false, |id| id != t.main_file)
666666
{
667+
let name = t
668+
.ast_context
669+
.get_decl(&decl_id)
670+
.and_then(|x| x.kind.get_name());
671+
log::debug!(
672+
"emitting submodule imports for exported type {}",
673+
name.unwrap_or(&"unknown".to_owned())
674+
);
667675
t.generate_submodule_imports(decl_id, decl_file_id);
668676
}
669677
};
@@ -684,7 +692,7 @@ pub fn translate(
684692
_ => false,
685693
};
686694
if needs_export {
687-
convert_type(decl_id, decl);
695+
export_type(decl_id, decl);
688696
}
689697
}
690698
}
@@ -771,6 +779,7 @@ pub fn translate(
771779
};
772780

773781
if t.tcfg.reorganize_definitions && decl_file_id.map_or(false, |id| id != t.main_file) {
782+
log::debug!("emitting any imports needed by {:?}", decl.kind.get_name());
774783
t.generate_submodule_imports(*top_id, decl_file_id);
775784
}
776785
}
@@ -870,14 +879,17 @@ pub fn translate(
870879

871880
all_items.extend(mod_items);
872881

882+
// Before consuming `uses`, remove them from the uses from submodules to avoid duplicates.
883+
let (_, _, mut new_uses) = new_uses.drain();
884+
new_uses.remove(&uses);
885+
873886
// This could have been merged in with items below; however, it's more idiomatic to have
874887
// imports near the top of the file than randomly scattered about. Also, there is probably
875888
// no reason to have comments associated with imports so it doesn't need to go through
876889
// the above comment store process
877890
all_items.extend(uses.into_items());
878891

879892
// Print new uses from submodules
880-
let (_, _, new_uses) = new_uses.drain();
881893
all_items.extend(new_uses.into_items());
882894

883895
if !foreign_items.is_empty() {
@@ -907,6 +919,43 @@ pub fn translate(
907919
}
908920
}
909921

922+
/// Represent the set of names made visible by a `use`: either a set of specific names, or a glob.
923+
enum IdentsOrGlob<'a> {
924+
Idents(Vec<&'a Ident>),
925+
Glob,
926+
}
927+
928+
impl<'a> IdentsOrGlob<'a> {
929+
fn join(self, other: Self) -> Self {
930+
use IdentsOrGlob::*;
931+
match (self, other) {
932+
(Glob, _) => Glob,
933+
(_, Glob) => Glob,
934+
(Idents(mut own), Idents(other)) => Idents({
935+
own.extend(other.into_iter());
936+
own
937+
}),
938+
}
939+
}
940+
}
941+
942+
/// Extract the set of names made visible by a `use`.
943+
fn use_idents<'a>(i: &'a UseTree) -> IdentsOrGlob<'a> {
944+
use UseTree::*;
945+
match i {
946+
Path(up) => use_idents(&up.tree),
947+
Name(un) => IdentsOrGlob::Idents(vec![&un.ident]),
948+
Rename(ur) => IdentsOrGlob::Idents(vec![&ur.rename]),
949+
Glob(_ugl) => IdentsOrGlob::Glob,
950+
Group(ugr) => ugr
951+
.items
952+
.iter()
953+
.map(|tree| use_idents(tree))
954+
.reduce(IdentsOrGlob::join)
955+
.unwrap_or(IdentsOrGlob::Idents(vec![])),
956+
}
957+
}
958+
910959
fn item_ident(i: &Item) -> Option<&Ident> {
911960
use Item::*;
912961
Some(match i {
@@ -986,6 +1035,8 @@ fn foreign_item_ident_vis(fi: &ForeignItem) -> Option<(&Ident, Visibility)> {
9861035
})
9871036
}
9881037

1038+
/// Create a submodule containing the items in `item_store`. Populates `use_item_store` with the set
1039+
/// of `use`s to import the submodule's exports.
9891040
fn make_submodule(
9901041
ast_context: &TypedAstContext,
9911042
item_store: &mut ItemStore,
@@ -1000,34 +1051,67 @@ fn make_submodule(
10001051
.get_file_include_line_number(file_id)
10011052
.unwrap_or(0);
10021053
let mod_name = clean_path(mod_names, file_path);
1054+
let use_path = || vec!["self".into(), mod_name.clone()];
10031055

10041056
for item in items.iter() {
10051057
let ident_name = match item_ident(item) {
10061058
Some(i) => i.to_string(),
10071059
None => continue,
10081060
};
1009-
let use_path = vec!["self".into(), mod_name.clone()];
10101061

10111062
let vis = match item_vis(item) {
10121063
Some(Visibility::Public(_)) => mk().pub_(),
10131064
Some(_) => mk(),
10141065
None => continue,
10151066
};
10161067

1017-
use_item_store.add_use_with_attr(false, use_path, &ident_name, vis);
1068+
use_item_store.add_use_with_attr(false, use_path(), &ident_name, vis);
10181069
}
10191070

10201071
for foreign_item in foreign_items.iter() {
10211072
let ident_name = match foreign_item_ident_vis(foreign_item) {
10221073
Some((ident, _vis)) => ident.to_string(),
10231074
None => continue,
10241075
};
1025-
let use_path = vec!["self".into(), mod_name.clone()];
10261076

1027-
use_item_store.add_use(false, use_path, &ident_name);
1077+
use_item_store.add_use(false, use_path(), &ident_name);
10281078
}
10291079

1080+
// Consumers will `use` reexported items at their exported locations.
10301081
for item in uses.into_items() {
1082+
if let Item::Use(ItemUse {
1083+
vis: Visibility::Public(_),
1084+
tree,
1085+
..
1086+
}) = &*item
1087+
{
1088+
match use_idents(tree) {
1089+
IdentsOrGlob::Idents(idents) => {
1090+
for ident in idents {
1091+
fn is_simd_type_name(name: &str) -> bool {
1092+
const SIMD_TYPE_NAMES: &[&str] = &[
1093+
"__m128i", "__m128", "__m128d", "__m64", "__m256", "__m256d",
1094+
"__m256i",
1095+
];
1096+
SIMD_TYPE_NAMES.contains(&name) || name.starts_with("_mm_")
1097+
}
1098+
let name = &*ident.to_string();
1099+
if is_simd_type_name(name) {
1100+
// Import vector type/operation names from the stdlib, as we also generate
1101+
// other uses for them from that location and can't easily reason about
1102+
// the ultimate target of reexported names when avoiding duplicate imports
1103+
// (which are verboten).
1104+
simd::add_arch_use(use_item_store, "x86", name);
1105+
simd::add_arch_use(use_item_store, "x86_64", name);
1106+
} else {
1107+
// Add a `use` for `self::this_module::exported_name`.
1108+
use_item_store.add_use(false, use_path(), name);
1109+
}
1110+
}
1111+
}
1112+
IdentsOrGlob::Glob => {}
1113+
}
1114+
}
10311115
items.push(item);
10321116
}
10331117

c2rust-transpile/src/translator/simd.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ static SIMD_X86_64_ONLY: &[&str] = &[
6767
"_mm_crc32_u64",
6868
];
6969

70-
fn add_arch_use(store: &mut ItemStore, arch_name: &str, item_name: &str) {
70+
pub fn add_arch_use(store: &mut ItemStore, arch_name: &str, item_name: &str) {
7171
store.add_use_with_attr(
7272
true,
7373
vec!["core".into(), "arch".into(), arch_name.into()],

c2rust-transpile/src/translator/structs.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,10 @@ impl<'a> Translation<'a> {
398398
field_expr_ids: &[CExprId],
399399
) -> TranslationResult<WithStmts<Box<Expr>>> {
400400
let name = self.resolve_decl_inner_name(struct_id);
401+
if let Some(cur_file) = self.cur_file.get() {
402+
log::debug!("in file {cur_file} importing struct {name}, id {struct_id:?}");
403+
self.add_import(cur_file, struct_id, &name);
404+
}
401405

402406
let (field_decl_ids, platform_byte_size) = match self.ast_context.index(struct_id).kind {
403407
CDeclKind::Struct {

0 commit comments

Comments
 (0)