summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorVitaly Cheptsov <4348897+vit9696@users.noreply.github.com>2021-08-31 16:05:01 +0300
committerGitHub <noreply@github.com>2021-08-31 06:05:01 -0700
commitb1dbdc5e21346de0fec7fbb814dedbe1585bcfec (patch)
treef39a2416a742dcbf4193b96e7f8aa10c38d2618e /tests
parent302855a6f30bdec33614a145f1dbe031316f351a (diff)
downloadpycparser-b1dbdc5e21346de0fec7fbb814dedbe1585bcfec.tar.gz
Introduce partial C11 support (#429)
* Introduce partial C11 support Implemented _Noreturn, _Static_assert, _Thread_local. Also fixed tests with preprocessor on macOS. * Add more tests Co-authored-by: vit9696 <vit9696@users.noreply.github.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/c_files/c11.c31
-rw-r--r--tests/test_c_generator.py21
-rwxr-xr-xtests/test_c_parser.py19
-rw-r--r--tests/test_general.py31
-rw-r--r--tests/test_util.py16
5 files changed, 100 insertions, 18 deletions
diff --git a/tests/c_files/c11.c b/tests/c_files/c11.c
new file mode 100644
index 0000000..854feba
--- /dev/null
+++ b/tests/c_files/c11.c
@@ -0,0 +1,31 @@
+#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();
+}
diff --git a/tests/test_c_generator.py b/tests/test_c_generator.py
index 3c724a0..0cffa9e 100644
--- a/tests/test_c_generator.py
+++ b/tests/test_c_generator.py
@@ -7,6 +7,7 @@ import unittest
sys.path.insert(0, '.')
from pycparser import c_parser, c_generator, c_ast, parse_file
+from tests.test_util import cpp_supported, cpp_path, cpp_args
_c_parser = c_parser.CParser(
lex_optimize=False,
@@ -82,6 +83,9 @@ class TestCtoC(unittest.TestCase):
self._assert_ctoc_correct('int a;')
self._assert_ctoc_correct('int b, a;')
self._assert_ctoc_correct('int c, b, a;')
+ self._assert_ctoc_correct('auto int a;')
+ self._assert_ctoc_correct('register int a;')
+ self._assert_ctoc_correct('_Thread_local int a;')
def test_complex_decls(self):
self._assert_ctoc_correct('int** (*a)(void);')
@@ -246,6 +250,13 @@ class TestCtoC(unittest.TestCase):
int array[3] = {[0] = 0, [1] = 1, [1+1] = 2};
''')
+ def test_noreturn(self):
+ self._assert_ctoc_correct(r'''
+ _Noreturn int x(void) {
+ abort();
+ }
+ ''')
+
def test_exprlist_with_semi(self):
self._assert_ctoc_correct(r'''
void x() {
@@ -361,6 +372,10 @@ class TestCtoC(unittest.TestCase):
src = 'int x = ' + src + ';'
self._assert_ctoc_correct(src)
+ def test_static_assert(self):
+ self._assert_ctoc_correct('_Static_assert(sizeof(int) == sizeof(int), "123");')
+ self._assert_ctoc_correct('int main() { _Static_assert(sizeof(int) == sizeof(int), "123"); } ')
+
def test_reduce_parentheses_binaryops(self):
c1 = 'int x = a + b + c + d;';
self.assertEqual(self._run_c_to_c(c1), 'int x = ((a + b) + c) + d;\n')
@@ -408,14 +423,14 @@ class TestCasttoC(unittest.TestCase):
self.assertEqual(generator.visit(c_ast.Cast(int_type, test_fun)),
'(int) test_fun()')
- @unittest.skipUnless(platform.system() == 'Linux',
- 'cpp only works on Linux')
+ @unittest.skipUnless(cpp_supported(), 'cpp only works on Unix')
def test_to_type_with_cpp(self):
generator = c_generator.CGenerator()
test_fun = c_ast.FuncCall(c_ast.ID('test_fun'), c_ast.ExprList([]))
memmgr_path = self._find_file('memmgr.h')
- ast2 = parse_file(memmgr_path, use_cpp=True)
+ ast2 = parse_file(memmgr_path, use_cpp=True,
+ cpp_path = cpp_path(), cpp_args = cpp_args())
void_ptr_type = ast2.ext[-3].type.type
void_type = void_ptr_type.type
self.assertEqual(generator.visit(c_ast.Cast(void_ptr_type, test_fun)),
diff --git a/tests/test_c_parser.py b/tests/test_c_parser.py
index 270f2fb..f4a3744 100755
--- a/tests/test_c_parser.py
+++ b/tests/test_c_parser.py
@@ -40,6 +40,8 @@ def expand_decl(decl):
assert isinstance(decl.values, EnumeratorList)
values = [enum.name for enum in decl.values.enumerators]
return ['Enum', decl.name, values]
+ elif typ == StaticAssert:
+ return ['StaticAssert', decl.cond.value, decl.message.value]
else:
nested = expand_decl(decl.type)
@@ -520,6 +522,7 @@ class TestCParser_fundamentals(TestCParser_base):
self.assertEqual(d.storage, storage)
assert_qs("extern int p;", 0, [], ['extern'])
+ assert_qs("_Thread_local int p;", 0, [], ['_Thread_local'])
assert_qs("const long p = 6;", 0, ['const'], [])
d1 = "static const int p, q, r;"
@@ -1556,6 +1559,18 @@ class TestCParser_fundamentals(TestCParser_base):
[['ID', 'p']],
['TypeDecl', ['IdentifierType', ['int']]]]])
+ def test_static_assert(self):
+ f1 = self.parse('''
+ _Static_assert(1, "123");
+ int factorial(int p)
+ {
+ _Static_assert(2, "456");
+ }
+ ''')
+
+ self.assertEqual(expand_decl(f1.ext[0]), ['StaticAssert', '1', '"123"'])
+ self.assertEqual(expand_decl(f1.ext[1].body.block_items[0]), ['StaticAssert', '2', '"456"'])
+
def test_unified_string_literals(self):
# simple string, for reference
d1 = self.get_decl_init('char* s = "hello";')
@@ -1607,6 +1622,10 @@ class TestCParser_fundamentals(TestCParser_base):
ps2 = self.parse('static inline void inlinefoo(void);')
self.assertEqual(ps2.ext[0].funcspec, ['inline'])
+ def test_noreturn_specifier(self):
+ ps2 = self.parse('static _Noreturn void noreturnfoo(void);')
+ self.assertEqual(ps2.ext[0].funcspec, ['_Noreturn'])
+
# variable length array
def test_vla(self):
ps2 = self.parse(r'''
diff --git a/tests/test_general.py b/tests/test_general.py
index 18e388c..3d43cbf 100644
--- a/tests/test_general.py
+++ b/tests/test_general.py
@@ -5,9 +5,7 @@ import unittest
sys.path.insert(0, '..')
from pycparser import parse_file, c_ast
-
-CPPPATH = 'cpp'
-
+from tests.test_util import cpp_supported, cpp_path, cpp_args
# Test successful parsing
#
@@ -25,26 +23,22 @@ class TestParsing(unittest.TestCase):
ast = parse_file(self._find_file('example_c_file.c'))
self.assertIsInstance(ast, c_ast.FileAST)
- @unittest.skipUnless(platform.system() == 'Linux',
- 'cpp only works on Linux')
+ @unittest.skipUnless(cpp_supported(), 'cpp only works on Unix')
def test_with_cpp(self):
memmgr_path = self._find_file('memmgr.c')
c_files_path = os.path.dirname(memmgr_path)
ast = parse_file(memmgr_path, use_cpp=True,
- cpp_path=CPPPATH,
- cpp_args='-I%s' % c_files_path)
+ cpp_path=cpp_path(), cpp_args=cpp_args('-I%s' % c_files_path))
self.assertIsInstance(ast, c_ast.FileAST)
fake_libc = os.path.join(c_files_path, '..', '..',
'utils', 'fake_libc_include')
ast2 = parse_file(self._find_file('year.c'), use_cpp=True,
- cpp_path=CPPPATH,
- cpp_args=[r'-I%s' % fake_libc])
+ cpp_path=cpp_path(), cpp_args=cpp_args('-I%s' % fake_libc))
self.assertIsInstance(ast2, c_ast.FileAST)
- @unittest.skipUnless(platform.system() == 'Linux',
- 'cpp only works on Linux')
+ @unittest.skipUnless(cpp_supported(), 'cpp only works on Unix')
def test_cpp_funkydir(self):
# This test contains Windows specific path escapes
if sys.platform != 'win32':
@@ -52,16 +46,23 @@ class TestParsing(unittest.TestCase):
c_files_path = os.path.join('tests', 'c_files')
ast = parse_file(self._find_file('simplemain.c'), use_cpp=True,
- cpp_path=CPPPATH, cpp_args='-I%s' % c_files_path)
+ cpp_path=cpp_path(), cpp_args=cpp_args('-I%s' % c_files_path))
self.assertIsInstance(ast, c_ast.FileAST)
- @unittest.skipUnless(platform.system() == 'Linux',
- 'cpp only works on Linux')
+ @unittest.skipUnless(cpp_supported(), 'cpp only works on Unix')
def test_no_real_content_after_cpp(self):
ast = parse_file(self._find_file('empty.h'), use_cpp=True,
- cpp_path=CPPPATH)
+ cpp_path=cpp_path(), cpp_args=cpp_args())
self.assertIsInstance(ast, c_ast.FileAST)
+ @unittest.skipUnless(cpp_supported(), 'cpp only works on Unix')
+ def test_c11_with_cpp(self):
+ c_files_path = os.path.join('tests', 'c_files')
+ fake_libc = os.path.join(c_files_path, '..', '..',
+ 'utils', 'fake_libc_include')
+ ast = parse_file(self._find_file('c11.c'), use_cpp=True,
+ cpp_path=cpp_path(), cpp_args=cpp_args('-I%s' % fake_libc))
+ self.assertIsInstance(ast, c_ast.FileAST)
if __name__ == '__main__':
unittest.main()
diff --git a/tests/test_util.py b/tests/test_util.py
new file mode 100644
index 0000000..0b3365c
--- /dev/null
+++ b/tests/test_util.py
@@ -0,0 +1,16 @@
+import platform
+
+def cpp_supported():
+ return platform.system() == 'Linux' or platform.system() == 'Darwin'
+
+def cpp_path():
+ if platform.system() == 'Darwin':
+ return 'gcc'
+ return 'cpp'
+
+def cpp_args(args=[]):
+ if isinstance(args, str):
+ args = [args]
+ if platform.system() == 'Darwin':
+ return ['-E'] + args
+ return args