@@ -173,61 +173,88 @@ 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
+ } ;
196
+
197
+ let is_string_literal = |id : CExprId | {
198
+ matches ! (
199
+ self . ast_context. index( id) . kind,
200
+ CExprKind :: Literal ( _, CLiteral :: String { .. } )
201
+ )
202
+ } ;
203
+
204
+ let is_zero_literal = |id| -> TranslationResult < bool > {
205
+ let expr = self . convert_expr ( ctx. used ( ) , id) ?;
206
+ let mut current = expr. into_value ( ) ;
180
207
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 ;
208
+ loop {
209
+ match * current {
210
+ syn:: Expr :: Cast ( ExprCast { attrs, expr, .. } ) if attrs. is_empty ( ) => {
211
+ current = expr
212
+ }
213
+ syn:: Expr :: Lit ( ExprLit { attrs, lit, .. } ) if attrs. is_empty ( ) => {
214
+ return Ok ( match lit {
215
+ Lit :: Int ( lit_int) => lit_int. base10_digits ( ) == "0" ,
216
+ _ => false ,
217
+ } ) ;
218
+ }
219
+ _ => return Ok ( false ) ,
220
+ }
187
221
}
188
- }
222
+ } ;
189
223
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) ) )
224
+ match ids {
225
+ [ ] => {
226
+ // this was likely a C array of the form `int x[16] = {}`,
227
+ // we'll emit that as [0; 16].
228
+ let len = mk ( ) . lit_expr ( mk ( ) . int_unsuffixed_lit ( n as u128 ) ) ;
229
+ Ok ( self
230
+ . implicit_default_expr ( ty, ctx. is_static ) ?
231
+ . map ( |default_value| mk ( ) . repeat_expr ( default_value, len) ) )
232
+ }
233
+ [ single] if is_string_literal ( * single) => {
234
+ // Need to check to see if the next item is a string literal,
235
+ // if it is need to treat it as a declaration, rather than
236
+ // an init list. https://github.com/GaloisInc/C2Rust/issues/40
237
+ self . convert_expr ( ctx. used ( ) , * single)
238
+ }
239
+ [ single] if is_zero_literal ( * single) ? && n > 1 => {
240
+ // this was likely a C array of the form `int x[16] = { 0 }`,
241
+ // we'll emit that as [0; 16].
242
+ let len = mk ( ) . lit_expr ( mk ( ) . int_unsuffixed_lit ( n as u128 ) ) ;
243
+ Ok ( to_array_element ( single) ?
244
+ . map ( |default_value| mk ( ) . repeat_expr ( default_value, len) ) )
245
+ }
246
+ [ ..] => {
247
+ Ok ( ids
248
+ . iter ( )
249
+ . map ( to_array_element)
250
+ . chain (
251
+ // Pad out the array literal with default values to the desired size
252
+ iter:: repeat ( self . implicit_default_expr ( ty, ctx. is_static ) )
253
+ . take ( n - ids. len ( ) ) ,
254
+ )
255
+ . collect :: < TranslationResult < WithStmts < _ > > > ( ) ?
256
+ . map ( |vals| mk ( ) . array_expr ( vals) ) )
257
+ }
231
258
}
232
259
}
233
260
CTypeKind :: Struct ( struct_id) => {
0 commit comments