From dc051c62b0c5d002d6090d9e2d7b5e9c89caf910 Mon Sep 17 00:00:00 2001 From: Rua Date: Thu, 14 May 2026 15:45:25 +0200 Subject: [PATCH 1/7] transpile: Rename `Translation::macro_expansions` to reduce confusion with AST --- c2rust-transpile/src/translator/macros.rs | 20 ++++++++++---------- c2rust-transpile/src/translator/mod.rs | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index 148e60a199..c62c179cab 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) } @@ -168,10 +168,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 expansion = self.macro_expansions.borrow().get(macro_id).cloned(); - let macro_ty = match expansion { + let converted = self.converted_macros.borrow().get(macro_id).cloned(); + let macro_ty = match converted { // Expansion exists. - Some(Some(expansion)) => expansion.ty, + Some(Some(converted)) => converted.ty, // Expansion wasn't possible. Some(None) => return Ok(None), @@ -179,8 +179,8 @@ impl<'c> Translation<'c> { // We haven't tried to expand it yet. None => { self.convert_decl(ctx, *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 d4bfb88c37..96add6b448 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -261,7 +261,7 @@ impl FuncContext { } #[derive(Clone)] -struct MacroExpansion { +struct ConvertedMacro { ty: CTypeId, } @@ -283,7 +283,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 @@ -1508,7 +1508,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()), comment_context, comment_store: RefCell::new(CommentStore::new()), @@ -4324,8 +4324,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 7fdc8cf7b3005dbc4ce1b6891936ba5953745c0c Mon Sep 17 00:00:00 2001 From: Rua Date: Thu, 14 May 2026 18:00:42 +0200 Subject: [PATCH 2/7] transpile: Rename `ExprContext::expanding_macro` to `converting_macro` --- c2rust-transpile/src/translator/literals.rs | 2 +- c2rust-transpile/src/translator/macros.rs | 4 ++-- c2rust-transpile/src/translator/mod.rs | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/c2rust-transpile/src/translator/literals.rs b/c2rust-transpile/src/translator/literals.rs index e1bfeca9f3..f17f461a71 100644 --- a/c2rust-transpile/src/translator/literals.rs +++ b/c2rust-transpile/src/translator/literals.rs @@ -166,7 +166,7 @@ impl<'c> Translation<'c> { ) -> TranslationResult>> { // C compound literals are lvalues, but equivalent Rust expressions generally are not. // So if an address is needed, store it in an intermediate variable first. - if !ctx.needs_address() || ctx.expanding_macro.is_some() { + if !ctx.needs_address() || ctx.converting_macro.is_some() { return self.convert_expr(ctx, val, override_ty); } diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index c62c179cab..a12afee584 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -25,7 +25,7 @@ impl<'c> Translation<'c> { ); let maybe_replacement = self.recreate_const_macro_from_expansions( - ctx.const_().set_expanding_macro(decl_id), + ctx.const_().set_converting_macro(decl_id), &self.ast_context.macro_expansions[&decl_id], ); @@ -157,7 +157,7 @@ impl<'c> Translation<'c> { // Find the first macro after the macro we're currently expanding, if any. let first_macro = macros - .splitn(2, |macro_id| ctx.expanding_macro(macro_id)) + .splitn(2, |macro_id| ctx.is_converting_macro(macro_id)) .last() .unwrap() .first(); diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 96add6b448..ba286f7d2e 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -143,7 +143,7 @@ pub struct ExprContext { needs_address: bool, ternary_needs_parens: bool, - expanding_macro: Option, + converting_macro: Option, } impl ExprContext { @@ -212,15 +212,15 @@ impl ExprContext { } /// Are we expanding the given macro in the current context? - pub fn expanding_macro(&self, mac: &CDeclId) -> bool { - match self.expanding_macro { + pub fn is_converting_macro(&self, mac: &CDeclId) -> bool { + match self.converting_macro { Some(expanding) => expanding == *mac, None => false, } } - pub fn set_expanding_macro(self, mac: CDeclId) -> Self { + pub fn set_converting_macro(self, mac: CDeclId) -> Self { ExprContext { - expanding_macro: Some(mac), + converting_macro: Some(mac), ..self } } @@ -694,7 +694,7 @@ pub fn translate( is_bitfield_write: false, needs_address: false, ternary_needs_parens: false, - expanding_macro: None, + converting_macro: None, }; { @@ -3008,7 +3008,7 @@ impl<'c> Translation<'c> { .get_decl(&decl_id) .ok_or_else(|| format_err!("Missing declref {:?}", decl_id))? .kind; - if ctx.expanding_macro.is_some() { + if ctx.converting_macro.is_some() { // TODO Determining which declarations have been declared within the scope of the const macro expr // vs. which are out-of-scope of the const macro is non-trivial, // so for now, we don't allow const macros referencing any declarations. From 0c83f535e977a48e6592cab3d39ec864297269d1 Mon Sep 17 00:00:00 2001 From: Rua Date: Fri, 15 May 2026 11:26:58 +0200 Subject: [PATCH 3/7] transpile: Rename `ConvertedMacro::ty` to `result_type_id` --- c2rust-transpile/src/translator/macros.rs | 16 ++++++++-------- c2rust-transpile/src/translator/mod.rs | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index a12afee584..0757b10b4b 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -30,18 +30,18 @@ impl<'c> Translation<'c> { ); match maybe_replacement { - Ok((replacement, ty)) => { + Ok((replacement, result_type_id)) => { trace!(" to {:?}", replacement); - let converted = ConvertedMacro { ty }; + let converted = ConvertedMacro { result_type_id }; self.converted_macros .borrow_mut() .insert(decl_id, Some(converted)); - let ty = self.convert_type(ty)?; + let result_type_rs = self.convert_type(result_type_id)?; Ok(ConvertedDecl::Item(mk().span(span).pub_().const_item( name, - ty, + result_type_rs, replacement, ))) } @@ -169,9 +169,9 @@ 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 result_type_id = match converted { // Expansion exists. - Some(Some(converted)) => converted.ty, + Some(Some(converted)) => converted.result_type_id, // Expansion wasn't possible. Some(None) => return Ok(None), @@ -180,7 +180,7 @@ impl<'c> Translation<'c> { None => { self.convert_decl(ctx, *macro_id)?; if let Some(Some(converted)) = self.converted_macros.borrow().get(macro_id) { - converted.ty + converted.result_type_id } else { return Ok(None); } @@ -206,7 +206,7 @@ impl<'c> Translation<'c> { if let Some(expr_ty) = expr_ty { self.convert_cast( ctx, - CQualTypeId::new(macro_ty), + CQualTypeId::new(result_type_id), expr_ty, val, None, diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index ba286f7d2e..64babf7f18 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -262,7 +262,7 @@ impl FuncContext { #[derive(Clone)] struct ConvertedMacro { - ty: CTypeId, + result_type_id: CTypeId, } type ZeroInits = IndexMap>, IndexSet)>; @@ -4325,7 +4325,7 @@ impl<'c> Translation<'c> { CDeclKind::MacroObject { .. } => { if let Some(Some(converted)) = self.converted_macros.borrow().get(&decl_id) { - add_use_items_for_type(converted.ty) + add_use_items_for_type(converted.result_type_id) } } From 0ee31ae404d1cfc49da3ff90044661a26e7dc52a Mon Sep 17 00:00:00 2001 From: Rua Date: Thu, 14 May 2026 22:28:13 +0200 Subject: [PATCH 4/7] transpile: Refactor `recreate_const_macro_from_expansions` --- c2rust-transpile/src/translator/macros.rs | 66 ++++++++++++++--------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index 0757b10b4b..76e5326057 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -71,35 +71,51 @@ impl<'c> Translation<'c> { ) -> TranslationResult<(Box, CTypeId)> { let (val, ty) = expansions .iter() - .try_fold::>, CTypeId)>, _, _>(None, |canonical, &id| { - self.can_convert_const_macro_expansion(id)?; + .try_fold::>, CTypeId)>, _, _>( + None, + |mut canonical, &expr_id| -> TranslationResult<_> { + self.can_convert_const_macro_expansion(expr_id)?; + + let type_id = self.ast_context[expr_id] + .kind + .get_type() + .ok_or_else(|| format_err!("Invalid expression type"))?; + let val = self.convert_expr(ctx, expr_id, None)?; + let new = (val, type_id); - let ty = self.ast_context[id] - .kind - .get_type() - .ok_or_else(|| format_err!("Invalid expression type"))?; - let expr = self.convert_expr(ctx, id, None)?; + // Join ty and cur_ty to the smaller of the two types. If the + // types are not cast-compatible, abort the fold. + match &mut canonical { + Some(canonical) => { + let &mut (_, canon_type_id) = canonical; + let (_, new_type_id) = new; - // 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(); - 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))) - } else { - Ok(Some((expr, ty))) + let canon_type_kind = + self.ast_context.resolve_type(canon_type_id).kind.clone(); + let new_type_kind = + self.ast_context.resolve_type(new_type_id).kind.clone(); + let smaller_type_kind = CTypeKind::smaller_compatible_type( + canon_type_kind.clone(), + new_type_kind, + ); + let Some(smaller_type_kind) = smaller_type_kind else { + return Err( + format_err!("Not all macro expansions are compatible types") + .into() + ) + }; + + if smaller_type_kind != canon_type_kind { + *canonical = new; + } } - } else { - Err(format_err!("Not all macro expansions are compatible types")) + + None => canonical = Some(new), } - } else { - Ok(Some((expr, ty))) - } - })? + + Ok(canonical) + }, + )? .ok_or_else(|| format_err!("Could not find a valid type for macro"))?; val.wrap_unsafe() From 4f73b6ee8677e77831cb80e88c9356740665714a Mon Sep 17 00:00:00 2001 From: Rua Date: Fri, 15 May 2026 11:23:04 +0200 Subject: [PATCH 5/7] transpile: Refactor `convert_const_macro_expansion` to avoid cloning --- c2rust-transpile/src/translator/macros.rs | 40 +++++++++++++---------- c2rust-transpile/src/translator/mod.rs | 1 - 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index 76e5326057..75c2ffeb42 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -173,9 +173,9 @@ impl<'c> Translation<'c> { // Find the first macro after the macro we're currently expanding, if any. let first_macro = macros - .splitn(2, |macro_id| ctx.is_converting_macro(macro_id)) - .last() - .unwrap() + .iter() + .position(|macro_id| ctx.is_converting_macro(macro_id)) + .map_or(macros, |index| ¯os[index + 1..]) .first(); let macro_id = match first_macro { Some(macro_id) => macro_id, @@ -183,25 +183,29 @@ 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 result_type_id = match converted { - // Expansion exists. - Some(Some(converted)) => converted.result_type_id, - // Expansion wasn't possible. - Some(None) => return Ok(None), + use std::cell::Ref; + let get_converted = || -> Option>> { + Ref::filter_map(self.converted_macros.borrow(), |converted_macros| { + converted_macros.get(macro_id) + }) + .ok() + .map(|val| Ref::filter_map(val, Option::as_ref).ok()) + }; + // Ensure that we've converted this macro and that it has a valid definition. + let mut converted = get_converted(); + if converted.is_none() { // We haven't tried to expand it yet. - None => { - self.convert_decl(ctx, *macro_id)?; - if let Some(Some(converted)) = self.converted_macros.borrow().get(macro_id) { - converted.result_type_id - } else { - return Ok(None); - } - } + self.convert_decl(ctx, *macro_id)?; + converted = get_converted(); + } + let Some(Some(converted)) = converted else { + // Expansion wasn't possible. + return Ok(None); }; + + let result_type_id = converted.result_type_id; let rust_name = self .renamer .borrow_mut() diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 64babf7f18..645a633645 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -260,7 +260,6 @@ impl FuncContext { } } -#[derive(Clone)] struct ConvertedMacro { result_type_id: CTypeId, } From 8ab82ece53ce4560578586db4abd9654dd9d1f6f Mon Sep 17 00:00:00 2001 From: Rua Date: Fri, 15 May 2026 11:33:24 +0200 Subject: [PATCH 6/7] transpile: Return `ConvertedMacro` from `recreate_const_macro_from_expansions` --- c2rust-transpile/src/translator/macros.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index 75c2ffeb42..0f374c5ab4 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, result_type_id)) => { + Ok((replacement, converted)) => { trace!(" to {:?}", replacement); - let converted = ConvertedMacro { result_type_id }; + let result_type_rs = self.convert_type(converted.result_type_id)?; self.converted_macros .borrow_mut() .insert(decl_id, Some(converted)); - let result_type_rs = self.convert_type(result_type_id)?; Ok(ConvertedDecl::Item(mk().span(span).pub_().const_item( name, @@ -68,8 +67,8 @@ impl<'c> Translation<'c> { &self, ctx: ExprContext, expansions: &[CExprId], - ) -> TranslationResult<(Box, CTypeId)> { - let (val, ty) = expansions + ) -> TranslationResult<(Box, ConvertedMacro)> { + let (val, result_type_id) = expansions .iter() .try_fold::>, CTypeId)>, _, _>( None, @@ -118,9 +117,10 @@ impl<'c> Translation<'c> { )? .ok_or_else(|| format_err!("Could not find a valid type for macro"))?; + let converted = ConvertedMacro { result_type_id }; 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 8ee6a65e5b4275d2b63297237fdeba93479cc5a0 Mon Sep 17 00:00:00 2001 From: Rua Date: Fri, 15 May 2026 13:45:09 +0200 Subject: [PATCH 7/7] transpile: Allow macro conversion to succeed only for some expansions --- c2rust-transpile/src/translator/macros.rs | 124 ++++++++++++++-------- c2rust-transpile/src/translator/mod.rs | 1 + 2 files changed, 79 insertions(+), 46 deletions(-) diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index 0f374c5ab4..7345623f28 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -1,10 +1,11 @@ use c2rust_ast_builder::mk; use failure::format_err; +use indexmap::IndexMap; use log::{info, trace}; use proc_macro2::{Span, TokenStream}; use syn::{Expr, MacroDelimiter}; -use crate::c_ast::{CDeclId, CExprId, CQualTypeId, CTypeId, CTypeKind}; +use crate::c_ast::{CDeclId, CExprId, CQualTypeId, CTypeKind}; use crate::diagnostics::{TranslationError, TranslationResult}; use crate::translator::{ConvertedDecl, ConvertedMacro, ExprContext, Translation}; use crate::with_stmts::WithStmts; @@ -33,6 +34,15 @@ impl<'c> Translation<'c> { Ok((replacement, converted)) => { trace!(" to {:?}", replacement); + for (expr_id, result) in &converted.expr_results { + if let Err(err) = result { + info!( + "Could not convert macro {} for {:?}: {}", + name, expr_id, err + ); + } + } + let result_type_rs = self.convert_type(converted.result_type_id)?; self.converted_macros .borrow_mut() @@ -46,7 +56,7 @@ impl<'c> Translation<'c> { } Err(e) => { self.converted_macros.borrow_mut().insert(decl_id, None); - info!("Could not expand macro {}: {}", name, e); + info!("Could not convert macro {}: {}", name, e); Ok(ConvertedDecl::NoItem) } } @@ -68,56 +78,73 @@ impl<'c> Translation<'c> { ctx: ExprContext, expansions: &[CExprId], ) -> TranslationResult<(Box, ConvertedMacro)> { - let (val, result_type_id) = expansions + let mut canonical = None; + let mut expr_results: IndexMap<_, _> = expansions .iter() - .try_fold::>, CTypeId)>, _, _>( - None, - |mut canonical, &expr_id| -> TranslationResult<_> { - self.can_convert_const_macro_expansion(expr_id)?; - - let type_id = self.ast_context[expr_id] - .kind - .get_type() - .ok_or_else(|| format_err!("Invalid expression type"))?; - let val = self.convert_expr(ctx, expr_id, None)?; - let new = (val, type_id); - - // Join ty and cur_ty to the smaller of the two types. If the - // types are not cast-compatible, abort the fold. - match &mut canonical { - Some(canonical) => { - let &mut (_, canon_type_id) = canonical; - let (_, new_type_id) = new; - - let canon_type_kind = - self.ast_context.resolve_type(canon_type_id).kind.clone(); - let new_type_kind = - self.ast_context.resolve_type(new_type_id).kind.clone(); - let smaller_type_kind = CTypeKind::smaller_compatible_type( - canon_type_kind.clone(), - new_type_kind, - ); - let Some(smaller_type_kind) = smaller_type_kind else { - return Err( - format_err!("Not all macro expansions are compatible types") - .into() - ) - }; - - if smaller_type_kind != canon_type_kind { - *canonical = new; + .map(|&expr_id| { + let result = self + .can_convert_const_macro_expansion(expr_id) + .and_then(|_| { + let type_id = self.ast_context[expr_id] + .kind + .get_type() + .ok_or_else(|| format_err!("Invalid expression type"))?; + let val = self.convert_expr(ctx, expr_id, None)?; + Ok((val, type_id)) + }) + .and_then(|new| { + // Join ty and cur_ty to the smaller of the two types. If the + // types are not cast-compatible, skip this expansion. + match &mut canonical { + Some(canonical) => { + let &mut (_, canon_type_id) = canonical; + let (_, new_type_id) = new; + + let canon_type_kind = + self.ast_context.resolve_type(canon_type_id).kind.clone(); + let new_type_kind = + self.ast_context.resolve_type(new_type_id).kind.clone(); + let smaller_type_kind = CTypeKind::smaller_compatible_type( + canon_type_kind.clone(), + new_type_kind, + ); + let Some(smaller_type_kind) = smaller_type_kind else { + return Err( + format_err!( + "Not all macro expansions are compatible types" + ) + .into() + ) + }; + + if smaller_type_kind != canon_type_kind { + *canonical = new; + } } + + None => canonical = Some(new), } - None => canonical = Some(new), - } + Ok(()) + }); - Ok(canonical) - }, - )? - .ok_or_else(|| format_err!("Could not find a valid type for macro"))?; + (expr_id, result) + }) + .collect(); + + let Some((val, result_type_id)) = canonical else { + // If none of the expansions could be converted, try returning the first error we got. + let err = match expr_results.swap_remove_index(0) { + Some((_, Err(err))) => err, + _ => format_err!("Could not find a valid type for macro").into(), + }; + return Err(err); + }; - let converted = ConvertedMacro { result_type_id }; + let converted = ConvertedMacro { + result_type_id, + expr_results, + }; val.wrap_unsafe() .to_pure_expr() .map(|val| (val, converted)) @@ -205,6 +232,11 @@ impl<'c> Translation<'c> { return Ok(None); }; + if !matches!(converted.expr_results.get(&expr_id), Some(Ok(_))) { + // Expansion succeeded in general, but not for this particular expression. + return Ok(None); + } + let result_type_id = converted.result_type_id; let rust_name = self .renamer diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 645a633645..1da486bda1 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -262,6 +262,7 @@ impl FuncContext { struct ConvertedMacro { result_type_id: CTypeId, + expr_results: IndexMap>, } type ZeroInits = IndexMap>, IndexSet)>;