Skip to content

transpile: Handle module name collisions#1858

Draft
randomPoison wants to merge 3 commits into
perl/test-libgit2from
legare/module-name-collision
Draft

transpile: Handle module name collisions#1858
randomPoison wants to merge 3 commits into
perl/test-libgit2from
legare/module-name-collision

Conversation

@randomPoison

Copy link
Copy Markdown
Contributor

Note that the current code is directly from Codex, I haven't yet reviewed and cleaned things up and am putting this up mostly for visibility.

In testing against libgit2, we ran into a case where module names could collide, leading to a generated Rust file not being included in the build. The situation is that we have both a hash.c file and some files in a hash directory, e.g. hash/sha1.c. C2rust then wants to generate both

mod src {
    mod hash;
}

and

mod src {
    mod hash {
        mod sha1;
    }
}

In this case, the latter is what gets generated, effectively dropping src/hash.rs from the Rust build.

This PR has c2rust detect these collisions and rename the colliding module, so we'd generate something like

mod src {
    #[path = "hash.rs"]
    mod hash_;
    mod hash {
        mod sha1;
    }
}

}

for i in 1.. {
let candidate = format!("{module_name}{i}");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The transpiler renamer uses the scheme {name}_{i}, it would make sense to keep that for consistency.

.iter()
.filter_map(|(module, path)| {
internal_modules
.iter()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is quadratic in the number of modules, it might be worth optimizing this a little. Maybe sort them first, or use a trie?

}
for relpath in collision_relpaths {
let mut path = module_path(&relpath);
let module_name = format!("{}_", path.pop().unwrap());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

"{}_0" for consistency with the transpiler? Or anything other than a trailing _?

let mut path = module_path(&relpath);
let module_name = format!("{}_", path.pop().unwrap());
let file_name = relpath.file_name().unwrap().to_str().unwrap().to_string();
module_tree.insert_path_module(&path, file_name, module_name);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Doesn't insert_path_module already checks for uniqueness? Why do you need the extra trailing underscore?

}
for relpath in collision_relpaths {
let mut path = module_path(&relpath);
let module_name = format!("{}_", path.pop().unwrap());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Don't we also need to check the new module for collisions?

}
}

unreachable!("We tried all the numbers and couln't find one that didn't collide")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: couldn't

@thedataking thedataking changed the title Attempt to handle module name collisions transpile: Handle module name collisions Jun 17, 2026
Comment thread c2rust-transpile/src/build_files/mod.rs
@thedataking thedataking changed the base branch from master to perl/test-libgit2 June 18, 2026 09:31
@thedataking thedataking added the bug Something isn't working label Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants