Skip to content

Commit b714e5b

Browse files
committed
Fixes for type traits handling of cv-qualified array types
cv-qualified arrays were not being handled correctly by type traits manipulations functions. For instance, 'int const[N]' would not be detected as 'const'. Similar problems existed for volatile qualified arrays too. There is a difference in behavior between GCCXML and CastXML for cv-qual arrays. GCCXML produces the following nesting of types: -> volatile_t(const_t(array_t)) while CastXML produces the following nesting: -> array_t(volatile_t(const_t)) For both cases, we must unwrap the types, remove const_t, and add back the outer layers. Prior to CastXML/CastXML#55 being fixed, CastXML would incorrectly generate default constructor definitions for types with const data members. This caused pygccxml to incorrectly flag such types as trivially constructible. These tests have now been fixed, and the tests are being executed conditionally only for GCCXML (which handles them correctly), or, if CastXML is being used, then for xml_output_version >= 1.138. gccxml places cv-qualifiers to the right of the array declarator in the decl_string. For instance, given the declaration 'int const[arr[42]', the decl_string from gccxml is 'int [42] const'. Combined type_traits_castxml.hpp and type_traits_gccxml.hpp into a single file - type_traits.hpp. Change-Id: If5deaecf4cc9ab38cb8b8ac90befa9c62ebd0106
1 parent 1c09779 commit b714e5b

File tree

5 files changed

+190
-897
lines changed

5 files changed

+190
-897
lines changed

pygccxml/declarations/type_traits.py

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -284,19 +284,46 @@ def remove_reference(type):
284284
def is_const(type):
285285
"""returns True, if type represents C++ const type, False otherwise"""
286286
nake_type = remove_alias(type)
287-
return isinstance(nake_type, cpptypes.const_t)
287+
if isinstance(nake_type, cpptypes.const_t):
288+
return True
289+
elif isinstance(nake_type, cpptypes.volatile_t):
290+
return is_const(nake_type.base)
291+
elif isinstance(nake_type, cpptypes.array_t):
292+
return is_const(nake_type.base)
293+
return False
288294

289295

290-
def remove_const(type):
296+
def remove_const(type_):
291297
"""removes const from the type definition
292298
293299
If type is not const type, it will be returned as is
294300
"""
295301

296-
nake_type = remove_alias(type)
302+
nake_type = remove_alias(type_)
297303
if not is_const(nake_type):
298-
return type
304+
return type_
299305
else:
306+
# Handling for const and volatile qualified types. There is a
307+
# difference in behavior between GCCXML and CastXML for cv-qual arrays.
308+
# GCCXML produces the following nesting of types:
309+
# -> volatile_t(const_t(array_t))
310+
# while CastXML produces the following nesting:
311+
# -> array_t(volatile_t(const_t))
312+
# For both cases, we must unwrap the types, remove const_t, and add
313+
# back the outer layers
314+
if isinstance(nake_type, cpptypes.array_t):
315+
is_v = is_volatile(nake_type)
316+
if is_v:
317+
result_type = nake_type.base.base.base
318+
else:
319+
result_type = nake_type.base.base
320+
if is_v:
321+
result_type = cpptypes.volatile_t(result_type)
322+
return cpptypes.array_t(result_type, nake_type.size)
323+
324+
elif isinstance(nake_type, cpptypes.volatile_t):
325+
return cpptypes.volatile_t(nake_type.base.base)
326+
300327
return nake_type.base
301328

302329

@@ -322,7 +349,13 @@ def is_same(type1, type2):
322349
def is_volatile(type):
323350
"""returns True, if type represents C++ volatile type, False otherwise"""
324351
nake_type = remove_alias(type)
325-
return isinstance(nake_type, cpptypes.volatile_t)
352+
if isinstance(nake_type, cpptypes.volatile_t):
353+
return True
354+
elif isinstance(nake_type, cpptypes.const_t):
355+
return is_volatile(nake_type.base)
356+
elif isinstance(nake_type, cpptypes.array_t):
357+
return is_volatile(nake_type.base)
358+
return False
326359

327360

328361
def remove_volatile(type):
@@ -334,6 +367,16 @@ def remove_volatile(type):
334367
if not is_volatile(nake_type):
335368
return type
336369
else:
370+
if isinstance(nake_type, cpptypes.array_t):
371+
is_c = is_const(nake_type)
372+
if is_c:
373+
base_type = nake_type.base.base.base
374+
else:
375+
base_type = nake_type.base.base
376+
result_type = base_type
377+
if is_c:
378+
result_type = cpptypes.const_t(result_type)
379+
return cpptypes.array_t(result_type, nake_type.size)
337380
return nake_type.base
338381

339382

