diff options
author | Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> | 2021-08-31 16:05:01 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-31 06:05:01 -0700 |
commit | b1dbdc5e21346de0fec7fbb814dedbe1585bcfec (patch) | |
tree | f39a2416a742dcbf4193b96e7f8aa10c38d2618e /tests | |
parent | 302855a6f30bdec33614a145f1dbe031316f351a (diff) | |
download | pycparser-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.c | 31 | ||||
-rw-r--r-- | tests/test_c_generator.py | 21 | ||||
-rwxr-xr-x | tests/test_c_parser.py | 19 | ||||
-rw-r--r-- | tests/test_general.py | 31 | ||||
-rw-r--r-- | tests/test_util.py | 16 |
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 |