@@ -10,6 +10,8 @@ pub(crate) enum Constness {
10
10
Const ,
11
11
Mut ,
12
12
}
13
+
14
+ #[ cfg_attr( not( test) , expect( unused_imports) ) ]
13
15
use Constness :: { Const , Mut } ;
14
16
15
17
/// A basic representation of C's types.
@@ -19,13 +21,15 @@ pub(crate) enum CTy {
19
21
/// `int`, `struct foo`, etc. There is only ever one basic type per decl.
20
22
Named {
21
23
name : BoxStr ,
22
- constness : Constness ,
24
+ qual : Qual ,
23
25
} ,
24
26
Ptr {
25
27
ty : Box < Self > ,
26
- constness : Constness ,
28
+ qual : Qual ,
27
29
} ,
28
30
Array {
31
+ // C99 also supports type qualifiers in arrays, e.g. `[const volatile restrict]`. MSVC does
32
+ // not though, so we ignore these for now.
29
33
ty : Box < Self > ,
30
34
len : Option < BoxStr > ,
31
35
} ,
@@ -98,17 +102,20 @@ fn cdecl_impl(cty: &CTy, s: &mut String, prev: Option<&CTy>) -> Result<(), Inval
98
102
cty. check_ret_ty ( ) ?;
99
103
cty. parens_if_needed ( s, prev) ;
100
104
match cty {
101
- CTy :: Named { name, constness } => {
102
- let sp = if s. is_empty ( ) { "" } else { " " } ;
103
- let c = if * constness == Const { "const " } else { "" } ;
104
- let to_insert = format ! ( "{c}{name}{sp}" ) ;
105
+ CTy :: Named { name, qual } => {
106
+ assert ! ( !qual. restrict, "restrict is not allowed for named types" ) ;
107
+ let mut to_insert = String :: new ( ) ;
108
+ qual. write_to ( & mut to_insert) ;
109
+ space_if ( !to_insert. is_empty ( ) && !name. is_empty ( ) , & mut to_insert) ;
110
+ to_insert. push_str ( name) ;
111
+ space_if ( !to_insert. is_empty ( ) && !s. is_empty ( ) , & mut to_insert) ;
105
112
s. insert_str ( 0 , & to_insert) ;
106
113
}
107
- CTy :: Ptr { ty, constness } => {
108
- match constness {
109
- Const => s . insert_str ( 0 , "*const " ) ,
110
- Mut => s . insert ( 0 , '*' ) ,
111
- }
114
+ CTy :: Ptr { ty, qual } => {
115
+ let mut to_insert = "*" . to_owned ( ) ;
116
+ qual . write_to ( & mut to_insert ) ;
117
+ space_if ( to_insert . len ( ) > 1 && !s . is_empty ( ) , & mut to_insert ) ;
118
+ s . insert_str ( 0 , & to_insert ) ;
112
119
cdecl_impl ( ty, s, Some ( cty) ) ?;
113
120
}
114
121
CTy :: Array { ty, len } => {
@@ -136,6 +143,41 @@ fn cdecl_impl(cty: &CTy, s: &mut String, prev: Option<&CTy>) -> Result<(), Inval
136
143
Ok ( ( ) )
137
144
}
138
145
146
+ /// Keyword qualifiers.
147
+ #[ derive( Clone , Copy , Debug ) ]
148
+ pub ( crate ) struct Qual {
149
+ // C11 also supports _Atomic, but it doesn't really come up for `ctest`.
150
+ pub constness : Constness ,
151
+ pub volatile : bool ,
152
+ pub restrict : bool ,
153
+ }
154
+
155
+ impl Qual {
156
+ fn write_to ( self , s : & mut String ) {
157
+ let mut need_sp = false ;
158
+ if self . constness == Const {
159
+ s. push_str ( "const" ) ;
160
+ need_sp = true ;
161
+ }
162
+ if self . volatile {
163
+ space_if ( need_sp, s) ;
164
+ s. push_str ( "volatile" ) ;
165
+ need_sp = true ;
166
+ }
167
+ if self . restrict {
168
+ space_if ( need_sp, s) ;
169
+ s. push_str ( "restrict" ) ;
170
+ }
171
+ }
172
+ }
173
+
174
+ // We do this a surprising number of times.
175
+ fn space_if ( yes : bool , s : & mut String ) {
176
+ if yes {
177
+ s. push ( ' ' ) ;
178
+ }
179
+ }
180
+
139
181
/// Checked with <https://cdecl.org/>.
140
182
#[ cfg( test) ]
141
183
mod tests {
@@ -149,6 +191,17 @@ mod tests {
149
191
150
192
/* Helpful constructors */
151
193
194
+ const RESTRICT : Qual = Qual {
195
+ constness : Mut ,
196
+ volatile : false ,
197
+ restrict : true ,
198
+ } ;
199
+ const VOLATILE : Qual = Qual {
200
+ constness : Mut ,
201
+ volatile : true ,
202
+ restrict : false ,
203
+ } ;
204
+
152
205
fn mut_int ( ) -> CTy {
153
206
named ( "int" , Mut )
154
207
}
@@ -160,14 +213,36 @@ mod tests {
160
213
fn named ( name : & str , constness : Constness ) -> CTy {
161
214
CTy :: Named {
162
215
name : name. into ( ) ,
163
- constness,
216
+ qual : Qual {
217
+ constness,
218
+ volatile : false ,
219
+ restrict : false ,
220
+ } ,
221
+ }
222
+ }
223
+
224
+ fn named_qual ( name : & str , qual : Qual ) -> CTy {
225
+ CTy :: Named {
226
+ name : name. into ( ) ,
227
+ qual,
164
228
}
165
229
}
166
230
167
231
fn ptr ( inner : CTy , constness : Constness ) -> CTy {
232
+ ptr_qual (
233
+ inner,
234
+ Qual {
235
+ constness,
236
+ volatile : false ,
237
+ restrict : false ,
238
+ } ,
239
+ )
240
+ }
241
+
242
+ fn ptr_qual ( inner : CTy , qual : Qual ) -> CTy {
168
243
CTy :: Ptr {
169
244
ty : Box :: new ( inner) ,
170
- constness ,
245
+ qual ,
171
246
}
172
247
}
173
248
@@ -217,6 +292,19 @@ mod tests {
217
292
& ptr ( ptr ( const_int ( ) , Const ) , Const ) ,
218
293
"const int *const *const foo" ,
219
294
) ;
295
+ assert_decl ( & ptr_qual ( mut_int ( ) , RESTRICT ) , "int *restrict foo" ) ;
296
+ assert_decl ( & ptr_qual ( mut_int ( ) , VOLATILE ) , "int *volatile foo" ) ;
297
+ assert_decl (
298
+ & ptr_qual (
299
+ mut_int ( ) ,
300
+ Qual {
301
+ constness : Const ,
302
+ volatile : true ,
303
+ restrict : true ,
304
+ } ,
305
+ ) ,
306
+ "int *const volatile restrict foo" ,
307
+ ) ;
220
308
}
221
309
222
310
#[ test]
@@ -251,6 +339,10 @@ mod tests {
251
339
& func ( vec ! [ const_int( ) , mut_int( ) ] , mut_int ( ) ) ,
252
340
"int foo(const int, int)" ,
253
341
) ;
342
+ assert_decl (
343
+ & func ( vec ! [ ] , named_qual ( "int" , VOLATILE ) ) ,
344
+ "volatile int foo()" ,
345
+ ) ;
254
346
}
255
347
256
348
#[ test]
@@ -310,13 +402,40 @@ mod tests {
310
402
// Function args are usually unnamed
311
403
assert_eq ! ( cdecl( & mut_int( ) , String :: new( ) ) . unwrap( ) , "int" ) ;
312
404
assert_eq ! (
313
- cdecl( & ptr( array( mut_int( ) , None ) , Mut ) , String :: new( ) ) . unwrap( ) ,
314
- "int (*)[]"
405
+ cdecl( & array( mut_int( ) , None ) , String :: new( ) ) . unwrap( ) ,
406
+ "int []"
407
+ ) ;
408
+ assert_eq ! (
409
+ cdecl( & array( const_int( ) , None ) , String :: new( ) ) . unwrap( ) ,
410
+ "const int []"
315
411
) ;
316
412
assert_eq ! (
317
413
cdecl( & array( ptr( mut_int( ) , Mut ) , None ) , String :: new( ) ) . unwrap( ) ,
318
414
"int *[]"
319
415
) ;
416
+ assert_eq ! (
417
+ cdecl( & ptr( array( mut_int( ) , None ) , Mut ) , String :: new( ) ) . unwrap( ) ,
418
+ "int (*)[]"
419
+ ) ;
420
+ assert_eq ! (
421
+ cdecl( & ptr( array( mut_int( ) , None ) , Const ) , String :: new( ) ) . unwrap( ) ,
422
+ "int (*const)[]"
423
+ ) ;
424
+ assert_eq ! (
425
+ cdecl(
426
+ & ptr_qual(
427
+ mut_int( ) ,
428
+ Qual {
429
+ constness: Const ,
430
+ volatile: true ,
431
+ restrict: true ,
432
+ } ,
433
+ ) ,
434
+ String :: new( ) ,
435
+ )
436
+ . unwrap( ) ,
437
+ "int *const volatile restrict" ,
438
+ ) ;
320
439
}
321
440
322
441
#[ test]
0 commit comments