Commit 5aeb0139 authored by Stefan Behnel's avatar Stefan Behnel

huge cleanup of 'star-args only' unpacking code, incl. bug fixes for memory...

huge cleanup of 'star-args only' unpacking code, incl. bug fixes for memory handling and non-string keywords
parent 35828d66
...@@ -964,10 +964,13 @@ class DefNode(FuncDefNode): ...@@ -964,10 +964,13 @@ class DefNode(FuncDefNode):
self.declare_pyfunction(env) self.declare_pyfunction(env)
self.analyse_signature(env) self.analyse_signature(env)
self.return_type = self.entry.signature.return_type() self.return_type = self.entry.signature.return_type()
if self.star_arg: if self.signature_has_generic_args():
env.use_utility_code(get_stararg_utility_code) if self.star_arg:
if self.starstar_arg: env.use_utility_code(get_stararg_utility_code)
env.use_utility_code(get_splitkeywords_utility_code) if not self.signature_has_nongeneric_args():
env.use_utility_code(get_keyword_string_check_utility_code)
elif self.starstar_arg:
env.use_utility_code(get_splitkeywords_utility_code)
if self.num_required_kw_args: if self.num_required_kw_args:
env.use_utility_code(get_checkkeywords_utility_code) env.use_utility_code(get_checkkeywords_utility_code)
...@@ -1223,7 +1226,7 @@ class DefNode(FuncDefNode): ...@@ -1223,7 +1226,7 @@ class DefNode(FuncDefNode):
self.generate_argument_conversion_code(code) self.generate_argument_conversion_code(code)
elif not self.signature_has_nongeneric_args(): elif not self.signature_has_nongeneric_args():
# func(*args) or func(**kw) or func(*args, **kw) # func(*args) or func(**kw) or func(*args, **kw)
self.generate_stararg_copy_code(env, code) self.generate_stararg_copy_code(code)
else: else:
arg_addrs = [] arg_addrs = []
arg_formats = [] arg_formats = []
...@@ -1366,38 +1369,29 @@ class DefNode(FuncDefNode): ...@@ -1366,38 +1369,29 @@ class DefNode(FuncDefNode):
else: else:
return 0 return 0
def generate_stararg_copy_code(self, env, code): def generate_stararg_copy_code(self, code):
if not self.starstar_arg: if not self.star_arg:
env.use_utility_code(get_keyword_error_utility_code)
code.putln("if (unlikely(%s) && unlikely(PyDict_Size(%s))) {" % (
Naming.kwds_cname, Naming.kwds_cname))
code.putln("__Pyx_RaiseKeywordError(%s);" % Naming.kwds_cname)
code.putln("return %s;" % self.error_value())
code.putln("}")
if self.star_arg:
code.put_incref(Naming.args_cname, py_object_type)
code.putln("%s = %s; %s = 0;" % (
self.star_arg.entry.cname,
Naming.args_cname,
Naming.args_cname))
self.star_arg.entry.xdecref_cleanup = 0
self.star_arg = None
else:
self.generate_positional_args_check(code, 0) self.generate_positional_args_check(code, 0)
self.generate_keyword_args_check(code)
if self.starstar_arg: if self.starstar_arg:
code.putln("if (%s) {" % Naming.kwds_cname) code.putln("%s = (%s) ? PyDict_Copy(%s) : PyDict_New();" % (
code.put_incref(Naming.kwds_cname, py_object_type)
code.putln("%s = %s; %s = 0;" % (
self.starstar_arg.entry.cname, self.starstar_arg.entry.cname,
Naming.kwds_cname, Naming.kwds_cname,
Naming.kwds_cname)) Naming.kwds_cname))
code.putln("}") code.putln("if (unlikely(!%s)) return %s;" % (
code.putln("else {") self.starstar_arg.entry.cname, self.error_value()))
code.putln("%s = PyDict_New();" % self.starstar_arg.entry.cname)
code.putln("}")
self.starstar_arg.entry.xdecref_cleanup = 0 self.starstar_arg.entry.xdecref_cleanup = 0
self.starstar_arg = None self.starstar_arg = None
if self.star_arg:
code.put_incref(Naming.args_cname, py_object_type)
code.putln("%s = %s;" % (
self.star_arg.entry.cname,
Naming.args_cname))
self.star_arg.entry.xdecref_cleanup = 0
self.star_arg = None
def generate_stararg_getting_code(self, code): def generate_stararg_getting_code(self, code):
num_kwonly = self.num_kwonly_args num_kwonly = self.num_kwonly_args
fixed_args = self.entry.signature.num_fixed_args() fixed_args = self.entry.signature.num_fixed_args()
...@@ -1463,6 +1457,13 @@ class DefNode(FuncDefNode): ...@@ -1463,6 +1457,13 @@ class DefNode(FuncDefNode):
code.putln("return %s;" % self.error_value()) code.putln("return %s;" % self.error_value())
code.putln("}") code.putln("}")
def generate_keyword_args_check(self, code):
code.putln("if (unlikely(%s)) {" % Naming.kwds_cname)
code.putln("if (unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % (
Naming.kwds_cname, self.name,
bool(self.starstar_arg), self.error_value()))
code.putln("}")
def generate_argument_conversion_code(self, code): def generate_argument_conversion_code(self, code):
# Generate code to convert arguments from # Generate code to convert arguments from
# signature type to declared type, if needed. # signature type to declared type, if needed.
...@@ -3534,25 +3535,35 @@ static INLINE int __Pyx_SplitStarArg( ...@@ -3534,25 +3535,35 @@ static INLINE int __Pyx_SplitStarArg(
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
# #
# __Pyx_RaiseKeywordError raises an error that keywords were passed # __Pyx_CheckKeywordStrings raises an error if non-string keywords
# to a function that does not accept them. # were passed to a function, or if any keywords were passed to a
# function that does not accept them.
get_keyword_error_utility_code = [ get_keyword_string_check_utility_code = [
""" """
static void __Pyx_RaiseKeywordError(PyObject *kwdict); /*proto*/ static int __Pyx_CheckKeywordStrings(PyObject *kwdict, const char* function_name, int kw_allowed); /*proto*/
""",""" ""","""
static void __Pyx_RaiseKeywordError(PyObject *kwdict) { static int __Pyx_CheckKeywordStrings(
PyObject *kwdict,
const char* function_name,
int kw_allowed)
{
PyObject* key = 0; PyObject* key = 0;
Py_ssize_t pos = 0; Py_ssize_t pos = 0;
PyDict_Next(kwdict, &pos, &key, 0); while (PyDict_Next(kwdict, &pos, &key, 0)) {
if (!PyString_Check(key)) { if (unlikely(!PyString_Check(key))) {
PyErr_SetString(PyExc_TypeError, "keywords must be strings"); PyErr_Format(PyExc_TypeError,
"%s() keywords must be strings", function_name);
return 0;
}
} }
else { if (unlikely(!kw_allowed) && unlikely(key)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"'%s' is an invalid keyword argument for this function", "'%s' is an invalid keyword argument for this function",
PyString_AsString(key)); PyString_AsString(key));
return 0;
} }
return 1;
} }
"""] """]
......
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