@@ -107,7 +107,7 @@ pub fn emit_build_files<'lcmd>(
107107 } )
108108}
109109
110- #[ derive( Serialize ) ]
110+ #[ derive( Clone , Debug , Serialize ) ]
111111struct Module {
112112 path : Option < String > ,
113113 name : String ,
@@ -116,19 +116,23 @@ struct Module {
116116}
117117
118118#[ derive( Debug , Default ) ]
119- struct ModuleTree ( BTreeMap < String , ModuleTree > ) ;
119+ struct ModuleTree {
120+ children : BTreeMap < String , ModuleTree > ,
121+ path_modules : Vec < Module > ,
122+ }
120123
121124impl ModuleTree {
122125 /// Convert the tree representation into a linear vector
123126 /// and push it into `res`
124127 fn linearize ( & self , res : & mut Vec < Module > ) {
125- for ( name, child) in self . 0 . iter ( ) {
128+ res. extend ( self . path_modules . iter ( ) . cloned ( ) ) ;
129+ for ( name, child) in self . children . iter ( ) {
126130 child. linearize_internal ( name, res) ;
127131 }
128132 }
129133
130134 fn linearize_internal ( & self , name : & str , res : & mut Vec < Module > ) {
131- if self . 0 . is_empty ( ) {
135+ if self . path_modules . is_empty ( ) && self . children . is_empty ( ) {
132136 res. push ( Module {
133137 name : name. to_string ( ) ,
134138 path : None ,
@@ -151,6 +155,55 @@ impl ModuleTree {
151155 } ) ;
152156 }
153157 }
158+
159+ fn insert_nested ( & mut self , path : Vec < String > ) {
160+ let mut cur = self ;
161+ for name in path {
162+ cur = cur. children . entry ( name) . or_default ( ) ;
163+ }
164+ }
165+
166+ fn insert_path_module (
167+ & mut self ,
168+ parent_path : & [ String ] ,
169+ file_name : String ,
170+ module_name : String ,
171+ ) {
172+ let mut cur = self ;
173+ for name in parent_path {
174+ cur = cur. children . entry ( name. clone ( ) ) . or_default ( ) ;
175+ }
176+ let name = cur. unique_child_name ( & module_name) ;
177+ cur. path_modules . push ( Module {
178+ path : Some ( file_name) ,
179+ name,
180+ open : false ,
181+ close : false ,
182+ } ) ;
183+ }
184+
185+ fn unique_child_name ( & self , module_name : & str ) -> String {
186+ if !self . child_name_exists ( module_name) {
187+ return module_name. to_owned ( ) ;
188+ }
189+
190+ for i in 1 .. {
191+ let candidate = format ! ( "{module_name}{i}" ) ;
192+ if !self . child_name_exists ( & candidate) {
193+ return candidate;
194+ }
195+ }
196+
197+ unreachable ! ( "We tried all the numbers and couln't find one that didn't collide" )
198+ }
199+
200+ fn child_name_exists ( & self , module_name : & str ) -> bool {
201+ self . children . contains_key ( module_name)
202+ || self
203+ . path_modules
204+ . iter ( )
205+ . any ( |module| module. name == module_name)
206+ }
154207}
155208
156209#[ derive( Debug , PartialEq , Eq ) ]
@@ -182,7 +235,7 @@ fn convert_module_list(
182235 } ) ;
183236
184237 let mut res = vec ! [ ] ;
185- let mut module_tree = ModuleTree ( BTreeMap :: new ( ) ) ;
238+ let mut module_tree = ModuleTree :: default ( ) ;
186239 // A C file can have the same stem as a sibling directory, such as
187240 // `hash.c` and `hash/sha1.c`. The current nested module emitter cannot
188241 // represent both at `mod hash`, so emit the file module with an explicit
@@ -207,28 +260,21 @@ fn convert_module_list(
207260 . then_some ( * module)
208261 } )
209262 . collect :: < BTreeSet < _ > > ( ) ;
210- let mut used_flat_names = BTreeSet :: new ( ) ;
211263
264+ let mut collision_relpaths = vec ! [ ] ;
212265 for m in & modules {
213266 match m. strip_prefix ( build_dir) {
214267 Ok ( relpath) if !tcfg. is_binary ( m) && !collision_modules. contains ( m) => {
215268 // The module is inside the build directory, use nested modules
216- let mut cur = & mut module_tree;
217- for name in module_path ( relpath ) {
218- cur = cur . 0 . entry ( name ) . or_default ( ) ;
219- }
269+ module_tree. insert_nested ( module_path ( relpath ) ) ;
270+ }
271+ Ok ( relpath ) if !tcfg . is_binary ( m ) => {
272+ collision_relpaths . push ( relpath . to_path_buf ( ) ) ;
220273 }
221274 _ => {
222275 let relpath = diff_paths ( m, build_dir) . unwrap ( ) ;
223276 let path = Some ( relpath. to_str ( ) . unwrap ( ) . to_string ( ) ) ;
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- } ;
277+ let name = get_module_name ( m, true , false , false ) . unwrap ( ) ;
232278 res. push ( Module {
233279 path,
234280 name,
@@ -238,6 +284,12 @@ fn convert_module_list(
238284 }
239285 }
240286 }
287+ for relpath in collision_relpaths {
288+ let mut path = module_path ( & relpath) ;
289+ let module_name = format ! ( "{}_" , path. pop( ) . unwrap( ) ) ;
290+ let file_name = relpath. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ;
291+ module_tree. insert_path_module ( & path, file_name, module_name) ;
292+ }
241293 module_tree. linearize ( & mut res) ;
242294 res
243295}
@@ -251,21 +303,6 @@ fn module_path(path: &Path) -> Vec<String> {
251303 . collect ( )
252304}
253305
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-
269306fn emit_thin_binaries (
270307 tcfg : & TranspilerConfig ,
271308 build_dir : & Path ,
0 commit comments