From 5492b9b159668d3932a6c3406b05009a7754c51a Mon Sep 17 00:00:00 2001 From: fw Date: Thu, 30 Oct 2025 17:08:14 -0400 Subject: [PATCH 01/13] tests/statics: tolerate --reorganize-definitions output --- tests/statics/src/test_sections.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/statics/src/test_sections.rs b/tests/statics/src/test_sections.rs index 0fd84e74bd..16d30b63ad 100644 --- a/tests/statics/src/test_sections.rs +++ b/tests/statics/src/test_sections.rs @@ -36,7 +36,12 @@ pub fn test_sectioned_used_static() { // directly at the source file let src = include_str!("attributes.rs"); - let lines: Vec<&str> = src.lines().collect(); + let mut lines: Vec<&str> = src.lines().collect(); + + // Remove the c2rust::src_loc annotation, which is only produced if + // --reorganize-definitions is enabled. + lines.retain(|x| !x.contains("#[c2rust::src_loc")); + let src = lines.join("\n"); let pos = lines .iter() @@ -52,6 +57,8 @@ pub fn test_sectioned_used_static() { // This static is pub, but we want to ensure it has attributes applied assert!(src.contains("#[link_section = \"fb\"]\npub static mut rust_initialized_extern: ::core::ffi::c_int = 1 as ::core::ffi::c_int;")); - assert!(src.contains("extern \"C\" {\n #[link_name = \"no_attrs\"]\n static mut rust_aliased_static: ::core::ffi::c_int;")) + // This static is pub only with --reorganize-definitions + let aliased_static_syntax = |public| format!("extern \"C\" {{\n #[link_name = \"no_attrs\"]\n {}static mut rust_aliased_static: ::core::ffi::c_int;", public); + assert!(src.contains(&aliased_static_syntax("")) || src.contains(&aliased_static_syntax("pub "))) } } From 6aa55545f995c56efe05534e936928516a19c0a7 Mon Sep 17 00:00:00 2001 From: fw Date: Thu, 30 Oct 2025 17:14:22 -0400 Subject: [PATCH 02/13] tests/items: tolerate --reorganize-definitions output --- tests/items/src/test_fn_attrs.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/items/src/test_fn_attrs.rs b/tests/items/src/test_fn_attrs.rs index 518a3d1c09..1edf4e1c37 100644 --- a/tests/items/src/test_fn_attrs.rs +++ b/tests/items/src/test_fn_attrs.rs @@ -6,6 +6,12 @@ pub fn test_fn_attrs() { // so instead we're checking the source itself let src = include_str!("fn_attrs.rs"); + // Remove the c2rust::src_loc annotation, which is only produced if + // --reorganize-definitions is enabled. + let mut lines: Vec<&str> = src.lines().collect(); + lines.retain(|x| !x.contains("#[c2rust::src_loc")); + let src = lines.join("\n"); + // Some C99 rules for convenience: // * In C99, a function defined inline will never, and a function defined extern inline // will always, emit an externally visible function. @@ -57,8 +63,7 @@ pub fn test_fn_attrs() { if cfg!(not(target_os = "macos")) { // aliased_fn is aliased to the inline_extern function - assert!(src.contains( - "extern \"C\" {\n #[link_name = \"inline_extern\"]\n fn aliased_fn();" - )); + let aliased_fn_syntax = |public| format!("extern \"C\" {{\n #[link_name = \"inline_extern\"]\n {}fn aliased_fn();", public); + assert!(src.contains(&aliased_fn_syntax("")) || src.contains(&aliased_fn_syntax("pub "))); } } From 00796cbfbc59ebe63c1c4307657a11a1ad2c9369 Mon Sep 17 00:00:00 2001 From: fw Date: Mon, 3 Nov 2025 10:05:20 -0500 Subject: [PATCH 03/13] transpile: rename shadowing convert_type closure this closure is called when exporting types, and a convert_type method already exists --- c2rust-transpile/src/translator/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 383a55a70b..5898276fd4 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -630,7 +630,7 @@ pub fn translate( } { - let convert_type = |decl_id: CDeclId, decl: &CDecl| { + let export_type = |decl_id: CDeclId, decl: &CDecl| { let decl_file_id = t.ast_context.file_id(decl); if t.tcfg.reorganize_definitions { t.cur_file.set(decl_file_id); @@ -684,7 +684,7 @@ pub fn translate( _ => false, }; if needs_export { - convert_type(decl_id, decl); + export_type(decl_id, decl); } } } From c44f72b74d7c58fa3dba8358c13083aa050fecaa Mon Sep 17 00:00:00 2001 From: fw Date: Mon, 3 Nov 2025 10:06:16 -0500 Subject: [PATCH 04/13] transpile: add some logging for import generation --- c2rust-transpile/src/translator/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 5898276fd4..d4caf7edcd 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -664,6 +664,14 @@ pub fn translate( if t.tcfg.reorganize_definitions && decl_file_id.map_or(false, |id| id != t.main_file) { + let name: Option<&String> = t + .ast_context + .get_decl(&decl_id) + .and_then(|x| x.kind.get_name()); + log::debug!( + "emitting submodule imports for exported type {}", + name.unwrap_or(&"unknown".to_owned()) + ); t.generate_submodule_imports(decl_id, decl_file_id); } }; @@ -771,6 +779,7 @@ pub fn translate( }; if t.tcfg.reorganize_definitions && decl_file_id.map_or(false, |id| id != t.main_file) { + log::debug!("emitting any imports needed by {:?}", decl.kind.get_name()); t.generate_submodule_imports(*top_id, decl_file_id); } } From ea238031ab48f11e08aca80fa8211cbbb8c25944 Mon Sep 17 00:00:00 2001 From: fw Date: Mon, 3 Nov 2025 10:06:38 -0500 Subject: [PATCH 05/13] transpile: document `make_submodule` --- c2rust-transpile/src/translator/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index d4caf7edcd..b2473a0858 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -995,6 +995,8 @@ fn foreign_item_ident_vis(fi: &ForeignItem) -> Option<(&Ident, Visibility)> { }) } +/// Create a submodule containing the items in `item_store`. Populates `use_item_store` with the set +/// of `use`s to import the submodule's exports. fn make_submodule( ast_context: &TypedAstContext, item_store: &mut ItemStore, From 0d84c1dde3d845f2314d6c7067993bcae299108a Mon Sep 17 00:00:00 2001 From: fw Date: Mon, 3 Nov 2025 10:07:14 -0500 Subject: [PATCH 06/13] transpile: factor out cloning of module path --- c2rust-transpile/src/translator/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index b2473a0858..ffd9310cca 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -1011,13 +1011,13 @@ fn make_submodule( .get_file_include_line_number(file_id) .unwrap_or(0); let mod_name = clean_path(mod_names, file_path); + let use_path = || vec!["self".into(), mod_name.clone()]; for item in items.iter() { let ident_name = match item_ident(item) { Some(i) => i.to_string(), None => continue, }; - let use_path = vec!["self".into(), mod_name.clone()]; let vis = match item_vis(item) { Some(Visibility::Public(_)) => mk().pub_(), @@ -1025,7 +1025,7 @@ fn make_submodule( None => continue, }; - use_item_store.add_use_with_attr(false, use_path, &ident_name, vis); + use_item_store.add_use_with_attr(false, use_path(), &ident_name, vis); } for foreign_item in foreign_items.iter() { @@ -1033,9 +1033,8 @@ fn make_submodule( Some((ident, _vis)) => ident.to_string(), None => continue, }; - let use_path = vec!["self".into(), mod_name.clone()]; - use_item_store.add_use(false, use_path, &ident_name); + use_item_store.add_use(false, use_path(), &ident_name); } for item in uses.into_items() { From ff53350b94297a638982c576a958d7b9942b1982 Mon Sep 17 00:00:00 2001 From: fw Date: Mon, 3 Nov 2025 10:08:44 -0500 Subject: [PATCH 07/13] transpile: add submodule's reexports to consumers' import set other exports from the submodule (for types it defines via enum/struct definitions) are already added to this set, but reexports were not. this meant that if we organized imports of std/core types into a submodule (which the transpiler itself does when `--reorganize-definitions` is passed), these imports would then be missing from the main module. --- c2rust-transpile/src/translator/mod.rs | 55 +++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index ffd9310cca..f23418a4ab 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -18,7 +18,7 @@ use syn::{ ForeignItemStatic, ForeignItemType, Ident, Item, ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod, ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Lit, MacroDelimiter, PathSegment, ReturnType, - Stmt, Type, TypeTuple, Visibility, + Stmt, Type, TypeTuple, UseTree, Visibility, }; use syn::{BinOp, UnOp}; // To override `c_ast::{BinOp,UnOp}` from glob import. @@ -916,6 +916,42 @@ pub fn translate( } } +/// Represent the set of names made visible by a `use`: either a set of specific names, or a glob. +enum IdentsOrGlob<'a> { + Idents(Vec<&'a Ident>), + Glob, +} + +impl<'a> IdentsOrGlob<'a> { + fn join(self, other: Self) -> Self { + use IdentsOrGlob::*; + match (self, other) { + (Glob, _) => Glob, + (_, Glob) => Glob, + (Idents(mut own), Idents(other)) => Idents({ + own.extend(other.into_iter()); + own + }), + } + } +} + +/// Extract the set of names made visible by a `use`. +fn use_idents<'a>(i: &'a UseTree) -> IdentsOrGlob<'a> { + match i { + UseTree::Path(up) => use_idents(&up.tree), + UseTree::Name(un) => IdentsOrGlob::Idents(vec![&un.ident]), + UseTree::Rename(ur) => IdentsOrGlob::Idents(vec![&ur.rename]), + UseTree::Glob(_ugl) => IdentsOrGlob::Glob, + UseTree::Group(ugr) => ugr + .items + .iter() + .map(|tree| use_idents(tree)) + .reduce(IdentsOrGlob::join) + .unwrap_or(IdentsOrGlob::Idents(vec![])), + } +} + fn item_ident(i: &Item) -> Option<&Ident> { use Item::*; Some(match i { @@ -1037,7 +1073,24 @@ fn make_submodule( use_item_store.add_use(false, use_path(), &ident_name); } + // Consumers will `use` reexported items at their exported locations. for item in uses.into_items() { + if let Item::Use(ItemUse { + vis: Visibility::Public(_), + tree, + .. + }) = &*item + { + match use_idents(tree) { + IdentsOrGlob::Idents(idents) => { + for ident in idents { + // Add a `use` for `self::this_module::exported_name`. + use_item_store.add_use(false, use_path(), &ident.to_string()); + } + } + IdentsOrGlob::Glob => {} + } + } items.push(item); } From 0cce6b8e8e053e478e659daa821a4b72f991425e Mon Sep 17 00:00:00 2001 From: fw Date: Mon, 3 Nov 2025 20:34:05 -0500 Subject: [PATCH 08/13] transpile: `use` built-in SIMD items from stdlib, not via reexports these will have `use`s added unconditionally with the stdlib path if the main module uses them directly, so in order to allow deduplication without tracing through reexports, we should have the main module import these from their original (stdlib) location, not the reexported one --- c2rust-transpile/src/translator/mod.rs | 21 +++++++++++++++++++-- c2rust-transpile/src/translator/simd.rs | 2 +- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index f23418a4ab..57175b5cfb 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -1084,8 +1084,25 @@ fn make_submodule( match use_idents(tree) { IdentsOrGlob::Idents(idents) => { for ident in idents { - // Add a `use` for `self::this_module::exported_name`. - use_item_store.add_use(false, use_path(), &ident.to_string()); + fn is_simd_type_name(name: &str) -> bool { + const SIMD_TYPE_NAMES: &[&str] = &[ + "__m128i", "__m128", "__m128d", "__m64", "__m256", "__m256d", + "__m256i", + ]; + SIMD_TYPE_NAMES.contains(&name) || name.starts_with("_mm_") + } + let name = &*ident.to_string(); + if is_simd_type_name(name) { + // Import vector type/operation names from the stdlib, as we also generate + // other uses for them from that location and can't easily reason about + // the ultimate target of reexported names when avoiding duplicate imports + // (which are verboten). + simd::add_arch_use(use_item_store, "x86", name); + simd::add_arch_use(use_item_store, "x86_64", name); + } else { + // Add a `use` for `self::this_module::exported_name`. + use_item_store.add_use(false, use_path(), name); + } } } IdentsOrGlob::Glob => {} diff --git a/c2rust-transpile/src/translator/simd.rs b/c2rust-transpile/src/translator/simd.rs index 47a0ba753f..78d57fd65c 100644 --- a/c2rust-transpile/src/translator/simd.rs +++ b/c2rust-transpile/src/translator/simd.rs @@ -67,7 +67,7 @@ static SIMD_X86_64_ONLY: &[&str] = &[ "_mm_crc32_u64", ]; -fn add_arch_use(store: &mut ItemStore, arch_name: &str, item_name: &str) { +pub fn add_arch_use(store: &mut ItemStore, arch_name: &str, item_name: &str) { store.add_use_with_attr( true, vec!["core".into(), "arch".into(), arch_name.into()], From 38060b697c5f3f530756a8240d2316854136133c Mon Sep 17 00:00:00 2001 From: fw Date: Mon, 3 Nov 2025 20:35:32 -0500 Subject: [PATCH 09/13] transpile: deduplicate imports from main module itself vs. submodules --- c2rust-transpile/src/rust_ast/item_store.rs | 18 ++++++++++++++++++ c2rust-transpile/src/translator/mod.rs | 5 ++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/c2rust-transpile/src/rust_ast/item_store.rs b/c2rust-transpile/src/rust_ast/item_store.rs index 1629c49217..0f4bb200e2 100644 --- a/c2rust-transpile/src/rust_ast/item_store.rs +++ b/c2rust-transpile/src/rust_ast/item_store.rs @@ -78,6 +78,24 @@ impl PathedMultiImports { }) .collect() } + + /// Remove all imports covered by the other `PathedMultiImports`. + pub fn remove(&mut self, other: &PathedMultiImports) { + for (k, v) in &mut self.0 { + // We don't consider attributes, just subtract leaf sets. + let other_items = other + .0 + .get(k) + .map(|imports| { + imports + .leaves + .iter() + .collect::>() + }) + .unwrap_or_default(); + v.leaves.retain(|leaf| !other_items.contains(leaf)); + } + } } #[derive(Debug, Default)] diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 57175b5cfb..2ab0ca5eb0 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -879,6 +879,10 @@ pub fn translate( all_items.extend(mod_items); + // Before consuming `uses`, remove them from the uses from submodules to avoid duplicates. + let (_, _, mut new_uses) = new_uses.drain(); + new_uses.remove(&uses); + // This could have been merged in with items below; however, it's more idiomatic to have // imports near the top of the file than randomly scattered about. Also, there is probably // no reason to have comments associated with imports so it doesn't need to go through @@ -886,7 +890,6 @@ pub fn translate( all_items.extend(uses.into_items()); // Print new uses from submodules - let (_, _, new_uses) = new_uses.drain(); all_items.extend(new_uses.into_items()); if !foreign_items.is_empty() { From 86293910f7b17f88a56c84c5a44f78b3f9548806 Mon Sep 17 00:00:00 2001 From: fw Date: Mon, 3 Nov 2025 21:43:07 -0500 Subject: [PATCH 10/13] transpile: import struct/union names when creating their literals --- c2rust-transpile/src/translator/literals.rs | 4 ++++ c2rust-transpile/src/translator/structs.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/c2rust-transpile/src/translator/literals.rs b/c2rust-transpile/src/translator/literals.rs index 4011c30b67..d7c83af7e7 100644 --- a/c2rust-transpile/src/translator/literals.rs +++ b/c2rust-transpile/src/translator/literals.rs @@ -334,6 +334,10 @@ impl<'c> Translation<'c> { .borrow() .resolve_decl_name(union_id) .unwrap(); + if let Some(cur_file) = self.cur_file.get() { + log::debug!("in file {cur_file} importing union {union_name}, id {union_id:?}"); + self.add_import(cur_file, union_id, &union_name); + } match self.ast_context.index(union_field_id).kind { CDeclKind::Field { typ: field_ty, .. } => { let val = if ids.is_empty() { diff --git a/c2rust-transpile/src/translator/structs.rs b/c2rust-transpile/src/translator/structs.rs index f76e0562c3..07270053e2 100644 --- a/c2rust-transpile/src/translator/structs.rs +++ b/c2rust-transpile/src/translator/structs.rs @@ -398,6 +398,10 @@ impl<'a> Translation<'a> { field_expr_ids: &[CExprId], ) -> TranslationResult>> { let name = self.resolve_decl_inner_name(struct_id); + if let Some(cur_file) = self.cur_file.get() { + log::debug!("in file {cur_file} importing struct {name}, id {struct_id:?}"); + self.add_import(cur_file, struct_id, &name); + } let (field_decl_ids, platform_byte_size) = match self.ast_context.index(struct_id).kind { CDeclKind::Struct { From 584b50b81f117c005addeeaa6d1e6bf576a2cec5 Mon Sep 17 00:00:00 2001 From: fw Date: Tue, 4 Nov 2025 00:25:05 -0500 Subject: [PATCH 11/13] transpile: disable caching zero initializers computing these is impure because it can call `import_type`. ideally we would not disable this caching but instead cache both the initializer and its set of required imports. --- c2rust-transpile/src/translator/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 2ab0ca5eb0..7a338ba412 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -4996,10 +4996,11 @@ impl<'c> Translation<'c> { self.import_type(type_id, file_id); } + // Caching skips critical side effect of `import_type` call. // Look up the decl in the cache and return what we find (if we find anything) - if let Some(init) = self.zero_inits.borrow().get(&decl_id) { + /*if let Some(init) = self.zero_inits.borrow().get(&decl_id) { return Ok(init.clone()); - } + }*/ let name_decl_id = match self.ast_context.index(type_id).kind { CTypeKind::Typedef(decl_id) => decl_id, From 481c6d7d8013b9857c96686e1f7f68bc81433f3b Mon Sep 17 00:00:00 2001 From: fw Date: Wed, 8 Oct 2025 10:32:44 -0400 Subject: [PATCH 12/13] Revert "break c2rust dependency on c2rust-refactor" This reverts commit 2bd339d92e1112faa4baf97e295223804b294d67. --- Cargo.lock | 1 + c2rust-transpile/src/lib.rs | 39 ++++++++++++++++++- c2rust/Cargo.toml | 2 + .../src/bin/c2rust-refactor.rs | 11 +++++- c2rust/src/main.rs | 2 +- {c2rust-refactor => c2rust}/src/refactor.yaml | 0 6 files changed, 50 insertions(+), 5 deletions(-) rename {c2rust-refactor => c2rust}/src/bin/c2rust-refactor.rs (97%) rename {c2rust-refactor => c2rust}/src/refactor.yaml (100%) diff --git a/Cargo.lock b/Cargo.lock index 7a734b069f..b87124c6c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -275,6 +275,7 @@ version = "0.21.0" dependencies = [ "anyhow", "c2rust-build-paths", + "c2rust-refactor", "c2rust-transpile", "clap 3.2.25", "env_logger 0.10.0", diff --git a/c2rust-transpile/src/lib.rs b/c2rust-transpile/src/lib.rs index e94ab9ecb8..4c5a67a669 100644 --- a/c2rust-transpile/src/lib.rs +++ b/c2rust-transpile/src/lib.rs @@ -464,8 +464,43 @@ fn get_extra_args_macos() -> Vec { args } -fn invoke_refactor(_build_dir: &Path) -> Result<(), Error> { - Ok(()) +fn invoke_refactor(build_dir: &Path) -> Result<(), Error> { + // Make sure the crate builds cleanly + let status = process::Command::new("cargo") + .args(&["check"]) + .env("RUSTFLAGS", "-Awarnings") + .current_dir(build_dir) + .status()?; + if !status.success() { + return Err(failure::format_err!("Crate does not compile.")); + } + + // Assumes the subcommand executable is in the same directory as this program. + let cmd_path = std::env::current_exe().expect("Cannot get current executable path"); + let mut cmd_path = cmd_path.as_path().canonicalize().unwrap(); + cmd_path.pop(); // remove current executable + cmd_path.push(format!("c2rust-refactor")); + assert!(cmd_path.exists(), "{:?} is missing", cmd_path); + let args = [ + "--cargo", + "--rewrite-mode", + "inplace", + "rename_unnamed", + ";", + "reorganize_definitions", + ]; + let status = process::Command::new(cmd_path.into_os_string()) + .args(&args) + .current_dir(build_dir) + .status()?; + if status.success() { + Ok(()) + } else { + Err(failure::format_err!( + "Refactoring failed. Please fix errors above and re-run:\n c2rust refactor {}", + args.join(" "), + )) + } } fn reorganize_definitions( diff --git a/c2rust/Cargo.toml b/c2rust/Cargo.toml index 6058f200a4..688a248a79 100644 --- a/c2rust/Cargo.toml +++ b/c2rust/Cargo.toml @@ -21,6 +21,7 @@ log = "0.4" regex = "1.3" shlex = "1.3" c2rust-transpile = { version = "0.21.0", path = "../c2rust-transpile" } +c2rust-refactor = { version = "0.21.0", path = "../c2rust-refactor" } [build-dependencies] c2rust-build-paths = { path = "../c2rust-build-paths", version = "0.21.0" } @@ -28,3 +29,4 @@ c2rust-build-paths = { path = "../c2rust-build-paths", version = "0.21.0" } [features] # Force static linking of LLVM llvm-static = ["c2rust-transpile/llvm-static"] +profile = ["c2rust-refactor/profile"] diff --git a/c2rust-refactor/src/bin/c2rust-refactor.rs b/c2rust/src/bin/c2rust-refactor.rs similarity index 97% rename from c2rust-refactor/src/bin/c2rust-refactor.rs rename to c2rust/src/bin/c2rust-refactor.rs index 633e948800..13701cea81 100644 --- a/c2rust-refactor/src/bin/c2rust-refactor.rs +++ b/c2rust/src/bin/c2rust-refactor.rs @@ -1,5 +1,12 @@ -use clap::{load_yaml, App, ArgMatches}; -use log::info; +extern crate env_logger; +#[macro_use] +extern crate log; +#[macro_use] +extern crate clap; +extern crate c2rust_refactor; +extern crate shlex; + +use clap::{App, ArgMatches}; use std::fs::File; use std::io::Read; use std::process; diff --git a/c2rust/src/main.rs b/c2rust/src/main.rs index 5da573a665..f4158f1d0c 100644 --- a/c2rust/src/main.rs +++ b/c2rust/src/main.rs @@ -60,7 +60,7 @@ impl SubCommand { /// Get all known [`SubCommand`]s. These have no [`SubCommand::path`]. /// Even if the subcommand executables aren't there, we can still suggest them. pub fn known() -> impl Iterator { - ["transpile", "instrument", "pdg", "analyze"] + ["transpile", "refactor", "instrument", "pdg", "analyze"] .into_iter() .map(|name| Self { path: None, diff --git a/c2rust-refactor/src/refactor.yaml b/c2rust/src/refactor.yaml similarity index 100% rename from c2rust-refactor/src/refactor.yaml rename to c2rust/src/refactor.yaml From 6efb84e15a146103b35e39361b50348ce833b0a1 Mon Sep 17 00:00:00 2001 From: fw Date: Tue, 14 Oct 2025 16:40:34 -0400 Subject: [PATCH 13/13] transpile: enable `--reorganize-definitions` by default Unfortunately, we have to bend over backwards to make this work without changing CLI behavior. This adds a new `--no-reorganize-definitions` flag to disable reorganizing definitions, because it would not be backwards-compatible to add an optional argument for the flag (it would eat a following argument that would previously be unassociated with the flag). --- c2rust/src/bin/c2rust-transpile.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/c2rust/src/bin/c2rust-transpile.rs b/c2rust/src/bin/c2rust-transpile.rs index 890664447b..82f3e8ddbb 100644 --- a/c2rust/src/bin/c2rust-transpile.rs +++ b/c2rust/src/bin/c2rust-transpile.rs @@ -124,9 +124,17 @@ struct Args { #[clap(long)] reduce_type_annotations: bool, - /// Output file in such a way that the refactoring tool can deduplicate code - #[clap(short = 'r', long)] - reorganize_definitions: bool, + /// Disable `--reorganize-definitions` + #[clap(long = "no-reorganize-definitions", hidden = true, action = clap::ArgAction::SetFalse)] + reorganize_definitions: bool, // NB, this *is* the right field; this flag sets it to *false*. + + /// Output file in such a way that the refactoring tool can deduplicate code (enabled by default; disable with `--no-reorganize-definitions`) + #[clap( + short = 'r', + long = "reorganize-definitions", + conflicts_with = "reorganize-definitions" + )] + _no_reorganize_definitions: bool, // Field is unused, but flag mutually excludes the negative sense above. /// Extra arguments to pass to clang frontend during parsing the input C file #[clap(multiple = true, last(true))]