11use c2rust_ast_builder:: mk;
22use failure:: format_err;
3+ use indexmap:: IndexMap ;
34use log:: { info, trace} ;
45use proc_macro2:: { Span , TokenStream } ;
56use syn:: { Expr , MacroDelimiter } ;
67
7- use crate :: c_ast:: { CDeclId , CExprId , CQualTypeId , CTypeId , CTypeKind } ;
8+ use crate :: c_ast:: { CDeclId , CExprId , CQualTypeId , CTypeKind } ;
89use crate :: diagnostics:: { TranslationError , TranslationResult } ;
910use crate :: translator:: { ConvertedDecl , ConvertedMacro , ExprContext , Translation } ;
1011use 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,73 @@ 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 mut expr_results: IndexMap < _ , _ > = 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+ } ) ;
114130
115- Ok ( canonical)
116- } ,
117- ) ?
118- . ok_or_else ( || format_err ! ( "Could not find a valid type for macro" ) ) ?;
131+ ( expr_id, result)
132+ } )
133+ . collect ( ) ;
134+
135+ let Some ( ( val, result_type_id) ) = canonical else {
136+ // If none of the expansions could be converted, try returning the first error we got.
137+ let err = match expr_results. swap_remove_index ( 0 ) {
138+ Some ( ( _, Err ( err) ) ) => err,
139+ _ => format_err ! ( "Could not find a valid type for macro" ) . into ( ) ,
140+ } ;
141+ return Err ( err) ;
142+ } ;
119143
120- let converted = ConvertedMacro { result_type_id } ;
144+ let converted = ConvertedMacro {
145+ result_type_id,
146+ expr_results,
147+ } ;
121148 val. wrap_unsafe ( )
122149 . to_pure_expr ( )
123150 . map ( |val| ( val, converted) )
@@ -205,6 +232,11 @@ impl<'c> Translation<'c> {
205232 return Ok ( None ) ;
206233 } ;
207234
235+ if !matches ! ( converted. expr_results. get( & expr_id) , Some ( Ok ( _) ) ) {
236+ // Expansion succeeded in general, but not for this particular expression.
237+ return Ok ( None ) ;
238+ }
239+
208240 let result_type_id = converted. result_type_id ;
209241 let rust_name = self
210242 . renamer
0 commit comments