@@ -347,83 +347,126 @@ impl TypedAstContext {
347347 . is_some ( )
348348 }
349349
350- /// Follow a chain of typedefs and return true iff the last typedef is named
351- /// `__builtin_va_list` thus naming the type clang uses to represent `va_list`s.
352- pub fn is_builtin_va_list ( & self , typ : CTypeId ) -> bool {
353- match self . index ( typ) . kind {
354- CTypeKind :: Typedef ( decl) => match & self . index ( decl) . kind {
355- CDeclKind :: Typedef {
356- name : name_,
357- typ : ty,
358- ..
359- } => {
360- if name_ == "__builtin_va_list" {
361- true
362- } else {
363- self . is_builtin_va_list ( ty. ctype )
364- }
365- }
366- _ => panic ! ( "Typedef decl did not point to a typedef" ) ,
367- } ,
368- _ => false ,
369- }
370- }
350+ /// Returns whether `typ` is a chain of typedefs that ends in `__builtin_va_list`,
351+ /// thus naming the type clang uses to represent `va_list`s.
352+ /// This works on all architectures, but does not work in situations where typedefs are
353+ /// resolved/bypassed, such as with array-to-pointer decay.
354+ pub fn is_builtin_va_list ( & self , mut typ : CTypeId ) -> bool {
355+ loop {
356+ // Skip over Elaborated types
357+ let mut kind = & self . index ( typ) . kind ;
358+
359+ while let & CTypeKind :: Elaborated ( typ) = kind {
360+ kind = & self . index ( typ) . kind ;
361+ }
371362
372- /// Predicate for types that are used to implement C's `va_list`.
373- /// FIXME: can we get rid of this method and use `is_builtin_va_list` instead?
374- pub fn is_va_list_struct ( & self , typ : CTypeId ) -> bool {
375- // detect `va_list`s based on typedef (should work across implementations)
376- // if self.is_builtin_va_list(typ) {
377- // return true;
378- // }
363+ // TODO: Rust 1.65: use let-else
364+ let decl = match kind {
365+ & CTypeKind :: Typedef ( decl) => decl,
366+ _ => return false ,
367+ } ;
368+ let ( name, qtyp) = match & self . index ( decl) . kind {
369+ & CDeclKind :: Typedef { ref name, typ, .. } => ( name, typ) ,
370+ _ => panic ! ( "Typedef decl did not point to a typedef" ) ,
371+ } ;
379372
380- // detect `va_list`s based on type (assumes struct-based implementation)
381- let resolved_ctype = self . resolve_type ( typ) ;
382- use CTypeKind :: * ;
383- match resolved_ctype. kind {
384- Struct ( record_id) => {
385- if let CDeclKind :: Struct {
386- name : Some ( ref name_) ,
387- ..
388- } = & self [ record_id] . kind
389- {
390- name_ == "__va_list_tag" || name_ == "__va_list"
391- } else {
392- false
393- }
373+ if name == "__builtin_va_list" {
374+ return true ;
394375 }
395- // va_list is a 1 element array; return true iff element type is struct __va_list_tag
396- ConstantArray ( typ, 1 ) => self . is_va_list ( typ) ,
397- _ => false ,
376+
377+ typ = qtyp. ctype ;
398378 }
399379 }
400380
401- /// Predicate for pointers to types that are used to implement C's `va_list`.
402- pub fn is_va_list ( & self , typ : CTypeId ) -> bool {
381+ /// Returns whether `typ` is the architecture-specific type used for `va_list`.
382+ /// Returns `false` for architectures where `va_list` is a generic pointer type.
383+ pub fn is_va_list_struct ( & self , typ : CTypeId ) -> bool {
403384 use BuiltinVaListKind :: * ;
385+
404386 match self . va_list_kind {
405- CharPtrBuiltinVaList | VoidPtrBuiltinVaList | X86_64ABIBuiltinVaList => {
406- match self . resolve_type ( typ) . kind {
407- CTypeKind :: Pointer ( CQualTypeId { ctype, .. } )
408- | CTypeKind :: ConstantArray ( ctype, _) => self . is_va_list_struct ( ctype) ,
409- _ => false ,
410- }
387+ // No special identification is possible with generic types.
388+ CharPtrBuiltinVaList | VoidPtrBuiltinVaList => false ,
389+
390+ // ARM32:
391+ // typedef struct __va_list {
392+ // void *__ap;
393+ // } __builtin_va_list;
394+
395+ // ARM64:
396+ // typedef struct __va_list {
397+ // void *__stack;
398+ // void *__gr_top;
399+ // void *__vr_top;
400+ // int __gr_offs;
401+ // int __vr_offs;
402+ // } __builtin_va_list;
403+ AArch64ABIBuiltinVaList | AAPCSABIBuiltinVaList => {
404+ // TODO: Rust 1.65: use let-else
405+ let decl = match self . resolve_type ( typ) . kind {
406+ CTypeKind :: Struct ( decl) => decl,
407+ _ => return false ,
408+ } ;
409+ let name = match & self [ decl] . kind {
410+ CDeclKind :: Struct {
411+ name : Some ( name) , ..
412+ } => name,
413+ _ => return false ,
414+ } ;
415+
416+ name == "__va_list"
411417 }
412418
413- AArch64ABIBuiltinVaList => self . is_va_list_struct ( typ) ,
419+ // X86-64:
420+ // typedef struct __va_list_tag {
421+ // unsigned int gp_offset;
422+ // unsigned int fp_offset;
423+ // void *overflow_arg_area;
424+ // void *reg_save_area;
425+ // } __builtin_va_list[1];
426+
427+ // Power:
428+ // typedef struct __va_list_tag {
429+ // unsigned char gpr;
430+ // unsigned char fpr;
431+ // unsigned short reserved;
432+ // char *overflow_arg_area;
433+ // char *reg_save_area;
434+ // } __builtin_va_list[1];
435+ PowerABIBuiltinVaList | X86_64ABIBuiltinVaList => {
436+ // TODO: Rust 1.65: use let-else
437+ let inner = match self . resolve_type ( typ) . kind {
438+ CTypeKind :: ConstantArray ( inner, 1 ) => inner,
439+ // Account for array-to-pointer decay in function parameters.
440+ CTypeKind :: Pointer ( CQualTypeId { ctype : inner, .. } ) => inner,
441+ _ => return false ,
442+ } ;
443+ let decl = match self . resolve_type ( inner) . kind {
444+ CTypeKind :: Struct ( decl) => decl,
445+ _ => return false ,
446+ } ;
447+ let name = match & self [ decl] . kind {
448+ CDeclKind :: Struct {
449+ name : Some ( name) , ..
450+ } => name,
451+ _ => return false ,
452+ } ;
414453
415- AAPCSABIBuiltinVaList => {
416- // The mechanism applies: va_list is a `struct __va_list { ... }` as per
417- // https://documentation-service.arm.com/static/5f201281bb903e39c84d7eae
418- // ("Procedure Call Standard for the Arm Architecture Release 2020Q2, Document
419- // number IHI 0042J") Section 8.1.4 "Additional Types"
420- self . is_va_list_struct ( typ)
454+ name == "__va_list_tag"
421455 }
422456
423- kind => unimplemented ! ( "va_list type {:?} not yet implemented" , kind) ,
457+ // TODO:
458+ PNaClABIBuiltinVaList => false ,
459+
460+ // TODO:
461+ SystemZBuiltinVaList => false ,
424462 }
425463 }
426464
465+ /// Returns whether `typ` is a C `va_list`.
466+ pub fn is_va_list ( & self , typ : CTypeId ) -> bool {
467+ self . is_builtin_va_list ( typ) || self . is_va_list_struct ( typ)
468+ }
469+
427470 /// Predicate for function pointers
428471 pub fn is_function_pointer ( & self , typ : CTypeId ) -> bool {
429472 let resolved_ctype = self . resolve_type ( typ) ;
0 commit comments