Skip to content

Commit d7d679d

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

2 files changed

Lines changed: 77 additions & 44 deletions

File tree

c2rust-transpile/src/translator/macros.rs

Lines changed: 76 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use c2rust_ast_builder::mk;
22
use failure::format_err;
3+
use indexmap::IndexMap;
34
use log::{info, trace};
45
use proc_macro2::{Span, TokenStream};
56
use std::rc::Rc;
@@ -34,6 +35,15 @@ impl<'c> Translation<'c> {
3435
Ok((replacement, expansion)) => {
3536
trace!(" to {:?}", replacement);
3637

38+
for (expr_id, result) in &expansion.expr_results {
39+
if let Err(err) = result {
40+
info!(
41+
"Could not convert macro {} for {:?}: {}",
42+
name, expr_id, err
43+
);
44+
}
45+
}
46+
3747
let ty = self.convert_type(expansion.ty)?;
3848
self.macro_expansions
3949
.borrow_mut()
@@ -74,57 +84,74 @@ impl<'c> Translation<'c> {
7484
type_id: CTypeId,
7585
}
7686

77-
let canonical = expansions
87+
let mut canonical: Option<ConvertedMacroExpr> = None;
88+
let mut expr_results: IndexMap<_, _> = expansions
7889
.iter()
79-
.try_fold::<Option<ConvertedMacroExpr>, _, _>(
80-
None,
81-
|mut canonical, &expr_id| -> TranslationResult<_> {
82-
self.can_convert_const_macro_expansion(expr_id)?;
83-
84-
let type_id = self.ast_context[expr_id]
85-
.kind
86-
.get_type()
87-
.ok_or_else(|| format_err!("Invalid expression type"))?;
88-
let val = self.convert_expr(ctx, expr_id, None)?;
89-
let new = ConvertedMacroExpr { val, type_id };
90-
91-
// Join ty and cur_ty to the smaller of the two types. If the
92-
// types are not cast-compatible, abort the fold.
93-
match &mut canonical {
94-
Some(canonical) => {
95-
let canon_type_kind = self
96-
.ast_context
97-
.resolve_type(canonical.type_id)
98-
.kind
99-
.clone();
100-
let new_type_kind =
101-
self.ast_context.resolve_type(new.type_id).kind.clone();
102-
let smaller_type_kind = CTypeKind::smaller_compatible_type(
103-
canon_type_kind.clone(),
104-
new_type_kind,
105-
);
106-
let Some(smaller_type_kind) = smaller_type_kind else {
107-
return Err(
108-
format_err!("Not all macro expansions are compatible types")
109-
.into()
110-
)
111-
};
112-
113-
if smaller_type_kind != canon_type_kind {
114-
*canonical = new;
90+
.map(|&expr_id| {
91+
let result = self
92+
.can_convert_const_macro_expansion(expr_id)
93+
.and_then(|_| {
94+
let type_id = self.ast_context[expr_id]
95+
.kind
96+
.get_type()
97+
.ok_or_else(|| format_err!("Invalid expression type"))?;
98+
let val = self.convert_expr(ctx, expr_id, None)?;
99+
Ok(ConvertedMacroExpr { val, type_id })
100+
})
101+
.and_then(|new| {
102+
// Join ty and cur_ty to the smaller of the two types. If the
103+
// types are not cast-compatible, skip this expansion.
104+
match &mut canonical {
105+
Some(canonical) => {
106+
let canon_type_kind = self
107+
.ast_context
108+
.resolve_type(canonical.type_id)
109+
.kind
110+
.clone();
111+
let new_type_kind =
112+
self.ast_context.resolve_type(new.type_id).kind.clone();
113+
let smaller_type_kind = CTypeKind::smaller_compatible_type(
114+
canon_type_kind.clone(),
115+
new_type_kind,
116+
);
117+
let Some(smaller_type_kind) = smaller_type_kind else {
118+
return Err(
119+
format_err!(
120+
"Not all macro expansions are compatible types"
121+
)
122+
.into()
123+
)
124+
};
125+
126+
if smaller_type_kind != canon_type_kind {
127+
*canonical = new;
128+
}
115129
}
130+
131+
None => canonical = Some(new),
116132
}
117133

118-
None => canonical = Some(new),
119-
}
134+
Ok(())
135+
});
120136

121-
Ok(canonical)
122-
},
123-
)?
124-
.ok_or_else(|| format_err!("Could not find a valid type for macro"))?;
137+
(expr_id, result)
138+
})
139+
.collect();
140+
141+
let Some(canonical) = canonical else {
142+
// If none of the expansions could be converted, try returning the first error we got.
143+
let err = match expr_results.swap_remove_index(0) {
144+
Some((_, Err(err))) => err,
145+
_ => format_err!("Could not find a valid type for macro").into(),
146+
};
147+
return Err(err);
148+
};
125149

126150
let ConvertedMacroExpr { val, type_id } = canonical;
127-
let expansion = MacroExpansion { ty: type_id };
151+
let expansion = MacroExpansion {
152+
ty: type_id,
153+
expr_results,
154+
};
128155
val.wrap_unsafe()
129156
.to_pure_expr()
130157
.map(|val| (val, expansion))
@@ -212,6 +239,11 @@ impl<'c> Translation<'c> {
212239
}
213240
};
214241

242+
if !matches!(expansion.expr_results.get(&expr_id), Some(Ok(_))) {
243+
// Expansion succeeded in general, but not for this particular expression.
244+
return Ok(None);
245+
}
246+
215247
let macro_ty = expansion.ty;
216248
let rust_name = self
217249
.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 MacroExpansion {
264264
ty: CTypeId,
265+
expr_results: IndexMap<CExprId, TranslationResult<()>>,
265266
}
266267

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

0 commit comments

Comments
 (0)