Skip to content

Commit ec60c42

Browse files
committed
transpile: Allow macro conversion to succeed only for some expansions
1 parent f8c0e92 commit ec60c42

2 files changed

Lines changed: 73 additions & 46 deletions

File tree

c2rust-transpile/src/translator/macros.rs

Lines changed: 72 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ use c2rust_ast_builder::mk;
22
use failure::format_err;
33
use log::{info, trace};
44
use proc_macro2::{Span, TokenStream};
5+
use std::collections::HashMap;
56
use syn::{Expr, MacroDelimiter};
67

7-
use crate::c_ast::{CDeclId, CExprId, CQualTypeId, CTypeId, CTypeKind};
8+
use crate::c_ast::{CDeclId, CExprId, CQualTypeId, CTypeKind};
89
use crate::diagnostics::{TranslationError, TranslationResult};
910
use crate::translator::{ConvertedDecl, ConvertedMacro, ExprContext, Translation};
1011
use crate::with_stmts::WithStmts;
@@ -33,6 +34,15 @@ impl<'c> Translation<'c> {
3334
Ok((replacement, converted)) => {
3435
trace!(" to {:?}", replacement);
3536

37+
for (expr_id, result) in &converted.expr_results {
38+
if let Err(err) = result {
39+
info!(
40+
"Could not convert macro {} for {:?}: {}",
41+
name, expr_id, err
42+
);
43+
}
44+
}
45+
3646
let result_type_rs = self.convert_type(converted.result_type_id)?;
3747
self.converted_macros
3848
.borrow_mut()
@@ -46,7 +56,7 @@ impl<'c> Translation<'c> {
4656
}
4757
Err(e) => {
4858
self.converted_macros.borrow_mut().insert(decl_id, None);
49-
info!("Could not expand macro {}: {}", name, e);
59+
info!("Could not convert macro {}: {}", name, e);
5060
Ok(ConvertedDecl::NoItem)
5161
}
5262
}
@@ -68,56 +78,67 @@ impl<'c> Translation<'c> {
6878
ctx: ExprContext,
6979
expansions: &[CExprId],
7080
) -> TranslationResult<(Box<Expr>, ConvertedMacro)> {
71-
let (val, result_type_id) = expansions
81+
let mut canonical = None;
82+
let expr_results: HashMap<_, _> = expansions
7283
.iter()
73-
.try_fold::<Option<(WithStmts<Box<Expr>>, CTypeId)>, _, _>(
74-
None,
75-
|mut canonical, &expr_id| -> TranslationResult<_> {
76-
self.can_convert_const_macro_expansion(expr_id)?;
77-
78-
let type_id = self.ast_context[expr_id]
79-
.kind
80-
.get_type()
81-
.ok_or_else(|| format_err!("Invalid expression type"))?;
82-
let val = self.convert_expr(ctx, expr_id, None)?;
83-
let new = (val, type_id);
84-
85-
// Join ty and cur_ty to the smaller of the two types. If the
86-
// types are not cast-compatible, abort the fold.
87-
match &mut canonical {
88-
Some(canonical) => {
89-
let &mut (_, canon_type_id) = canonical;
90-
let (_, new_type_id) = new;
91-
92-
let canon_type_kind =
93-
self.ast_context.resolve_type(canon_type_id).kind.clone();
94-
let new_type_kind =
95-
self.ast_context.resolve_type(new_type_id).kind.clone();
96-
let smaller_type_kind = CTypeKind::smaller_compatible_type(
97-
canon_type_kind.clone(),
98-
new_type_kind,
99-
);
100-
let Some(smaller_type_kind) = smaller_type_kind else {
101-
return Err(
102-
format_err!("Not all macro expansions are compatible types")
103-
.into()
104-
)
105-
};
106-
107-
if smaller_type_kind != canon_type_kind {
108-
*canonical = new;
84+
.map(|&expr_id| {
85+
let result = self
86+
.can_convert_const_macro_expansion(expr_id)
87+
.and_then(|_| {
88+
let type_id = self.ast_context[expr_id]
89+
.kind
90+
.get_type()
91+
.ok_or_else(|| format_err!("Invalid expression type"))?;
92+
let val = self.convert_expr(ctx, expr_id, None)?;
93+
Ok((val, type_id))
94+
})
95+
.and_then(|new| {
96+
// Join ty and cur_ty to the smaller of the two types. If the
97+
// types are not cast-compatible, skip this expansion.
98+
match &mut canonical {
99+
Some(canonical) => {
100+
let &mut (_, canon_type_id) = canonical;
101+
let (_, new_type_id) = new;
102+
103+
let canon_type_kind =
104+
self.ast_context.resolve_type(canon_type_id).kind.clone();
105+
let new_type_kind =
106+
self.ast_context.resolve_type(new_type_id).kind.clone();
107+
let smaller_type_kind = CTypeKind::smaller_compatible_type(
108+
canon_type_kind.clone(),
109+
new_type_kind,
110+
);
111+
let Some(smaller_type_kind) = smaller_type_kind else {
112+
return Err(
113+
format_err!(
114+
"Not all macro expansions are compatible types"
115+
)
116+
.into()
117+
)
118+
};
119+
120+
if smaller_type_kind != canon_type_kind {
121+
*canonical = new;
122+
}
109123
}
124+
125+
None => canonical = Some(new),
110126
}
111127

112-
None => canonical = Some(new),
113-
}
128+
Ok(())
129+
});
130+
131+
(expr_id, result)
132+
})
133+
.collect();
114134

115-
Ok(canonical)
116-
},
117-
)?
118-
.ok_or_else(|| format_err!("Could not find a valid type for macro"))?;
135+
let (val, result_type_id) =
136+
canonical.ok_or_else(|| format_err!("Could not find a valid type for macro"))?;
119137

120-
let converted = ConvertedMacro { result_type_id };
138+
let converted = ConvertedMacro {
139+
result_type_id,
140+
expr_results,
141+
};
121142
val.wrap_unsafe()
122143
.to_pure_expr()
123144
.map(|val| (val, converted))
@@ -205,6 +226,11 @@ impl<'c> Translation<'c> {
205226
return Ok(None);
206227
};
207228

229+
if !matches!(converted.expr_results.get(&expr_id), Some(Ok(_))) {
230+
// Expansion succeeded in general, but not for this particular expression.
231+
return Ok(None);
232+
}
233+
208234
let result_type_id = converted.result_type_id;
209235
let rust_name = self
210236
.renamer

c2rust-transpile/src/translator/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ impl FuncContext {
262262

263263
struct ConvertedMacro {
264264
result_type_id: CTypeId,
265+
expr_results: HashMap<CExprId, TranslationResult<()>>,
265266
}
266267

267268
type ZeroInits = IndexMap<CDeclId, (WithStmts<Box<Expr>>, IndexSet<Import>)>;

0 commit comments

Comments
 (0)