X-Git-Url: http://git.tremily.us/?a=blobdiff_plain;f=Cython%2FCompiler%2FNodes.py;h=977447dc3f9c2e6fcb2105a93d5cda9c720a494e;hb=5b9d3022e7940db30f8dfc2b424d148acc0dbee1;hp=99267aa245d78ad72eb0bdcf86e12ce8507208a3;hpb=72f8a46e52496a1a18d2a34e130acbce420bea8f;p=cython.git diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 99267aa2..977447dc 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -535,7 +535,7 @@ class CFuncDeclaratorNode(CDeclaratorNode): overridable = 0 optional_arg_count = 0 - def analyse(self, return_type, env, nonempty = 0): + def analyse(self, return_type, env, nonempty = 0, directive_locals = {}): if nonempty: nonempty -= 1 func_type_args = [] @@ -543,6 +543,17 @@ class CFuncDeclaratorNode(CDeclaratorNode): name_declarator, type = arg_node.analyse(env, nonempty = nonempty, is_self_arg = (i == 0 and env.is_c_class_scope)) name = name_declarator.name + if name in directive_locals: + type_node = directive_locals[name] + other_type = type_node.analyse_as_type(env) + if other_type is None: + error(type_node.pos, "Not a type") + elif (type is not PyrexTypes.py_object_type + and not type.same_as(other_type)): + error(self.base.pos, "Signature does not agree with previous declaration") + error(type_node.pos, "Previous declaration here") + else: + type = other_type if name_declarator.cname: error(self.pos, "Function argument cannot have C name specification") @@ -925,9 +936,11 @@ class CVarDefNode(StatNode): child_attrs = ["base_type", "declarators"] decorators = None - directive_locals = {} + directive_locals = None def analyse_declarations(self, env, dest_scope = None): + if self.directive_locals is None: + self.directive_locals = {} if not dest_scope: dest_scope = env self.dest_scope = dest_scope @@ -944,7 +957,10 @@ class CVarDefNode(StatNode): visibility = self.visibility for declarator in self.declarators: - name_declarator, type = declarator.analyse(base_type, env) + if isinstance(declarator, CFuncDeclaratorNode): + name_declarator, type = declarator.analyse(base_type, env, directive_locals=self.directive_locals) + else: + name_declarator, type = declarator.analyse(base_type, env) if not type.is_complete(): if not (self.visibility == 'extern' and type.is_array): error(declarator.pos, @@ -962,7 +978,7 @@ class CVarDefNode(StatNode): cname = cname, visibility = self.visibility, in_pxd = self.in_pxd, api = self.api) if entry is not None: - entry.directive_locals = self.directive_locals + entry.directive_locals = copy.copy(self.directive_locals) else: if self.directive_locals: error(self.pos, "Decorators can only be followed by functions") @@ -1197,6 +1213,22 @@ class FuncDefNode(StatNode, BlockNode): elif default_seen: error(arg.pos, "Non-default argument following default argument") + def align_argument_type(self, env, arg): + directive_locals = self.directive_locals + type = arg.type + if arg.name in directive_locals: + type_node = directive_locals[arg.name] + other_type = type_node.analyse_as_type(env) + if other_type is None: + error(type_node.pos, "Not a type") + elif (type is not PyrexTypes.py_object_type + and not type.same_as(other_type)): + error(arg.base_type.pos, "Signature does not agree with previous declaration") + error(type_node.pos, "Previous declaration here") + else: + arg.type = other_type + return arg + def need_gil_acquisition(self, lenv): return 0 @@ -1257,9 +1289,10 @@ class FuncDefNode(StatNode, BlockNode): preprocessor_guard = None profile = code.globalstate.directives['profile'] + if profile and lenv.nogil: + warning(self.pos, "Cannot profile nogil function.", 1) + profile = False if profile: - if lenv.nogil: - error(self.pos, "Cannot profile nogil function.") code.globalstate.use_utility_code(profile_utility_code) # Generate C code for header and body of function @@ -1309,7 +1342,8 @@ class FuncDefNode(StatNode, BlockNode): (self.return_type.declaration_code(Naming.retval_cname), init)) tempvardecl_code = code.insertion_point() - code.put_declare_refcount_context() + if not lenv.nogil: + code.put_declare_refcount_context() self.generate_keyword_list(code) if profile: code.put_trace_declarations() @@ -1589,20 +1623,24 @@ class FuncDefNode(StatNode, BlockNode): info = self.local_scope.arg_entries[1].cname # Python 3.0 betas have a bug in memoryview which makes it call # getbuffer with a NULL parameter. For now we work around this; - # the following line should be removed when this bug is fixed. - code.putln("if (%s == NULL) return 0;" % info) + # the following block should be removed when this bug is fixed. + code.putln("if (%s != NULL) {" % info) code.putln("%s->obj = Py_None; __Pyx_INCREF(Py_None);" % info) code.put_giveref("%s->obj" % info) # Do not refnanny object within structs + code.putln("}") def getbuffer_error_cleanup(self, code): info = self.local_scope.arg_entries[1].cname + code.putln("if (%s != NULL && %s->obj != NULL) {" + % (info, info)) code.put_gotref("%s->obj" % info) - code.putln("__Pyx_DECREF(%s->obj); %s->obj = NULL;" % - (info, info)) + code.putln("__Pyx_DECREF(%s->obj); %s->obj = NULL;" + % (info, info)) + code.putln("}") def getbuffer_normal_cleanup(self, code): info = self.local_scope.arg_entries[1].cname - code.putln("if (%s->obj == Py_None) {" % info) + code.putln("if (%s != NULL && %s->obj == Py_None) {" % (info, info)) code.put_gotref("Py_None") code.putln("__Pyx_DECREF(Py_None); %s->obj = NULL;" % info) code.putln("}") @@ -1628,16 +1666,23 @@ class CFuncDefNode(FuncDefNode): inline_in_pxd = False decorators = None - directive_locals = {} + directive_locals = None def unqualified_name(self): return self.entry.name def analyse_declarations(self, env): + if self.directive_locals is None: + self.directive_locals = {} self.directive_locals.update(env.directives['locals']) base_type = self.base_type.analyse(env) # The 2 here is because we need both function and argument names. - name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None)) + if isinstance(self.declarator, CFuncDeclaratorNode): + name_declarator, type = self.declarator.analyse(base_type, env, + nonempty = 2 * (self.body is not None), + directive_locals = self.directive_locals) + else: + name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None)) if not type.is_cfunction: error(self.pos, "Suite attached to non-function declaration") @@ -1652,6 +1697,7 @@ class CFuncDefNode(FuncDefNode): declarator = declarator.base self.args = declarator.args for formal_arg, type_arg in zip(self.args, type.args): + self.align_argument_type(env, type_arg) formal_arg.type = type_arg.type formal_arg.name = type_arg.name formal_arg.cname = type_arg.cname @@ -1986,6 +2032,17 @@ class DefNode(FuncDefNode): api = False, directive_locals = getattr(cfunc, 'directive_locals', {})) + def is_cdef_func_compatible(self): + """Determines if the function's signature is compatible with a + cdef function. This can be used before calling + .as_cfunction() to see if that will be successful. + """ + if self.needs_closure: + return False + if self.star_arg or self.starstar_arg: + return False + return True + def analyse_declarations(self, env): self.is_classmethod = self.is_staticmethod = False if self.decorators: @@ -2019,28 +2076,18 @@ class DefNode(FuncDefNode): allow_none_for_extension_args = env.directives['allow_none_for_extension_args'] for arg in self.args: if hasattr(arg, 'name'): - type = arg.type name_declarator = None else: base_type = arg.base_type.analyse(env) name_declarator, type = \ arg.declarator.analyse(base_type, env) arg.name = name_declarator.name - if arg.name in directive_locals: - type_node = directive_locals[arg.name] - other_type = type_node.analyse_as_type(env) - if other_type is None: - error(type_node.pos, "Not a type") - elif (type is not PyrexTypes.py_object_type - and not type.same_as(other_type)): - error(arg.base_type.pos, "Signature does not agree with previous declaration") - error(type_node.pos, "Previous declaration here") - else: - type = other_type + arg.type = type + self.align_argument_type(env, arg) if name_declarator and name_declarator.cname: error(self.pos, "Python function argument cannot have C name specification") - arg.type = type.as_argument_type() + arg.type = arg.type.as_argument_type() arg.hdr_type = None arg.needs_conversion = 0 arg.needs_type_test = 0 @@ -2185,14 +2232,7 @@ class DefNode(FuncDefNode): entry.doc = None def declare_lambda_function(self, env): - name = self.name - prefix = env.scope_prefix - func_cname = \ - Naming.lambda_func_prefix + u'funcdef' + prefix + self.lambda_name - entry = env.declare_lambda_function(func_cname, self.pos) - entry.pymethdef_cname = \ - Naming.lambda_func_prefix + u'methdef' + prefix + self.lambda_name - entry.qualified_name = env.qualify_name(self.lambda_name) + entry = env.declare_lambda_function(self.lambda_name, self.pos) entry.doc = None self.entry = entry @@ -2926,7 +2966,7 @@ class GeneratorDefNode(DefNode): is_generator = True needs_closure = True - child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators", "gbody"] + child_attrs = DefNode.child_attrs + ["gbody"] def __init__(self, **kwargs): # XXX: don't actually needs a body @@ -2960,8 +3000,6 @@ class GeneratorBodyDefNode(DefNode): is_generator_body = True - child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators"] - def __init__(self, pos=None, name=None, body=None): super(GeneratorBodyDefNode, self).__init__(pos=pos, body=body, name=name, doc=None, args=[], @@ -3030,7 +3068,6 @@ class GeneratorBodyDefNode(DefNode): for cname, type in code.funcstate.all_managed_temps(): code.put_xdecref(cname, type) code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name) - # XXX: ^^^ is this enough? # ----- Non-error return cleanup code.put_label(code.return_label) @@ -4135,7 +4172,9 @@ class RaiseStatNode(StatNode): if self.exc_type and not self.exc_value and not self.exc_tb: exc = self.exc_type import ExprNodes - if isinstance(exc, ExprNodes.SimpleCallNode) and not exc.args: + if (isinstance(exc, ExprNodes.SimpleCallNode) and + not (exc.args or (exc.arg_tuple is not None and + exc.arg_tuple.args))): exc = exc.function # extract the exception type if exc.is_name and exc.entry.is_builtin: self.builtin_exc_name = exc.name @@ -4898,7 +4937,8 @@ class TryExceptStatNode(StatNode): code.put_goto(try_end_label) if code.label_used(try_return_label): code.put_label(try_return_label) - for var in exc_save_vars: code.put_xgiveref(var) + for var in exc_save_vars: + code.put_xgiveref(var) code.putln("__Pyx_ExceptionReset(%s);" % ', '.join(exc_save_vars)) code.put_goto(old_return_label) @@ -4912,7 +4952,8 @@ class TryExceptStatNode(StatNode): if error_label_used or not self.has_default_clause: if error_label_used: code.put_label(except_error_label) - for var in exc_save_vars: code.put_xgiveref(var) + for var in exc_save_vars: + code.put_xgiveref(var) code.putln("__Pyx_ExceptionReset(%s);" % ', '.join(exc_save_vars)) code.put_goto(old_error_label) @@ -4923,14 +4964,16 @@ class TryExceptStatNode(StatNode): if code.label_used(exit_label): code.put_label(exit_label) - for var in exc_save_vars: code.put_xgiveref(var) + for var in exc_save_vars: + code.put_xgiveref(var) code.putln("__Pyx_ExceptionReset(%s);" % ', '.join(exc_save_vars)) code.put_goto(old_label) if code.label_used(except_end_label): code.put_label(except_end_label) - for var in exc_save_vars: code.put_xgiveref(var) + for var in exc_save_vars: + code.put_xgiveref(var) code.putln("__Pyx_ExceptionReset(%s);" % ', '.join(exc_save_vars)) code.put_label(try_end_label) @@ -6062,6 +6105,31 @@ static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb) #------------------------------------------------------------------------------------ +swap_exception_utility_code = UtilityCode( +proto = """ +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); /*proto*/ +""", +impl = """ +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyThreadState *tstate = PyThreadState_GET(); + + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + + tstate->exc_type = *type; + tstate->exc_value = *value; + tstate->exc_traceback = *tb; + + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +""") + +#------------------------------------------------------------------------------------ + arg_type_test_utility_code = UtilityCode( proto = """ static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,