summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2017-02-27 08:46:05 +0100
committerArmin Rigo <arigo@tunes.org>2017-02-27 08:46:05 +0100
commit7cc4e2309282e5da740ba1c682563cd07342d062 (patch)
tree8e8e2f4e8162a39a810c7c653a70799031e2c811
parentbca987808120f90c3dff357400c3a9cf48498251 (diff)
downloadcffi-7cc4e2309282e5da740ba1c682563cd07342d062.tar.gz
Issue #310: pycparser was recently made stricter and no longer parses
``typedef int __dotdotdot__ foo_t;``. I think this fixes it
-rw-r--r--cffi/cparser.py59
-rw-r--r--testing/cffi0/test_verify.py4
2 files changed, 37 insertions, 26 deletions
diff --git a/cffi/cparser.py b/cffi/cparser.py
index 87d71b1..3d5caed 100644
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -34,6 +34,9 @@ _r_extern_python = re.compile(r'\bextern\s*"'
r'(Python|Python\s*\+\s*C|C\s*\+\s*Python)"\s*.')
_r_star_const_space = re.compile( # matches "* const "
r"[*]\s*((const|volatile|restrict)\b\s*)+")
+_r_int_dotdotdot = re.compile(r"(\b(int|long|short|signed|unsigned|char)\s*)+"
+ r"\.\.\.")
+_r_float_dotdotdot = re.compile(r"\b(double|float)\s*\.\.\.")
def _get_parser():
global _parser_cache
@@ -180,6 +183,10 @@ def _preprocess(csource):
assert csource[p:p+3] == '...'
csource = '%s __dotdotdot%d__ %s' % (csource[:p], number,
csource[p+3:])
+ # Replace "int ..." or "unsigned long int..." with "__dotdotdotint__"
+ csource = _r_int_dotdotdot.sub(' __dotdotdotint__ ', csource)
+ # Replace "float ..." or "double..." with "__dotdotdotfloat__"
+ csource = _r_float_dotdotdot.sub(' __dotdotdotfloat__ ', csource)
# Replace all remaining "..." with the same name, "__dotdotdot__",
# which is declared with a typedef for the purpose of C parsing.
return csource.replace('...', ' __dotdotdot__ '), macros
@@ -252,7 +259,8 @@ class Parser(object):
typenames += sorted(ctn)
#
csourcelines = ['typedef int %s;' % typename for typename in typenames]
- csourcelines.append('typedef int __dotdotdot__;')
+ csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,'
+ ' __dotdotdot__;')
csourcelines.append(csource)
csource = '\n'.join(csourcelines)
if lock is not None:
@@ -311,6 +319,8 @@ class Parser(object):
for decl in iterator:
if decl.name == '__dotdotdot__':
break
+ else:
+ assert 0
#
try:
self._inside_extern_python = '__cffi_extern_python_stop'
@@ -322,15 +332,15 @@ class Parser(object):
raise CDefError("typedef does not declare any name",
decl)
quals = 0
- if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType)
- and decl.type.type.names[-1] == '__dotdotdot__'):
+ if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and
+ decl.type.type.names[-1].startswith('__dotdotdot')):
realtype = self._get_unknown_type(decl)
elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and
isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and
isinstance(decl.type.type.type,
pycparser.c_ast.IdentifierType) and
- decl.type.type.type.names == ['__dotdotdot__']):
- realtype = model.unknown_ptr_type(decl.name)
+ decl.type.type.type.names[-1].startswith('__dotdotdot')):
+ realtype = self._get_unknown_ptr_type(decl)
else:
realtype, quals = self._get_type_and_quals(
decl.type, name=decl.name, partial_length_ok=True)
@@ -832,24 +842,25 @@ class Parser(object):
def _get_unknown_type(self, decl):
typenames = decl.type.type.names
- assert typenames[-1] == '__dotdotdot__'
- if len(typenames) == 1:
+ if typenames == ['__dotdotdot__']:
return model.unknown_type(decl.name)
- if (typenames[:-1] == ['float'] or
- typenames[:-1] == ['double']):
- # not for 'long double' so far
- result = model.UnknownFloatType(decl.name)
- else:
- for t in typenames[:-1]:
- if t not in ['int', 'short', 'long', 'signed',
- 'unsigned', 'char']:
- raise FFIError(':%d: bad usage of "..."' %
- decl.coord.line)
- result = model.UnknownIntegerType(decl.name)
-
- if self._uses_new_feature is None:
- self._uses_new_feature = "'typedef %s... %s'" % (
- ' '.join(typenames[:-1]), decl.name)
-
- return result
+ if typenames == ['__dotdotdotint__']:
+ if self._uses_new_feature is None:
+ self._uses_new_feature = "'typedef int... %s'" % decl.name
+ return model.UnknownIntegerType(decl.name)
+
+ if typenames == ['__dotdotdotfloat__']:
+ # note: not for 'long double' so far
+ if self._uses_new_feature is None:
+ self._uses_new_feature = "'typedef float... %s'" % decl.name
+ return model.UnknownFloatType(decl.name)
+
+ raise FFIError(':%d: unsupported usage of "..." in typedef'
+ % decl.coord.line)
+
+ def _get_unknown_ptr_type(self, decl):
+ if decl.type.type.type.names == ['__dotdotdot__']:
+ return model.unknown_ptr_type(decl.name)
+ raise FFIError(':%d: unsupported usage of "..." in typedef'
+ % decl.coord.line)
diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py
index e600908..25430bd 100644
--- a/testing/cffi0/test_verify.py
+++ b/testing/cffi0/test_verify.py
@@ -2246,10 +2246,10 @@ def test_dont_support_int_dotdotdot():
assert str(e.value) == ("feature not supported with ffi.verify(), but only "
"with ffi.set_source(): 'typedef int... t1'")
ffi = FFI()
- ffi.cdef("typedef unsigned long... t1;")
+ ffi.cdef("typedef double ... t1;")
e = py.test.raises(VerificationError, ffi.verify, "")
assert str(e.value) == ("feature not supported with ffi.verify(), but only "
- "with ffi.set_source(): 'typedef unsigned long... t1'")
+ "with ffi.set_source(): 'typedef float... t1'")
def test_const_fields():
ffi = FFI()