From f85ace166a5c55c94b32472f11d14d2394499b45 Mon Sep 17 00:00:00 2001 From: fw Date: Fri, 6 Mar 2026 14:53:14 -0500 Subject: [PATCH 1/3] HACK: transpile: use dashmap to enable interior mutability for `TypedAstContext::c_types` note: this is a hack because it adds a memory leak in the `Index` impl --- Cargo.lock | 11 +++++++++++ c2rust-transpile/Cargo.toml | 1 + c2rust-transpile/src/c_ast/mod.rs | 13 +++++++++---- c2rust-transpile/src/c_ast/print.rs | 4 ++-- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 78ef031bef..68ee7593eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -490,6 +490,7 @@ dependencies = [ "c2rust-bitfields", "c2rust-rust-tools", "colored 2.0.0", + "dashmap", "dtoa", "failure", "fern", @@ -967,6 +968,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "dashmap" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +dependencies = [ + "cfg-if", + "num_cpus", +] + [[package]] name = "datafrog" version = "2.0.1" diff --git a/c2rust-transpile/Cargo.toml b/c2rust-transpile/Cargo.toml index b4866c837e..672282d150 100644 --- a/c2rust-transpile/Cargo.toml +++ b/c2rust-transpile/Cargo.toml @@ -18,6 +18,7 @@ c2rust-ast-printer = { path = "../c2rust-ast-printer", version = "0.22.1" } c2rust-bitfields = { path = "../c2rust-bitfields", version = "0.22.1" } c2rust-rust-tools = { path = "../c2rust-rust-tools", version = "0.22.1" } colored = "2.0" +dashmap = "4.0" dtoa = "1.0" failure = "0.1.5" fern = { version = "0.6", features = ["colored"] } diff --git a/c2rust-transpile/src/c_ast/mod.rs b/c2rust-transpile/src/c_ast/mod.rs index c01937bf6c..ba46ebff61 100644 --- a/c2rust-transpile/src/c_ast/mod.rs +++ b/c2rust-transpile/src/c_ast/mod.rs @@ -47,7 +47,7 @@ pub type CEnumConstantId = CDeclId; // Enum's need to point to child 'DeclKind:: pub struct TypedAstContext { main_file: PathBuf, - c_types: HashMap, + c_types: dashmap::DashMap, c_exprs: HashMap, c_stmts: HashMap, @@ -1050,11 +1050,16 @@ impl TypedAstContext { use SomeId::*; match some_id { Type(type_id) => { - if let CTypeKind::Elaborated(decl_type_id) = self.c_types[&type_id].kind { + if let CTypeKind::Elaborated(decl_type_id) = + self.c_types.get(&type_id).unwrap().kind + { // This is a reference to a previously declared type. If we look // through it we should(?) get something that looks like a declaration, // which we can mark as wanted. - let decl_id = self.c_types[&decl_type_id] + let decl_id = self + .c_types + .get(&decl_type_id) + .unwrap() .kind .as_decl_or_typedef() .expect("target of CTypeKind::Elaborated isn't a decl?"); @@ -1388,7 +1393,7 @@ impl Index for TypedAstContext { fn index(&self, index: CTypeId) -> &CType { match self.c_types.get(&index) { None => panic!("Could not find {:?} in TypedAstContext", index), - Some(ty) => ty, + Some(ty) => Box::leak(Box::new(ty.clone())), } } } diff --git a/c2rust-transpile/src/c_ast/print.rs b/c2rust-transpile/src/c_ast/print.rs index 1c2c23d2df..cc4f5f2455 100644 --- a/c2rust-transpile/src/c_ast/print.rs +++ b/c2rust-transpile/src/c_ast/print.rs @@ -697,10 +697,10 @@ impl Printer { let ty = context .c_types .get(&type_id) - .map(|l| &l.kind) + .map(|l| l.kind.clone()) .unwrap_or_else(|| panic!("Could not find type with ID {:?}", type_id)); use CTypeKind::*; - match ty { + match &ty { Pointer(ref qual_ty) => { self.print_qtype(*qual_ty, None, context)?; self.writer.write_all(b"*")?; From 65c086568387b48ef2f69dfb5241abb26c2071dc Mon Sep 17 00:00:00 2001 From: fw Date: Fri, 6 Mar 2026 14:53:57 -0500 Subject: [PATCH 2/3] transpile: mint new `CTypeId`s when necessary in `TypedAstContext::type_for_kind` --- c2rust-transpile/src/c_ast/mod.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/c2rust-transpile/src/c_ast/mod.rs b/c2rust-transpile/src/c_ast/mod.rs index ba46ebff61..d96b58d31d 100644 --- a/c2rust-transpile/src/c_ast/mod.rs +++ b/c2rust-transpile/src/c_ast/mod.rs @@ -716,9 +716,26 @@ impl TypedAstContext { } pub fn type_for_kind(&self, kind: &CTypeKind) -> Option { - self.c_types + let ro = self.c_types.clone().into_read_only(); + if let Some(ty) = ro .iter() .find_map(|(id, k)| if kind == &k.kind { Some(*id) } else { None }) + { + return Some(ty); + } + let max_type_id = ro + .keys() + .max_by_key(|id| id.0) + .expect("expected non-empty AstContext::c_types"); + let new_id = CTypeId(max_type_id.0 + 1); + self.c_types.insert( + new_id, + Located { + loc: None, + kind: kind.clone(), + }, + ); + Some(new_id) } pub fn resolve_type_id(&self, typ: CTypeId) -> CTypeId { From 6e15fbf082d2dc778294a97119b5951d2d4c3829 Mon Sep 17 00:00:00 2001 From: fw Date: Fri, 6 Mar 2026 14:54:21 -0500 Subject: [PATCH 3/3] transpile: pass down modified `override_ty` for `ArrayToPointerDecay` casts --- c2rust-transpile/src/translator/mod.rs | 33 +++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index c014935ccf..4883f9b726 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3778,10 +3778,41 @@ impl<'c> Translation<'c> { return self.convert_expr(ctx, expr, override_ty); } } + if kind == CastKind::ArrayToPointerDecay && override_ty.is_some() { + let target_elem = match &self + .ast_context + .resolve_type(override_ty.unwrap().ctype) + .kind + { + CTypeKind::Pointer(qtype) => qtype.ctype, + k => panic!("ArrayToPointerDecay producing non-pointer type {k:?}"), + }; + let new_array_override_ty_kind = + match &self.ast_context.resolve_type(source_ty.ctype).kind { + CTypeKind::ConstantArray(_elem, len) => { + CTypeKind::ConstantArray(target_elem, *len) + } + CTypeKind::VariableArray(_elem, len) => { + CTypeKind::VariableArray(target_elem, *len) + } + k => panic!("ArrayToPointerDecay on non-array type {k:?}"), + }; + // + // && Some(source_ty.ctype) != override_ty.map(|x| x.ctype) + let new_array_override_ty = self + .ast_context + .type_for_kind(&new_array_override_ty_kind) + .expect(&format!( + "type id did not already exist for {:?}", + new_array_override_ty_kind + )); + + self.convert_expr(ctx, expr, Some(CQualTypeId::new(new_array_override_ty)))? + } // LValueToRValue casts don't actually change the type, so it still makes sense // to translate their inner expression with the expected type from outside the // cast. - if kind == CastKind::LValueToRValue + else if kind == CastKind::LValueToRValue && Some(source_ty.ctype) != override_ty.map(|x| x.ctype) { self.convert_expr(ctx, expr, override_ty)?