@@ -344,12 +387,12 @@ def remove_cv(type):
344387
if not is_const(nake_type) and not is_volatile(nake_type):
345388
return type
346389
result = nake_type
347-
if is_const(nake_type):
348-
result = nake_type.base
390+
if is_const(result):
391+
result = remove_const(result)
349392
if is_volatile(result):
350-
result = result.base
393+
result = remove_volatile(result)
351394
if is_const(result):
352-
result = result.base
395+
result = remove_const(result)
353396
return result
354397

355398

unittests/array_bug_tester.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,65 @@ def test4(self):
5555
'::xyz[2][3]' == aaaa_type.decl_string,
5656
aaaa_type.decl_string)
5757

58+
def test5(self):
59+
code = 'char const arr[4] = {};'
60+
src_reader = parser.source_reader_t(self.config)
61+
global_ns = declarations.get_global_namespace(
62+
src_reader.read_string(code))
63+
arr_type = global_ns.variable('arr').decl_type
64+
if self.config.xml_generator == "gccxml":
65+
self.assertTrue(
66+
'char[4] const' == arr_type.decl_string,
67+
arr_type.decl_string)
68+
else:
69+
self.assertTrue(
70+
'char const[4]' == arr_type.decl_string,
71+
arr_type.decl_string)
72+
self.assertTrue(
73+
declarations.is_array(arr_type))
74+
self.assertTrue(
75+
declarations.is_const(arr_type))
76+
77+
def test6(self):
78+
code = 'char volatile arr[4] = {};'
79+
src_reader = parser.source_reader_t(self.config)
80+
global_ns = declarations.get_global_namespace(
81+
src_reader.read_string(code))
82+
arr_type = global_ns.variable('arr').decl_type
83+
if self.config.xml_generator == "gccxml":
84+
self.assertTrue(
85+
'char[4] volatile' == arr_type.decl_string,
86+
arr_type.decl_string)
87+
else:
88+
self.assertTrue(
89+
'char volatile[4]' == arr_type.decl_string,
90+
arr_type.decl_string)
91+
self.assertTrue(
92+
declarations.is_array(arr_type))
93+
self.assertTrue(
94+
declarations.is_volatile(arr_type))
95+
96+
def test7(self):
97+
code = 'char const volatile arr[4] = {};'
98+
src_reader = parser.source_reader_t(self.config)
99+
global_ns = declarations.get_global_namespace(
100+
src_reader.read_string(code))
101+
arr_type = global_ns.variable('arr').decl_type
102+
if self.config.xml_generator == "gccxml":
103+
self.assertTrue(
104+
'char[4] const volatile' == arr_type.decl_string,
105+
arr_type.decl_string)
106+
else:
107+
self.assertTrue(
108+
'char const volatile[4]' == arr_type.decl_string,
109+
arr_type.decl_string)
110+
self.assertTrue(
111+
declarations.is_array(arr_type))
112+
self.assertTrue(
113+
declarations.is_const(arr_type))
114+
self.assertTrue(
115+
declarations.is_volatile(arr_type))
116+
58117

59118
def create_suite():
60119
suite = unittest.TestSuite()

unittests/data/type_traits_gccxml.hpp renamed to unittests/data/type_traits.hpp

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
typedef BASE volatile NAME##_volatile_t; \
2020
typedef BASE const volatile NAME##_const_volatile_t;
2121

22+
2223
struct some_struct_t{
2324
void do_smth();
2425
int member;
@@ -47,9 +48,7 @@ struct incomplete_type;
4748

4849
namespace is_void{
4950
namespace yes{
50-
typedef void void_t;
51-
typedef void const void_cont_t;
52-
typedef void volatile void_volatile_t;
51+
TYPE_PERMUTATION( void, void )
5352
}
5453
namespace no{
5554
typedef void* void_ptr_t;
@@ -186,7 +185,6 @@ namespace yes{
186185
typedef detail::dd_t dd_t;
187186
typedef detail::f_t f_t;
188187
typedef detail::g_t g_t;
189-
190188
typedef detail::const_container const_container_t;
191189
typedef detail::const_item const_item_t;
192190

@@ -287,11 +285,6 @@ namespace no{
287285
namespace is_fundamental{
288286
namespace yes{
289287

290-
#define FUNDAMENTAL_TYPE_PERMUTATION( BASE, NAME ) \
291-
typedef BASE NAME##_t; \
292-
typedef BASE const NAME##_const_t; \
293-
typedef BASE volatile NAME##_volatile_t;
294-
295288
TYPE_PERMUTATION( void, void )
296289
TYPE_PERMUTATION( bool, bool )
297290
TYPE_PERMUTATION( char, char )
@@ -409,7 +402,8 @@ namespace yes{
409402
typedef const void const_void_t;
410403
typedef const incomplete_type const_incomplete_type_t;
411404
typedef int* const int_const_t;
412-
//TODO typedef const int& const_int_ref_t;
405+
typedef int* volatile const int_volatile_const_t;
406+
typedef int* const volatile int_const_volatile_t;
413407
}
414408

415409
namespace no{
@@ -421,32 +415,53 @@ namespace no{
421415
typedef void(*function_t)();
422416
typedef void (some_struct_t::*member_function_t)();
423417
typedef int int_t;
418+
typedef const int& const_int_ref_t;
424419
} }
425420

426421
namespace remove_const{
427422
namespace before{
428-
429423
typedef const void x1;
430424
typedef const incomplete_type x2;
431425
typedef int* const x3;
432426
typedef int* volatile x4;
427+
typedef void const * x5;
428+
typedef int volatile const x6;
429+
typedef int const volatile x7;
430+
431+
typedef char arr_42[42];
432+
typedef char const arr_c_42[42];
433+
typedef char volatile arr_v_42[42];
434+
typedef char const volatile arr_cv_42[42];
435+
typedef char volatile const arr_vc_42[42];
433436
}
434437

435438
namespace after{
436439
typedef void x1;
437440
typedef incomplete_type x2;
438441
typedef int* x3;
439442
typedef int* volatile x4;
443+
typedef void const * x5;
444+
typedef int volatile x6;
445+
typedef int volatile x7;
446+
447+
typedef char arr_42[42];
448+
typedef char arr_c_42[42];
449+
typedef char volatile arr_v_42[42];
450+
typedef char volatile arr_cv_42[42];
451+
typedef char volatile arr_vc_42[42];
440452
} }
441453

442454
namespace is_volatile{
443455
namespace yes{
444456

445457
typedef void * volatile vvoid_ptr_t;
446458
typedef volatile int volatile_int_t;
459+
typedef int* volatile const int_volatile_const_t;
460+
typedef int* const volatile int_const_volatile_t;
447461
}
448462

449463
namespace no{
464+
typedef void volatile * void_ptr_to_v_t;
450465
typedef int* int_ptr_t;
451466
typedef const int* const_int_ptr_t;
452467
typedef int* volatile_int_ptr_t;
@@ -463,12 +478,30 @@ namespace before{
463478
typedef void * volatile x1;
464479
typedef volatile int x2;
465480
typedef int* x3;
481+
typedef void volatile * x4;
482+
typedef int volatile const x5;
483+
typedef int const volatile x6;
484+
485+
typedef char arr_42[42];
486+
typedef char const arr_c_42[42];
487+
typedef char volatile arr_v_42[42];
488+
typedef char const volatile arr_cv_42[42];
489+
typedef char volatile const arr_vc_42[42];
466490
}
467491

468492
namespace after{
469493
typedef void * x1;
470494
typedef int x2;
471495
typedef int* x3;
496+
typedef void volatile * x4;
497+
typedef int const x5;
498+
typedef int const x6;
499+
500+
typedef char arr_42[42];
501+
typedef char const arr_c_42[42];
502+
typedef char arr_v_42[42];
503+
typedef char const arr_cv_42[42];
504+
typedef char const arr_vc_42[42];
472505
} }
473506

474507

@@ -488,6 +521,12 @@ namespace before{
488521
typedef int* const x32;
489522

490523
typedef void(*x40)();
524+
525+
typedef char arr_42[42];
526+
typedef char const arr_c_42[42];
527+
typedef char volatile arr_v_42[42];
528+
typedef char const volatile arr_cv_42[42];
529+
typedef char volatile const arr_vc_42[42];
491530
}
492531

493532
namespace after{
@@ -504,6 +543,12 @@ namespace after{
504543
typedef int* x32;
505544

506545
typedef void(*x40)();
546+
547+
typedef char arr_42[42];
548+
typedef char arr_c_42[42];
549+
typedef char arr_v_42[42];
550+
typedef char arr_cv_42[42];
551+
typedef char arr_vc_42[42];
507552
} }
508553

509554

@@ -548,9 +593,6 @@ namespace yes{
548593

549594
namespace no{
550595

551-
typedef details::const_item const_item;
552-
typedef details::const_container const_container;
553-
554596
class y{
555597
private:
556598
y(){}
@@ -567,6 +609,9 @@ namespace no{
567609
public:
568610
static singleton_t* instance();
569611
};
612+
613+
typedef details::const_item const_item;
614+
typedef details::const_container const_container;
570615
} }
571616

572617
namespace has_public_constructor{
@@ -663,6 +708,7 @@ namespace yes{
663708
const int yes2[2] = {0};
664709
const volatile int yes3[2] = {0};
665710
int yes4[2][3];
711+
int const yes5[2] = {0};
666712
}
667713

668714
namespace no{

0 commit comments

Comments
 (0)