summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitaly Cheptsov <4348897+vit9696@users.noreply.github.com>2021-09-20 16:18:41 +0300
committerGitHub <noreply@github.com>2021-09-20 06:18:41 -0700
commit77cb1fcda28965de518051d3db752b2dbbe4bf4a (patch)
tree9618845abfcf65c09f806e272bd8ca8730ba9a7b
parenta5e1958d4ab975057e0ce5358d1ac0329bb0cf74 (diff)
downloadpycparser-77cb1fcda28965de518051d3db752b2dbbe4bf4a.tar.gz
Improve _Atomic support and add more tests (#431)
* Improve _Atomic support with more tests and fix typedef handling * Remove duplicated tests and check the generated code for typedefs * Add typedef testing to parser as well Co-authored-by: vit9696 <vit9696@users.noreply.github.com>
-rw-r--r--pycparser/c_parser.py14
-rw-r--r--tests/c_files/c11.c69
-rw-r--r--tests/test_c_generator.py22
-rwxr-xr-xtests/test_c_parser.py14
-rw-r--r--utils/fake_libc_include/_fake_defines.h15
-rw-r--r--utils/fake_libc_include/_fake_typedefs.h48
-rw-r--r--utils/fake_libc_include/stdatomic.h2
7 files changed, 150 insertions, 34 deletions
diff --git a/pycparser/c_parser.py b/pycparser/c_parser.py
index ad7ae50..0f026eb 100644
--- a/pycparser/c_parser.py
+++ b/pycparser/c_parser.py
@@ -779,6 +779,13 @@ class CParser(PLYParser):
"""
p[0] = self._add_declaration_specifier(p[2], p[1], 'function')
+ # This is a bit ugly, but we need to process atomic specifier before qualifiers
+ # for _Atomic(x) in typedefs.
+ def p_declaration_specifiers_no_type_4(self, p):
+ """ declaration_specifiers_no_type : atomic_specifier declaration_specifiers_no_type_opt
+ """
+ p[0] = self._add_declaration_specifier(p[2], p[1], 'type')
+
def p_declaration_specifiers_1(self, p):
""" declaration_specifiers : declaration_specifiers type_qualifier
"""
@@ -841,17 +848,18 @@ class CParser(PLYParser):
"""
p[0] = c_ast.IdentifierType([p[1]], coord=self._token_coord(p, 1))
- def p_type_specifier_1(self, p):
+ def p_type_specifier(self, p):
""" type_specifier : typedef_name
| enum_specifier
| struct_or_union_specifier
| type_specifier_no_typeid
+ | atomic_specifier
"""
p[0] = p[1]
# See section 6.7.2.4 of the C11 standard.
- def p_type_specifier_2(self, p):
- """ type_specifier : _ATOMIC LPAREN type_name RPAREN
+ def p_atomic_specifier(self, p):
+ """ atomic_specifier : _ATOMIC LPAREN type_name RPAREN
"""
typ = p[3]
typ.quals.append('_Atomic')
diff --git a/tests/c_files/c11.c b/tests/c_files/c11.c
index 854feba..3c57f55 100644
--- a/tests/c_files/c11.c
+++ b/tests/c_files/c11.c
@@ -1,31 +1,38 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdnoreturn.h>
-#include <threads.h>
-#include <assert.h>
-
-/* C11 thread locals */
-_Thread_local int flag;
-thread_local int flag2;
-
-static_assert(sizeof(flag) == sizeof(flag2), "Really unexpected size difference");
-
-noreturn void func2(void)
-{
- abort();
-}
-
-_Noreturn void func(void)
-{
- func2();
-}
-
-int main()
-{
- _Static_assert(sizeof(flag) == sizeof(flag2), "Unexpected size difference");
- static_assert(sizeof(flag) == sizeof(flag2), "Unexpected size difference");
-
- printf("Flag: %d\n", flag);
- printf("Flag2: %d\n", flag2);
- func();
-}
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdnoreturn.h>
+#include <threads.h>
+#include <assert.h>
+#include <stdatomic.h>
+
+/* C11 thread locals */
+_Thread_local int flag;
+thread_local int flag2;
+_Atomic int flag3;
+_Atomic(int) flag4;
+_Atomic(_Atomic(int) *) flag5;
+atomic_bool flag6;
+
+static_assert(sizeof(flag) == sizeof(flag2), "Really unexpected size difference");
+
+noreturn void func2(void)
+{
+ abort();
+}
+
+_Noreturn void func(void)
+{
+ func2();
+}
+
+int main()
+{
+ _Static_assert(sizeof(flag) == sizeof(flag2), "Unexpected size difference");
+ static_assert(sizeof(flag) == sizeof(flag2), "Unexpected size difference");
+ static_assert(sizeof(flag) == sizeof(flag3), "Unexpected size difference");
+ static_assert(sizeof(flag) == sizeof(flag4), "Unexpected size difference");
+
+ printf("Flag: %d\n", flag);
+ printf("Flag2: %d\n", flag2);
+ func();
+}
diff --git a/tests/test_c_generator.py b/tests/test_c_generator.py
index 0926b15..bcbdfcc 100644
--- a/tests/test_c_generator.py
+++ b/tests/test_c_generator.py
@@ -392,6 +392,28 @@ class TestCtoC(unittest.TestCase):
self.assertEqual(c3, '_Atomic int * _Atomic x;\n')
self._assert_ctoc_correct(s3)
+ # FIXME: Regeneration with multiple qualifiers is not fully supported.
+ # REF: https://github.com/eliben/pycparser/issues/433
+ # self._assert_ctoc_correct('auto const _Atomic(int *) a;')
+
+ s4 = 'typedef _Atomic(int) atomic_int;'
+ c4 = self._run_c_to_c(s4)
+ self.assertEqual(c4, 'typedef _Atomic int atomic_int;\n')
+ self._assert_ctoc_correct(s4)
+
+ s5 = 'typedef _Atomic(_Atomic(_Atomic(int (*)(void)) *) *) t;'
+ c5 = self._run_c_to_c(s5)
+ self.assertEqual(c5, 'typedef int (* _Atomic * _Atomic * _Atomic t)(void);\n')
+ self._assert_ctoc_correct(s5)
+
+ self._assert_ctoc_correct(r'''
+ typedef struct node_t {
+ _Atomic(void*) a;
+ _Atomic(void) *b;
+ _Atomic void *c;
+ } node;
+ ''')
+
def test_nested_sizeof(self):
src = '1'
for _ in range(30):
diff --git a/tests/test_c_parser.py b/tests/test_c_parser.py
index 40b53af..7e6a648 100755
--- a/tests/test_c_parser.py
+++ b/tests/test_c_parser.py
@@ -572,6 +572,20 @@ class TestCParser_fundamentals(TestCParser_base):
'bar',
['TypeDecl', ['IdentifierType', ['int']]]])
+ # typedefs with _Atomic specifiers.
+ s = 'typedef _Atomic(int) atomic_int;'
+ self.assertEqual(self.get_decl(s, 0),
+ ['Typedef', 'atomic_int', ['TypeDecl', ['IdentifierType', ['int']]]])
+
+ s = 'typedef _Atomic(_Atomic(_Atomic(int (*)(void)) *) *) t;'
+ self.assertEqual(self.get_decl(s, 0),
+ ['Typedef', 't',
+ ['PtrDecl', ['_Atomic'],
+ ['PtrDecl', ['_Atomic'],
+ ['PtrDecl', ['_Atomic'],
+ ['FuncDecl', [['Typename', ['TypeDecl', ['IdentifierType', ['void']]]]],
+ ['TypeDecl', ['IdentifierType', ['int']]]]]]]])
+
def test_sizeof(self):
e = """
void foo()
diff --git a/utils/fake_libc_include/_fake_defines.h b/utils/fake_libc_include/_fake_defines.h
index f2e8dd4..86b5c66 100644
--- a/utils/fake_libc_include/_fake_defines.h
+++ b/utils/fake_libc_include/_fake_defines.h
@@ -236,4 +236,19 @@
/* C11 assert.h defines */
#define static_assert _Static_assert
+/* C11 stdatomic.h defines */
+#define ATOMIC_BOOL_LOCK_FREE 0
+#define ATOMIC_CHAR_LOCK_FREE 0
+#define ATOMIC_CHAR16_T_LOCK_FREE 0
+#define ATOMIC_CHAR32_T_LOCK_FREE 0
+#define ATOMIC_WCHAR_T_LOCK_FREE 0
+#define ATOMIC_SHORT_LOCK_FREE 0
+#define ATOMIC_INT_LOCK_FREE 0
+#define ATOMIC_LONG_LOCK_FREE 0
+#define ATOMIC_LLONG_LOCK_FREE 0
+#define ATOMIC_POINTER_LOCK_FREE 0
+#define ATOMIC_VAR_INIT(value) (value)
+#define ATOMIC_FLAG_INIT { 0 }
+#define kill_dependency(y) (y)
+
#endif
diff --git a/utils/fake_libc_include/_fake_typedefs.h b/utils/fake_libc_include/_fake_typedefs.h
index dfcc653..9a85d40 100644
--- a/utils/fake_libc_include/_fake_typedefs.h
+++ b/utils/fake_libc_include/_fake_typedefs.h
@@ -169,4 +169,52 @@ typedef struct xcb_connection_t xcb_connection_t;
typedef uint32_t xcb_window_t;
typedef uint32_t xcb_visualid_t;
+/* C11 stdatomic.h types */
+typedef _Atomic(_Bool) atomic_bool;
+typedef _Atomic(char) atomic_char;
+typedef _Atomic(signed char) atomic_schar;
+typedef _Atomic(unsigned char) atomic_uchar;
+typedef _Atomic(short) atomic_short;
+typedef _Atomic(unsigned short) atomic_ushort;
+typedef _Atomic(int) atomic_int;
+typedef _Atomic(unsigned int) atomic_uint;
+typedef _Atomic(long) atomic_long;
+typedef _Atomic(unsigned long) atomic_ulong;
+typedef _Atomic(long long) atomic_llong;
+typedef _Atomic(unsigned long long) atomic_ullong;
+typedef _Atomic(uint_least16_t) atomic_char16_t;
+typedef _Atomic(uint_least32_t) atomic_char32_t;
+typedef _Atomic(wchar_t) atomic_wchar_t;
+typedef _Atomic(int_least8_t) atomic_int_least8_t;
+typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
+typedef _Atomic(int_least16_t) atomic_int_least16_t;
+typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
+typedef _Atomic(int_least32_t) atomic_int_least32_t;
+typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
+typedef _Atomic(int_least64_t) atomic_int_least64_t;
+typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
+typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
+typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
+typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
+typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
+typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
+typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
+typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
+typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
+typedef _Atomic(intptr_t) atomic_intptr_t;
+typedef _Atomic(uintptr_t) atomic_uintptr_t;
+typedef _Atomic(size_t) atomic_size_t;
+typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
+typedef _Atomic(intmax_t) atomic_intmax_t;
+typedef _Atomic(uintmax_t) atomic_uintmax_t;
+typedef struct atomic_flag { atomic_bool _Value; } atomic_flag;
+typedef enum memory_order {
+ memory_order_relaxed,
+ memory_order_consume,
+ memory_order_acquire,
+ memory_order_release,
+ memory_order_acq_rel,
+ memory_order_seq_cst
+} memory_order;
+
#endif
diff --git a/utils/fake_libc_include/stdatomic.h b/utils/fake_libc_include/stdatomic.h
new file mode 100644
index 0000000..f952c1d
--- /dev/null
+++ b/utils/fake_libc_include/stdatomic.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"