From f3051f95d9ba35b79f7eb177f580809001a87610 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 8 Aug 2026 18:44:34 +0200 Subject: [PATCH 1/6] transpile: Add `ConvertedMacroExpr` to `recreate_const_macro_from_expansions` --- c2rust-transpile/src/translator/macros.rs | 25 +++++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index 1a66b0c0d9..e448e289c7 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -69,9 +69,14 @@ impl<'c> Translation<'c> { ctx: ExprContext, expansions: &[CExprId], ) -> TranslationResult<(Box, CTypeId)> { - let (val, ty) = expansions + struct ConvertedMacroExpr { + val: WithStmts>, + ty: CTypeId, + } + + let canonical = expansions .iter() - .try_fold::>, CTypeId)>, _, _>(None, |canonical, &id| { + .try_fold::, _, _>(None, |canonical, &id| { self.can_convert_const_macro_expansion(id)?; let ty = self @@ -80,30 +85,32 @@ impl<'c> Translation<'c> { .kind .get_type() .ok_or_else(|| format_err!("Invalid expression type"))?; - let expr = self.convert_expr(ctx, id, None)?; + let val = self.convert_expr(ctx, id, None)?; + let new = ConvertedMacroExpr { val, ty }; // Join ty and cur_ty to the smaller of the two types. If the // types are not cast-compatible, abort the fold. - let ty_kind = self.ast_context.resolve_type(ty).kind.clone(); - if let Some((canon_val, canon_ty)) = canonical { - let canon_ty_kind = self.ast_context.resolve_type(canon_ty).kind.clone(); + let ty_kind = self.ast_context.resolve_type(new.ty).kind.clone(); + if let Some(canonical) = canonical { + let canon_ty_kind = self.ast_context.resolve_type(canonical.ty).kind.clone(); if let Some(smaller_ty) = CTypeKind::smaller_compatible_type(canon_ty_kind.clone(), ty_kind) { if smaller_ty == canon_ty_kind { - Ok(Some((canon_val, canon_ty))) + Ok(Some(canonical)) } else { - Ok(Some((expr, ty))) + Ok(Some(new)) } } else { Err(format_err!("Not all macro expansions are compatible types")) } } else { - Ok(Some((expr, ty))) + Ok(Some(new)) } })? .ok_or_else(|| format_err!("Could not find a valid type for macro"))?; + let ConvertedMacroExpr { val, ty } = canonical; val.wrap_unsafe() .to_pure_expr() .map(|val| (val, ty)) From 9cd12ac1805d8edea1bfd1577673cba7a21632c2 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 8 Aug 2026 19:04:00 +0200 Subject: [PATCH 2/6] transpile: Rename `MacroExpansion` to `ConvertedMacro` to better reflect purpose --- c2rust-transpile/src/translator/macros.rs | 26 +++++++++++------------ c2rust-transpile/src/translator/mod.rs | 10 ++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index e448e289c7..868b46ad83 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -6,7 +6,7 @@ use syn::{Expr, MacroDelimiter}; use crate::c_ast::{CDeclId, CExprId, CQualTypeId, CTypeId, CTypeKind}; use crate::diagnostics::{TranslationError, TranslationResult}; -use crate::translator::{ConvertedDecl, ExprContext, MacroExpansion, Translation}; +use crate::translator::{ConvertedDecl, ConvertedMacro, ExprContext, Translation}; use crate::with_stmts::WithStmts; use crate::TranslateMacros; @@ -33,10 +33,10 @@ impl<'c> Translation<'c> { Ok((replacement, ty)) => { trace!(" to {:?}", replacement); - let expansion = MacroExpansion { ty }; - self.macro_expansions + let converted = ConvertedMacro { ty }; + self.converted_macros .borrow_mut() - .insert(decl_id, Some(expansion)); + .insert(decl_id, Some(converted)); let ty = self.convert_type(ty)?; Ok(ConvertedDecl::Item(mk().span(span).pub_().const_item( @@ -46,7 +46,7 @@ impl<'c> Translation<'c> { ))) } Err(e) => { - self.macro_expansions.borrow_mut().insert(decl_id, None); + self.converted_macros.borrow_mut().insert(decl_id, None); info!("Could not expand macro {}: {}", name, e); Ok(ConvertedDecl::NoItem) } @@ -185,19 +185,19 @@ impl<'c> Translation<'c> { trace!(" found macro expansion: {macro_id:?}"); // Ensure that we've converted this macro and that it has a valid definition. - let expansion = self.macro_expansions.borrow().get(macro_id).cloned(); - let macro_ty = match expansion { - // Expansion exists. - Some(Some(expansion)) => expansion.ty, + let converted = self.converted_macros.borrow().get(macro_id).cloned(); + let macro_ty = match converted { + // Macro was converted previously. + Some(Some(converted)) => converted.ty, - // Expansion wasn't possible. + // Macro failed to convert previously. Some(None) => return Ok(None), - // We haven't tried to expand it yet. + // We haven't tried to convert it yet. None => { self.convert_decl(ctx.not_pattern(), *macro_id)?; - if let Some(Some(expansion)) = self.macro_expansions.borrow().get(macro_id) { - expansion.ty + if let Some(Some(converted)) = self.converted_macros.borrow().get(macro_id) { + converted.ty } else { return Ok(None); } diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 4308e61bf5..3b630d5a62 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -280,7 +280,7 @@ impl FuncContext { } #[derive(Clone)] -struct MacroExpansion { +struct ConvertedMacro { ty: CTypeId, } @@ -305,7 +305,7 @@ pub struct Translation<'c> { zero_inits: RefCell, function_context: RefCell, potential_flexible_array_members: RefCell>, - macro_expansions: RefCell>>, + converted_macros: RefCell>>, /// Sets of imports deferred while translating nested expressions for caching. Imports are /// deferred when caching translations to make them pure and thus cache the translation /// alongside its required imports. Each additional nested level of caching translation @@ -1676,7 +1676,7 @@ impl<'c> Translation<'c> { zero_inits: RefCell::new(IndexMap::new()), function_context: RefCell::new(FuncContext::new()), potential_flexible_array_members: RefCell::new(IndexSet::new()), - macro_expansions: RefCell::new(IndexMap::new()), + converted_macros: RefCell::new(IndexMap::new()), deferred_imports: RefCell::new(Vec::new()), cleanup_guard_emitted: Cell::new(false), comment_context, @@ -4979,8 +4979,8 @@ impl<'c> Translation<'c> { } => add_use_items_for_type(typ), CDeclKind::MacroObject { .. } => { - if let Some(Some(expansion)) = self.macro_expansions.borrow().get(&decl_id) { - add_use_items_for_type(expansion.ty) + if let Some(Some(converted)) = self.converted_macros.borrow().get(&decl_id) { + add_use_items_for_type(converted.ty) } } From 1878806d370a8910255d0774b243fffdf012765d Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 8 Aug 2026 18:47:08 +0200 Subject: [PATCH 3/6] transpile: Return `ConvertedMacro` from `recreate_const_macro_from_expansions` --- c2rust-transpile/src/translator/macros.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index 868b46ad83..74ccf92a51 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -30,14 +30,13 @@ impl<'c> Translation<'c> { ); match maybe_replacement { - Ok((replacement, ty)) => { + Ok((replacement, converted)) => { trace!(" to {:?}", replacement); - let converted = ConvertedMacro { ty }; + let ty = self.convert_type(converted.ty)?; self.converted_macros .borrow_mut() .insert(decl_id, Some(converted)); - let ty = self.convert_type(ty)?; Ok(ConvertedDecl::Item(mk().span(span).pub_().const_item( name, @@ -68,7 +67,7 @@ impl<'c> Translation<'c> { &self, ctx: ExprContext, expansions: &[CExprId], - ) -> TranslationResult<(Box, CTypeId)> { + ) -> TranslationResult<(Box, ConvertedMacro)> { struct ConvertedMacroExpr { val: WithStmts>, ty: CTypeId, @@ -111,9 +110,10 @@ impl<'c> Translation<'c> { .ok_or_else(|| format_err!("Could not find a valid type for macro"))?; let ConvertedMacroExpr { val, ty } = canonical; + let converted = ConvertedMacro { ty }; val.wrap_unsafe() .to_pure_expr() - .map(|val| (val, ty)) + .map(|val| (val, converted)) .ok_or_else(|| TranslationError::generic("Macro expansion is not a pure expression")) // TODO: Validate that all replacements are equivalent and pick the most From be1a74a7d12d1a29cc03f1dc177cace92a40ba35 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 8 Aug 2026 18:50:09 +0200 Subject: [PATCH 4/6] transpile: Wrap `ConvertedMacro` in `Rc` instead of cloning the struct --- c2rust-transpile/src/translator/macros.rs | 3 ++- c2rust-transpile/src/translator/mod.rs | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index 74ccf92a51..367305f3f2 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -2,6 +2,7 @@ use c2rust_ast_builder::mk; use failure::format_err; use log::{info, trace}; use proc_macro2::{Span, TokenStream}; +use std::rc::Rc; use syn::{Expr, MacroDelimiter}; use crate::c_ast::{CDeclId, CExprId, CQualTypeId, CTypeId, CTypeKind}; @@ -36,7 +37,7 @@ impl<'c> Translation<'c> { let ty = self.convert_type(converted.ty)?; self.converted_macros .borrow_mut() - .insert(decl_id, Some(converted)); + .insert(decl_id, Some(Rc::new(converted))); Ok(ConvertedDecl::Item(mk().span(span).pub_().const_item( name, diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 3b630d5a62..4b9963c760 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -279,7 +279,6 @@ impl FuncContext { } } -#[derive(Clone)] struct ConvertedMacro { ty: CTypeId, } @@ -305,7 +304,7 @@ pub struct Translation<'c> { zero_inits: RefCell, function_context: RefCell, potential_flexible_array_members: RefCell>, - converted_macros: RefCell>>, + converted_macros: RefCell>>>, /// Sets of imports deferred while translating nested expressions for caching. Imports are /// deferred when caching translations to make them pure and thus cache the translation /// alongside its required imports. Each additional nested level of caching translation From 70ad58c0675f2aa290f46ca21f023403fb4ef587 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 8 Aug 2026 18:53:27 +0200 Subject: [PATCH 5/6] transpile: In `convert_const_macro_expansion`, retrieve the whole `ConvertedMacro` --- c2rust-transpile/src/translator/macros.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index 367305f3f2..935182b383 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -186,10 +186,10 @@ impl<'c> Translation<'c> { trace!(" found macro expansion: {macro_id:?}"); // Ensure that we've converted this macro and that it has a valid definition. - let converted = self.converted_macros.borrow().get(macro_id).cloned(); - let macro_ty = match converted { + let maybe_converted = self.converted_macros.borrow().get(macro_id).cloned(); + let converted = match maybe_converted { // Macro was converted previously. - Some(Some(converted)) => converted.ty, + Some(Some(converted)) => converted, // Macro failed to convert previously. Some(None) => return Ok(None), @@ -197,8 +197,9 @@ impl<'c> Translation<'c> { // We haven't tried to convert it yet. None => { self.convert_decl(ctx.not_pattern(), *macro_id)?; - if let Some(Some(converted)) = self.converted_macros.borrow().get(macro_id) { - converted.ty + let maybe_converted = self.converted_macros.borrow().get(macro_id).cloned(); + if let Some(Some(converted)) = maybe_converted { + converted } else { return Ok(None); } @@ -222,7 +223,7 @@ impl<'c> Translation<'c> { // so we need to cast it to the `override_ty` here. let expr_ty = override_ty.or_else(|| expr_kind.get_qual_type()); if let Some(expr_ty) = expr_ty { - match self.make_cast(ctx, CQualTypeId::new(macro_ty), expr_ty, val) { + match self.make_cast(ctx, CQualTypeId::new(converted.ty), expr_ty, val) { Ok(new_val) => val = new_val, Err(err) => { info!( From ccbf696a0c09aa0d8f47659ecf8d0c4f7be6b83c Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 5 Sep 2026 10:29:14 +0200 Subject: [PATCH 6/6] transpile: Fail to convert macro also if type conversion fails --- c2rust-transpile/src/translator/macros.rs | 43 +++++++++++------------ c2rust-transpile/src/translator/mod.rs | 2 +- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index 935182b383..5d9f556677 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -18,39 +18,36 @@ impl<'c> Translation<'c> { decl_id: CDeclId, span: Span, name: &str, - ) -> TranslationResult { + ) -> ConvertedDecl { trace!( "Expanding macro {:?}: {:?}", decl_id, self.ast_context[decl_id] ); - let maybe_replacement = self.recreate_const_macro_from_expansions( + self.recreate_const_macro_from_expansions( ctx.const_().set_expanding_macro(decl_id), &self.ast_context.macro_expansions[&decl_id], - ); - - match maybe_replacement { - Ok((replacement, converted)) => { - trace!(" to {:?}", replacement); + ) + .and_then(|(replacement, converted)| { + trace!(" to {:?}", replacement); - let ty = self.convert_type(converted.ty)?; - self.converted_macros - .borrow_mut() - .insert(decl_id, Some(Rc::new(converted))); + let ty = self.convert_type(converted.ty)?; + self.converted_macros + .borrow_mut() + .insert(decl_id, Some(Rc::new(converted))); - Ok(ConvertedDecl::Item(mk().span(span).pub_().const_item( - name, - ty, - replacement, - ))) - } - Err(e) => { - self.converted_macros.borrow_mut().insert(decl_id, None); - info!("Could not expand macro {}: {}", name, e); - Ok(ConvertedDecl::NoItem) - } - } + Ok(ConvertedDecl::Item(mk().span(span).pub_().const_item( + name, + ty, + replacement, + ))) + }) + .unwrap_or_else(|e| { + self.converted_macros.borrow_mut().insert(decl_id, None); + info!("Could not expand macro {}: {}", name, e); + ConvertedDecl::NoItem + }) } /// Given all of the expansions of a const macro, diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 4b9963c760..71331849e0 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -2326,7 +2326,7 @@ impl<'c> Translation<'c> { .get(&decl_id) .expect("Macro object not named"); - self.convert_macro(ctx, decl_id, span, &name) + Ok(self.convert_macro(ctx, decl_id, span, &name)) } // We aren't doing anything with the definitions of function-like