Commit cd4d9281 authored by Lisandro Dalcin's avatar Lisandro Dalcin

merge

parents 857606e7 aca194ad
...@@ -1553,9 +1553,9 @@ class IndexNode(ExprNode): ...@@ -1553,9 +1553,9 @@ class IndexNode(ExprNode):
self.index.analyse_types(env, skip_children=skip_child_analysis) self.index.analyse_types(env, skip_children=skip_child_analysis)
elif not skip_child_analysis: elif not skip_child_analysis:
self.index.analyse_types(env) self.index.analyse_types(env)
self.original_index_type = self.index.type
if self.base.type.is_pyobject: if self.base.type.is_pyobject:
if self.index.type.is_int and not self.index.type.is_longlong: if self.index.type.is_int and not self.index.type.is_longlong:
self.original_index_type = self.index.type
self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env) self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env)
else: else:
self.index = self.index.coerce_to_pyobject(env) self.index = self.index.coerce_to_pyobject(env)
......
...@@ -84,13 +84,13 @@ class Context: ...@@ -84,13 +84,13 @@ class Context:
from AutoDocTransforms import EmbedSignature from AutoDocTransforms import EmbedSignature
from Optimize import FlattenInListTransform, SwitchTransform, FinalOptimizePhase from Optimize import FlattenInListTransform, SwitchTransform, FinalOptimizePhase
from Buffer import IntroduceBufferAuxiliaryVars from Buffer import IntroduceBufferAuxiliaryVars
from ModuleNode import check_c_classes from ModuleNode import check_c_declarations
if pxd: if pxd:
_check_c_classes = None _check_c_declarations = None
_specific_post_parse = PxdPostParse(self) _specific_post_parse = PxdPostParse(self)
else: else:
_check_c_classes = check_c_classes _check_c_declarations = check_c_declarations
_specific_post_parse = None _specific_post_parse = None
if py and not pxd: if py and not pxd:
...@@ -111,7 +111,7 @@ class Context: ...@@ -111,7 +111,7 @@ class Context:
EmbedSignature(self), EmbedSignature(self),
TransformBuiltinMethods(self), TransformBuiltinMethods(self),
IntroduceBufferAuxiliaryVars(self), IntroduceBufferAuxiliaryVars(self),
_check_c_classes, _check_c_declarations,
AnalyseExpressionsTransform(self), AnalyseExpressionsTransform(self),
SwitchTransform(), SwitchTransform(),
FinalOptimizePhase(self), FinalOptimizePhase(self),
......
...@@ -26,8 +26,9 @@ from Cython.Utils import open_new_file, replace_suffix, UtilityCode ...@@ -26,8 +26,9 @@ from Cython.Utils import open_new_file, replace_suffix, UtilityCode
from StringEncoding import escape_byte_string, EncodedString from StringEncoding import escape_byte_string, EncodedString
def check_c_classes(module_node): def check_c_declarations(module_node):
module_node.scope.check_c_classes() module_node.scope.check_c_classes()
module_node.scope.check_c_functions()
return module_node return module_node
class ModuleNode(Nodes.Node, Nodes.BlockNode): class ModuleNode(Nodes.Node, Nodes.BlockNode):
......
...@@ -1925,7 +1925,7 @@ class DefNode(FuncDefNode): ...@@ -1925,7 +1925,7 @@ class DefNode(FuncDefNode):
positional_args, kw_only_args, argtuple_error_label, code) positional_args, kw_only_args, argtuple_error_label, code)
# --- optimised code when we do not receive any keyword arguments # --- optimised code when we do not receive any keyword arguments
if min_positional_args > 0 or min_positional_args == max_positional_args: if (self.num_required_kw_args and min_positional_args > 0) or min_positional_args == max_positional_args:
# Python raises arg tuple related errors first, so we must # Python raises arg tuple related errors first, so we must
# check the length here # check the length here
if min_positional_args == max_positional_args and not self.star_arg: if min_positional_args == max_positional_args and not self.star_arg:
...@@ -1951,6 +1951,7 @@ class DefNode(FuncDefNode): ...@@ -1951,6 +1951,7 @@ class DefNode(FuncDefNode):
len(positional_args) + i)) len(positional_args) + i))
code.putln(code.error_goto(self.pos)) code.putln(code.error_goto(self.pos))
break break
elif min_positional_args == max_positional_args: elif min_positional_args == max_positional_args:
# parse the exact number of positional arguments from the # parse the exact number of positional arguments from the
# args tuple # args tuple
...@@ -1958,11 +1959,14 @@ class DefNode(FuncDefNode): ...@@ -1958,11 +1959,14 @@ class DefNode(FuncDefNode):
for i, arg in enumerate(positional_args): for i, arg in enumerate(positional_args):
item = "PyTuple_GET_ITEM(%s, %d)" % (Naming.args_cname, i) item = "PyTuple_GET_ITEM(%s, %d)" % (Naming.args_cname, i)
self.generate_arg_assignment(arg, item, code) self.generate_arg_assignment(arg, item, code)
else: else:
# parse the positional arguments from the variable length # parse the positional arguments from the variable length
# args tuple # args tuple
code.putln('} else {') code.putln('} else {')
code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname) code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
if self.star_arg:
code.putln('default:')
reversed_args = list(enumerate(positional_args))[::-1] reversed_args = list(enumerate(positional_args))[::-1]
for i, arg in reversed_args: for i, arg in reversed_args:
if i >= min_positional_args-1: if i >= min_positional_args-1:
...@@ -1972,10 +1976,15 @@ class DefNode(FuncDefNode): ...@@ -1972,10 +1976,15 @@ class DefNode(FuncDefNode):
code.put('case %2d: ' % (i+1)) code.put('case %2d: ' % (i+1))
item = "PyTuple_GET_ITEM(%s, %d)" % (Naming.args_cname, i) item = "PyTuple_GET_ITEM(%s, %d)" % (Naming.args_cname, i)
self.generate_arg_assignment(arg, item, code) self.generate_arg_assignment(arg, item, code)
if not self.star_arg:
if min_positional_args == 0: if min_positional_args == 0:
code.put('case 0: ') code.put('case 0: ')
code.putln('break;') code.putln('break;')
if self.star_arg:
if min_positional_args:
for i in range(min_positional_args-1, -1, -1):
code.putln('case %2d:' % i)
code.put_goto(argtuple_error_label)
else:
code.put('default: ') code.put('default: ')
code.put_goto(argtuple_error_label) code.put_goto(argtuple_error_label)
code.putln('}') code.putln('}')
...@@ -4683,11 +4692,11 @@ static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed ...@@ -4683,11 +4692,11 @@ static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed
raise_argtuple_invalid_utility_code = UtilityCode( raise_argtuple_invalid_utility_code = UtilityCode(
proto = """ proto = """
static INLINE void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); /*proto*/ Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); /*proto*/
""", """,
impl = """ impl = """
static INLINE void __Pyx_RaiseArgtupleInvalid( static void __Pyx_RaiseArgtupleInvalid(
const char* func_name, const char* func_name,
int exact, int exact,
Py_ssize_t num_min, Py_ssize_t num_min,
...@@ -4739,11 +4748,11 @@ static INLINE void __Pyx_RaiseKeywordRequired( ...@@ -4739,11 +4748,11 @@ static INLINE void __Pyx_RaiseKeywordRequired(
raise_double_keywords_utility_code = UtilityCode( raise_double_keywords_utility_code = UtilityCode(
proto = """ proto = """
static INLINE void __Pyx_RaiseDoubleKeywordsError( static void __Pyx_RaiseDoubleKeywordsError(
const char* func_name, PyObject* kw_name); /*proto*/ const char* func_name, PyObject* kw_name); /*proto*/
""", """,
impl = """ impl = """
static INLINE void __Pyx_RaiseDoubleKeywordsError( static void __Pyx_RaiseDoubleKeywordsError(
const char* func_name, const char* func_name,
PyObject* kw_name) PyObject* kw_name)
{ {
......
...@@ -1313,6 +1313,8 @@ def c_array_type(base_type, size): ...@@ -1313,6 +1313,8 @@ def c_array_type(base_type, size):
# Construct a C array type. # Construct a C array type.
if base_type is c_char_type: if base_type is c_char_type:
return CCharArrayType(size) return CCharArrayType(size)
elif base_type is error_type:
return error_type
else: else:
return CArrayType(base_type, size) return CArrayType(base_type, size)
...@@ -1320,6 +1322,8 @@ def c_ptr_type(base_type): ...@@ -1320,6 +1322,8 @@ def c_ptr_type(base_type):
# Construct a C pointer type. # Construct a C pointer type.
if base_type is c_char_type: if base_type is c_char_type:
return c_char_ptr_type return c_char_ptr_type
elif base_type is error_type:
return error_type
else: else:
return CPtrType(base_type) return CPtrType(base_type)
......
...@@ -135,6 +135,7 @@ class Entry: ...@@ -135,6 +135,7 @@ class Entry:
used = 0 used = 0
is_special = 0 is_special = 0
defined_in_pxd = 0 defined_in_pxd = 0
is_implemented = 0
api = 0 api = 0
utility_code = None utility_code = None
is_overridable = 0 is_overridable = 0
...@@ -445,6 +446,8 @@ class Scope: ...@@ -445,6 +446,8 @@ class Scope:
entry.api = 1 entry.api = 1
if not defining and not in_pxd and visibility != 'extern': if not defining and not in_pxd and visibility != 'extern':
error(pos, "Non-extern C function '%s' declared but not defined" % name) error(pos, "Non-extern C function '%s' declared but not defined" % name)
if defining:
entry.is_implemented = True
return entry return entry
def add_cfunction(self, name, type, pos, cname, visibility): def add_cfunction(self, name, type, pos, cname, visibility):
...@@ -1093,8 +1096,8 @@ class ModuleScope(Scope): ...@@ -1093,8 +1096,8 @@ class ModuleScope(Scope):
for entry in self.c_class_entries: for entry in self.c_class_entries:
if debug_check_c_classes: if debug_check_c_classes:
print("...entry %s %s" % (entry.name, entry)) print("...entry %s %s" % (entry.name, entry))
print("......type = " + entry.type) print("......type = ", entry.type)
print("......visibility = " + entry.visibility) print("......visibility = ", entry.visibility)
type = entry.type type = entry.type
name = entry.name name = entry.name
visibility = entry.visibility visibility = entry.visibility
...@@ -1117,6 +1120,18 @@ class ModuleScope(Scope): ...@@ -1117,6 +1120,18 @@ class ModuleScope(Scope):
#print "ModuleScope.check_c_classes: allocating vtable cname for", self ### #print "ModuleScope.check_c_classes: allocating vtable cname for", self ###
type.vtable_cname = self.mangle(Naming.vtable_prefix, entry.name) type.vtable_cname = self.mangle(Naming.vtable_prefix, entry.name)
def check_c_functions(self):
# Performs post-analysis checking making sure all
# defined c functions are actually implemented.
for name, entry in self.entries.items():
if entry.is_cfunction:
if (entry.defined_in_pxd
and entry.scope is self
and entry.visibility != 'extern'
and not entry.in_cinclude
and not entry.is_implemented):
error(entry.pos, "Non-extern C function '%s' declared but not defined" % name)
def attach_var_entry_to_c_class(self, entry): def attach_var_entry_to_c_class(self, entry):
# The name of an extension class has to serve as both a type # The name of an extension class has to serve as both a type
# name and a variable name holding the type object. It is # name and a variable name holding the type object. It is
......
...@@ -20,6 +20,9 @@ cdef f(Grail g, # incomplete argument type ...@@ -20,6 +20,9 @@ cdef f(Grail g, # incomplete argument type
int a[]): int a[]):
pass pass
cdef NoSuchType* ptr
ptr = None # This should not produce another error
_ERRORS = u""" _ERRORS = u"""
3:19: Python object cannot be declared extern 3:19: Python object cannot be declared extern
4:16: Array element cannot be a Python object 4:16: Array element cannot be a Python object
...@@ -35,4 +38,5 @@ _ERRORS = u""" ...@@ -35,4 +38,5 @@ _ERRORS = u"""
19:1: Use spam() rather than spam(void) to declare a function with no arguments. 19:1: Use spam() rather than spam(void) to declare a function with no arguments.
18:7: Argument type 'Grail' is incomplete 18:7: Argument type 'Grail' is incomplete
19:1: Invalid use of 'void' 19:1: Invalid use of 'void'
23:5: 'NoSuchType' is not a type identifier
""" """
...@@ -90,8 +90,48 @@ __doc__ = u""" ...@@ -90,8 +90,48 @@ __doc__ = u"""
>>> test_int_kwargs(h) >>> test_int_kwargs(h)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: h() keywords must be strings TypeError: h() keywords must be strings
>>> d()
Traceback (most recent call last):
TypeError: d() takes at least 1 positional argument (0 given)
>>> d(1)
1 1 0 0
>>> d(1,2)
1 2 0 0
>>> d(1,2,3)
1 2 1 0
>>> d(key=None)
Traceback (most recent call last):
TypeError: d() takes at least 1 positional argument (0 given)
>>> d(1, key=None)
1 1 0 1
>>> d(1,2, key=None)
1 2 0 1
>>> d(1,2,3, key=None)
1 2 1 1
>>> c()
10 20 0
>>> c(1)
1 20 0
>>> c(1,2)
1 2 0
>>> c(key=None)
10 20 1
>>> c(1, key=None)
1 20 1
>>> c(1,2, key=None)
1 2 1
""" """
def c(a=10, b=20, **kwds):
print a, b, len(kwds)
def d(a, b=1, *args, **kwds):
print a, b, len(args), len(kwds)
def e(*args, **kwargs): def e(*args, **kwargs):
print len(args), len(kwargs) print len(args), len(kwargs)
...@@ -112,7 +152,6 @@ if sys.version_info[0] >= 3: ...@@ -112,7 +152,6 @@ if sys.version_info[0] >= 3:
else: else:
kwargs = {"test" : u"toast"} kwargs = {"test" : u"toast"}
def test_kw_args(f): def test_kw_args(f):
f(1,2, c=3) f(1,2, c=3)
f(1,2, d=3, *args) f(1,2, d=3, *args)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment