@@ -173,61 +173,75 @@ impl<'c> Translation<'c> {
173
173
CTypeKind :: ConstantArray ( ty, n) => {
174
174
// Convert all of the provided initializer values
175
175
176
- // Need to check to see if the next item is a string literal,
177
- // if it is need to treat it as a declaration, rather than
178
- // an init list. https://github.com/GaloisInc/C2Rust/issues/40
179
- let mut is_string = false ;
176
+ let to_array_element = |id : & CExprId | -> TranslationResult < _ > {
177
+ self . convert_expr ( ctx. used ( ) , * id) ?. result_map ( |x| {
178
+ // Array literals require all of their elements to be
179
+ // the correct type; they will not use implicit casts to
180
+ // change mut to const. This becomes a problem when an
181
+ // array literal is used in a position where there is no
182
+ // type information available to force its type to the
183
+ // correct const or mut variation. To avoid this issue
184
+ // we manually insert the otherwise elided casts in this
185
+ // particular context.
186
+ if let CExprKind :: ImplicitCast ( ty, _, CastKind :: ConstCast , _, _) =
187
+ self . ast_context [ * id] . kind
188
+ {
189
+ let t = self . convert_type ( ty. ctype ) ?;
190
+ Ok ( mk ( ) . cast_expr ( x, t) )
191
+ } else {
192
+ Ok ( x)
193
+ }
194
+ } )
195
+ } ;
180
196
181
- if ids. len ( ) == 1 {
182
- let v = ids. first ( ) . unwrap ( ) ;
183
- if let CExprKind :: Literal ( _, CLiteral :: String { .. } ) =
184
- self . ast_context . index ( * v) . kind
185
- {
186
- is_string = true ;
187
- }
188
- }
197
+ let is_string_literal = |id : CExprId | {
198
+ matches ! (
199
+ self . ast_context. index( id) . kind,
200
+ CExprKind :: Literal ( _, CLiteral :: String { .. } )
201
+ )
202
+ } ;
189
203
190
- if is_string {
191
- let v = ids . first ( ) . unwrap ( ) ;
192
- self . convert_expr ( ctx . used ( ) , * v )
193
- } else if ids . is_empty ( ) {
194
- // this was likely a C array of the form `int x[16] = {}`,
195
- // we'll emit that as [0; 16].
196
- let len = mk ( ) . lit_expr ( mk ( ) . int_unsuffixed_lit ( n as u128 ) ) ;
197
- self . implicit_default_expr ( ty , ctx . is_static ) ?
198
- . and_then ( |default_value| {
199
- Ok ( WithStmts :: new_val ( mk ( ) . repeat_expr ( default_value , len ) ) )
200
- } )
201
- } else {
202
- Ok ( ids
203
- . iter ( )
204
- . map ( |id| {
205
- self . convert_expr ( ctx . used ( ) , * id ) ? . result_map ( |x| {
206
- // Array literals require all of their elements to be
207
- // the correct type; they will not use implicit casts to
208
- // change mut to const. This becomes a problem when an
209
- // array literal is used in a position where there is no
210
- // type information available to force its type to the
211
- // correct const or mut variation. To avoid this issue
212
- // we manually insert the otherwise elided casts in this
213
- // particular context.
214
- if let CExprKind :: ImplicitCast ( ty , _ , CastKind :: ConstCast , _ , _ ) =
215
- self . ast_context [ * id ] . kind
216
- {
217
- let t = self . convert_type ( ty . ctype ) ? ;
218
- Ok ( mk ( ) . cast_expr ( x , t ) )
219
- } else {
220
- Ok ( x )
221
- }
222
- } )
223
- } )
224
- . chain (
225
- // Pad out the array literal with default values to the desired size
226
- iter :: repeat ( self . implicit_default_expr ( ty , ctx . is_static ) )
227
- . take ( n - ids . len ( ) ) ,
228
- )
229
- . collect :: < TranslationResult < WithStmts < _ > > > ( ) ?
230
- . map ( |vals| mk ( ) . array_expr ( vals ) ) )
204
+ let is_zero_literal = | id : CExprId | {
205
+ matches ! (
206
+ self . ast_context . index ( id ) . kind ,
207
+ CExprKind :: Literal ( _ , CLiteral :: Integer ( 0 , _base ) )
208
+ )
209
+ } ;
210
+
211
+ match ids {
212
+ [ ] => {
213
+ // this was likely a C array of the form `int x[16] = {}`,
214
+ // we'll emit that as [0; 16].
215
+ let len = mk ( ) . lit_expr ( mk ( ) . int_unsuffixed_lit ( n as u128 ) ) ;
216
+ Ok ( self
217
+ . implicit_default_expr ( ty , ctx . is_static ) ?
218
+ . map ( |default_value| mk ( ) . repeat_expr ( default_value , len ) ) )
219
+ }
220
+ [ single ] if is_string_literal ( * single ) => {
221
+ // Need to check to see if the next item is a string literal,
222
+ // if it is need to treat it as a declaration, rather than
223
+ // an init list. https://github.com/GaloisInc/C2Rust/issues/40
224
+ self . convert_expr ( ctx . used ( ) , * single )
225
+ }
226
+ [ single ] if is_zero_literal ( * single ) && n > 1 => {
227
+ // this was likely a C array of the form `int x[16] = { 0 }`,
228
+ // we'll emit that as [0; 16].
229
+ let len = mk ( ) . lit_expr ( mk ( ) . int_unsuffixed_lit ( n as u128 ) ) ;
230
+ Ok ( to_array_element ( single ) ?
231
+ . map ( |default_value| mk ( ) . repeat_expr ( default_value , len ) ) )
232
+ }
233
+ [ .. ] => {
234
+ Ok ( ids
235
+ . iter ( )
236
+ . map ( to_array_element )
237
+ . chain (
238
+ // Pad out the array literal with default values to the desired size
239
+ iter :: repeat ( self . implicit_default_expr ( ty , ctx . is_static ) )
240
+ . take ( n - ids . len ( ) ) ,
241
+ )
242
+ . collect :: < TranslationResult < WithStmts < _ > > > ( ) ?
243
+ . map ( |vals| mk ( ) . array_expr ( vals ) ) )
244
+ }
231
245
}
232
246
}
233
247
CTypeKind :: Struct ( struct_id) => {
0 commit comments