Skip to content

Commit eb7f18b

Browse files
randomPoisonthedataking
authored andcommitted
First attempt at a fix
1 parent 8e4ff5d commit eb7f18b

1 file changed

Lines changed: 61 additions & 6 deletions

File tree

  • c2rust-transpile/src/build_files

c2rust-transpile/src/build_files/mod.rs

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::BTreeMap;
1+
use std::collections::{BTreeMap, BTreeSet};
22
use std::fs::{self, File};
33
use std::io::Write;
44
use std::path::{Path, PathBuf};
@@ -183,21 +183,52 @@ fn convert_module_list(
183183

184184
let mut res = vec![];
185185
let mut module_tree = ModuleTree(BTreeMap::new());
186+
// A C file can have the same stem as a sibling directory, such as
187+
// `hash.c` and `hash/sha1.c`. The current nested module emitter cannot
188+
// represent both at `mod hash`, so emit the file module with an explicit
189+
// path and keep the directory in the nested tree.
190+
let internal_modules = modules
191+
.iter()
192+
.filter_map(|m| {
193+
if tcfg.is_binary(m) {
194+
return None;
195+
}
196+
let relpath = m.strip_prefix(build_dir).ok()?;
197+
let path = module_path(relpath);
198+
Some((m, path))
199+
})
200+
.collect::<Vec<_>>();
201+
let collision_modules = internal_modules
202+
.iter()
203+
.filter_map(|(module, path)| {
204+
internal_modules
205+
.iter()
206+
.any(|(_, other)| other.len() > path.len() && other.starts_with(path))
207+
.then_some(*module)
208+
})
209+
.collect::<BTreeSet<_>>();
210+
let mut used_flat_names = BTreeSet::new();
211+
186212
for m in &modules {
187213
match m.strip_prefix(build_dir) {
188-
Ok(relpath) if !tcfg.is_binary(m) => {
214+
Ok(relpath) if !tcfg.is_binary(m) && !collision_modules.contains(m) => {
189215
// The module is inside the build directory, use nested modules
190216
let mut cur = &mut module_tree;
191-
for sm in relpath.iter() {
192-
let path = Path::new(sm);
193-
let name = get_module_name(path, true, false, false).unwrap();
217+
for name in module_path(relpath) {
194218
cur = cur.0.entry(name).or_default();
195219
}
196220
}
197221
_ => {
198222
let relpath = diff_paths(m, build_dir).unwrap();
199223
let path = Some(relpath.to_str().unwrap().to_string());
200-
let name = get_module_name(m, true, false, false).unwrap();
224+
let name = if collision_modules.contains(m) {
225+
unique_collision_module_name(
226+
m.strip_prefix(build_dir).unwrap(),
227+
&mut used_flat_names,
228+
)
229+
} else {
230+
get_module_name(m, true, false, false).unwrap()
231+
};
201232
res.push(Module {
202233
path,
203234
name,
@@ -211,6 +242,30 @@ fn convert_module_list(
211242
res
212243
}
213244

245+
fn module_path(path: &Path) -> Vec<String> {
246+
path.iter()
247+
.map(|component| {
248+
let path = Path::new(component);
249+
get_module_name(path, true, false, false).unwrap()
250+
})
251+
.collect()
252+
}
253+
254+
fn unique_collision_module_name(path: &Path, used_names: &mut BTreeSet<String>) -> String {
255+
let base = format!("c2rust_{}", module_path(path).into_iter().join("_"));
256+
if used_names.insert(base.clone()) {
257+
return base;
258+
}
259+
260+
for i in 1.. {
261+
let candidate = format!("{base}_{i}");
262+
if used_names.insert(candidate.clone()) {
263+
return candidate;
264+
}
265+
}
266+
unreachable!()
267+
}
268+
214269
fn emit_thin_binaries(
215270
tcfg: &TranspilerConfig,
216271
build_dir: &Path,

0 commit comments

Comments
 (0)