|
1 | 1 | use c2rust_ast_builder::mk; |
2 | 2 | use failure::format_err; |
| 3 | +use indexmap::IndexMap; |
3 | 4 | use log::{info, trace}; |
4 | 5 | use proc_macro2::{Span, TokenStream}; |
5 | 6 | use std::rc::Rc; |
@@ -34,6 +35,15 @@ impl<'c> Translation<'c> { |
34 | 35 | Ok((replacement, expansion)) => { |
35 | 36 | trace!(" to {:?}", replacement); |
36 | 37 |
|
| 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 | + |
37 | 47 | let ty = self.convert_type(expansion.ty)?; |
38 | 48 | self.macro_expansions |
39 | 49 | .borrow_mut() |
@@ -74,57 +84,74 @@ impl<'c> Translation<'c> { |
74 | 84 | type_id: CTypeId, |
75 | 85 | } |
76 | 86 |
|
77 | | - let canonical = expansions |
| 87 | + let mut canonical: Option<ConvertedMacroExpr> = None; |
| 88 | + let mut expr_results: IndexMap<_, _> = expansions |
78 | 89 | .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 | + } |
115 | 129 | } |
| 130 | + |
| 131 | + None => canonical = Some(new), |
116 | 132 | } |
117 | 133 |
|
118 | | - None => canonical = Some(new), |
119 | | - } |
| 134 | + Ok(()) |
| 135 | + }); |
120 | 136 |
|
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 | + }; |
125 | 149 |
|
126 | 150 | 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 | + }; |
128 | 155 | val.wrap_unsafe() |
129 | 156 | .to_pure_expr() |
130 | 157 | .map(|val| (val, expansion)) |
@@ -212,6 +239,11 @@ impl<'c> Translation<'c> { |
212 | 239 | } |
213 | 240 | }; |
214 | 241 |
|
| 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 | + |
215 | 247 | let macro_ty = expansion.ty; |
216 | 248 | let rust_name = self |
217 | 249 | .renamer |
|
0 commit comments