Commit 405c14c2 authored by Stefan Behnel's avatar Stefan Behnel

Pyrex merge: nogil declaration checking

parent 17ebac85
......@@ -297,7 +297,11 @@ class ExprNode(Node):
def analyse_target_types(self, env):
self.analyse_types(env)
def gil_assignment_check(self, env):
if env.nogil and self.type.is_pyobject:
error(self.pos, "Assignment of Python object not allowed without gil")
def check_const(self):
self.not_const()
......@@ -309,7 +313,11 @@ class ExprNode(Node):
def addr_not_const(self):
error(self.pos, "Address is not constant")
def gil_check(self, env):
if env.nogil and self.type.is_pyobject:
self.gil_error()
# ----------------- Result Allocation -----------------
def result_in_temp(self):
......@@ -755,11 +763,16 @@ class LongNode(AtomicExprNode):
def compile_time_value(self, denv):
return long(self.value)
gil_message = "Constructing Python long int"
def analyse_types(self, env):
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
gil_message = "Constructing Python long int"
def generate_evaluation_code(self, code):
code.putln(
'%s = PyLong_FromString("%s", 0, 0); %s' % (
......@@ -778,8 +791,11 @@ class ImagNode(AtomicExprNode):
def analyse_types(self, env):
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
gil_message = "Constructing complex number"
def generate_evaluation_code(self, code):
code.putln(
"%s = PyComplex_FromDoubles(0.0, %s); %s" % (
......@@ -880,7 +896,10 @@ class NameNode(AtomicExprNode):
else:
self.is_temp = 1
env.use_utility_code(get_name_interned_utility_code)
self.gil_check(env)
gil_message = "Accessing Python global or builtin"
def analyse_entry(self, env):
#print "NameNode.analyse_entry:", self.name ###
self.check_identifier_kind()
......@@ -1057,8 +1076,11 @@ class BackquoteNode(ExprNode):
self.arg.analyse_types(env)
self.arg = self.arg.coerce_to_pyobject(env)
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
gil_message = "Backquote expression"
def generate_result_code(self, code):
code.putln(
"%s = PyObject_Repr(%s); %s" % (
......@@ -1083,9 +1105,12 @@ class ImportNode(ExprNode):
if self.name_list:
self.name_list.analyse_types(env)
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
env.use_utility_code(import_utility_code)
gil_message = "Python import"
def generate_result_code(self, code):
if self.name_list:
name_list_code = self.name_list.py_result()
......@@ -1111,11 +1136,14 @@ class IteratorNode(ExprNode):
self.sequence.analyse_types(env)
self.sequence = self.sequence.coerce_to_pyobject(env)
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
self.counter = TempNode(self.pos, PyrexTypes.c_py_ssize_t_type, env)
self.counter.allocate_temp(env)
gil_message = "Iterating over Python object"
def release_temp(self, env):
env.release_temp(self.result_code)
self.counter.release_temp(env)
......@@ -1262,6 +1290,7 @@ class IndexNode(ExprNode):
else:
self.index = self.index.coerce_to_pyobject(env)
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
else:
if self.base.type.is_ptr or self.base.type.is_array:
......@@ -1278,7 +1307,9 @@ class IndexNode(ExprNode):
error(self.pos,
"Invalid index type '%s'" %
self.index.type)
gil_message = "Indexing Python object"
def check_const_addr(self):
self.base.check_const_addr()
self.index.check_const()
......@@ -1405,8 +1436,11 @@ class SliceIndexNode(ExprNode):
if self.stop:
self.stop = self.stop.coerce_to(c_int, env)
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
gil_message = "Slicing Python object"
def generate_result_code(self, code):
code.putln(
"%s = PySequence_GetSlice(%s, %s, %s); %s" % (
......@@ -1479,8 +1513,11 @@ class SliceNode(ExprNode):
self.stop = self.stop.coerce_to_pyobject(env)
self.step = self.step.coerce_to_pyobject(env)
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
gil_message = "Constructing Python slice object"
def generate_result_code(self, code):
code.putln(
"%s = PySlice_New(%s, %s, %s); %s" % (
......@@ -1490,7 +1527,15 @@ class SliceNode(ExprNode):
self.step.py_result(),
code.error_goto_if_null(self.result_code, self.pos)))
class SimpleCallNode(ExprNode):
class CallNode(ExprNode):
def gil_check(self, env):
# Make sure we're not in a nogil environment
if env.nogil:
error(self.pos, "Calling gil-requiring function without gil")
class SimpleCallNode(CallNode):
# Function call without keyword, * or ** args.
#
# function ExprNode
......@@ -1539,6 +1584,7 @@ class SimpleCallNode(ExprNode):
self.arg_tuple.analyse_types(env)
self.args = None
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
else:
for arg in self.args:
......@@ -1611,6 +1657,9 @@ class SimpleCallNode(ExprNode):
if func_type.exception_check == '+':
if func_type.exception_value is None:
env.use_utility_code(cpp_exception_utility_code)
# Check gil
if not func_type.nogil:
self.gil_check(env)
def calculate_result_code(self):
return self.c_call_code()
......@@ -1705,7 +1754,7 @@ class SimpleCallNode(ExprNode):
rhs,
code.error_goto_if(" && ".join(exc_checks), self.pos)))
class GeneralCallNode(ExprNode):
class GeneralCallNode(CallNode):
# General Python function call, including keyword,
# * and ** arguments.
#
......@@ -1741,6 +1790,7 @@ class GeneralCallNode(ExprNode):
self.starstar_arg = \
self.starstar_arg.coerce_to_pyobject(env)
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
def generate_result_code(self, code):
......@@ -1791,8 +1841,11 @@ class AsTupleNode(ExprNode):
self.arg.analyse_types(env)
self.arg = self.arg.coerce_to_pyobject(env)
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
gil_message = "Constructing Python tuple"
def generate_result_code(self, code):
code.putln(
"%s = PySequence_Tuple(%s); %s" % (
......@@ -1997,12 +2050,15 @@ class AttributeNode(ExprNode):
self.type = py_object_type
self.is_py_attr = 1
self.interned_attr_cname = env.intern_identifier(self.attribute)
self.gil_check(env)
else:
if not obj_type.is_error:
error(self.pos,
"Object of type '%s' has no attribute '%s'" %
(obj_type, self.attribute))
gil_message = "Accessing Python attribute"
def is_simple(self):
if self.obj:
return self.result_in_temp() or self.obj.is_simple()
......@@ -2119,8 +2175,9 @@ class SequenceNode(ExprNode):
arg.analyse_types(env)
self.args[i] = arg.coerce_to_pyobject(env)
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
def analyse_target_types(self, env):
self.iterator = PyTempNode(self.pos, env)
self.unpacked_items = []
......@@ -2217,7 +2274,9 @@ class SequenceNode(ExprNode):
class TupleNode(SequenceNode):
# Tuple constructor.
gil_message = "Constructing Python tuple"
def analyse_types(self, env):
if len(self.args) == 0:
self.is_temp = 0
......@@ -2268,7 +2327,9 @@ class TupleNode(SequenceNode):
class ListNode(SequenceNode):
# List constructor.
gil_message = "Constructing Python list"
def analyse_types(self, env):
SequenceNode.analyse_types(self, env)
self.type = list_type
......@@ -2365,8 +2426,11 @@ class DictNode(ExprNode):
for item in self.key_value_pairs:
item.analyse_types(env)
self.type = dict_type
self.gil_check(env)
self.is_temp = 1
gil_message = "Constructing Python dict"
def allocate_temps(self, env, result = None):
# Custom method used here because key-value
# pairs are evaluated and used one at a time.
......@@ -2441,9 +2505,12 @@ class ClassNode(ExprNode):
self.doc = self.doc.coerce_to_pyobject(env)
self.module_name = env.global_scope().qualified_name
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
env.use_utility_code(create_class_utility_code);
gil_message = "Constructing Python class"
def generate_result_code(self, code):
if self.doc:
code.put_error_if_neg(self.pos,
......@@ -2473,8 +2540,11 @@ class UnboundMethodNode(ExprNode):
def analyse_types(self, env):
self.function.analyse_types(env)
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
gil_message = "Constructing an unbound method"
def generate_result_code(self, code):
code.putln(
"%s = PyMethod_New(%s, 0, %s); %s" % (
......@@ -2493,8 +2563,11 @@ class PyCFunctionNode(AtomicExprNode):
def analyse_types(self, env):
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
gil_message = "Constructing Python function"
def generate_result_code(self, code):
code.putln(
"%s = PyCFunction_New(&%s, 0); %s" % (
......@@ -2546,6 +2619,7 @@ class UnopNode(ExprNode):
if self.is_py_operation():
self.coerce_operand_to_pyobject(env)
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
else:
self.analyse_c_operation(env)
......@@ -2895,6 +2969,7 @@ class BinopNode(ExprNode):
if self.is_py_operation():
self.coerce_operands_to_pyobjects(env)
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
if Options.incref_local_binop and self.operand1.type.is_pyobject:
self.operand1 = self.operand1.coerce_to_temp(env)
......@@ -3126,6 +3201,7 @@ class BoolBinopNode(ExprNode):
self.operand2 = self.operand2.coerce_to_pyobject(env)
self.temp_bool = TempNode(self.pos, PyrexTypes.c_bint_type, env)
self.type = py_object_type
self.gil_check(env)
else:
self.operand1 = self.operand1.coerce_to_boolean(env)
self.operand2 = self.operand2.coerce_to_boolean(env)
......@@ -3134,11 +3210,10 @@ class BoolBinopNode(ExprNode):
# both operands be temp nodes.
self.operand1 = self.operand1.coerce_to_temp(env) #CTT
self.operand2 = self.operand2.coerce_to_temp(env)
# coerce_to_simple does not seem to be sufficient
#self.operand1 = self.operand1.coerce_to_simple(env)
#self.operand2 = self.operand2.coerce_to_simple(env)
self.is_temp = 1
gil_message = "Truth-testing Python object"
def allocate_temps(self, env, result_code = None):
# We don't need both operands at the same time, and
# one of the operands will also be our result. So we
......@@ -3435,7 +3510,6 @@ class PrimaryCmpNode(ExprNode, CmpNode):
if self.has_int_operands():
self.coerce_chars_to_ints(env)
if self.cascade:
#self.operand2 = self.operand2.coerce_to_temp(env) #CTT
self.operand2 = self.operand2.coerce_to_simple(env)
self.cascade.coerce_cascaded_operands_to_temp(env)
self.check_operand_types(env)
......@@ -3685,8 +3759,11 @@ class PyTypeTestNode(CoercionNode):
assert dst_type.is_extension_type or dst_type.is_builtin_type, "PyTypeTest on non extension type"
CoercionNode.__init__(self, arg)
self.type = dst_type
self.gil_check(env)
self.result_ctype = arg.ctype()
env.use_utility_code(type_test_utility_code)
gil_message = "Python type test"
def analyse_types(self, env):
pass
......@@ -3721,11 +3798,14 @@ class CoerceToPyTypeNode(CoercionNode):
def __init__(self, arg, env):
CoercionNode.__init__(self, arg)
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
if not arg.type.to_py_function:
error(arg.pos,
"Cannot convert '%s' to Python object" % arg.type)
gil_message = "Converting to Python object"
def generate_result_code(self, code):
function = self.arg.type.to_py_function
code.putln('%s = %s(%s); %s' % (
......@@ -3770,7 +3850,11 @@ class CoerceToBooleanNode(CoercionNode):
CoercionNode.__init__(self, arg)
self.type = PyrexTypes.c_bint_type
if arg.type.is_pyobject:
if env.nogil:
self.gil_error()
self.is_temp = 1
gil_message = "Truth-testing Python object"
def check_const(self):
if self.is_temp:
......@@ -3799,8 +3883,11 @@ class CoerceToTempNode(CoercionNode):
self.type = self.arg.type
self.is_temp = 1
if self.type.is_pyobject:
self.gil_check(env)
self.result_ctype = py_object_type
gil_message = "Creating temporary Python reference"
def generate_result_code(self, code):
#self.arg.generate_evaluation_code(code) # Already done
# by generic generate_subexpr_evaluation_code!
......
......@@ -106,7 +106,16 @@ class Node(object):
def __init__(self, pos, **kw):
self.pos = pos
self.__dict__.update(kw)
gil_message = "Operation"
def gil_check(self, env):
if env.nogil:
self.gil_error()
def gil_error(self):
error(self.pos, "%s not allowed without gil" % self.gil_message)
def get_child_accessors(self):
"""Returns an iterator over the children of the Node. Each member in the
iterated list is an object with get(), set(value), and name() methods,
......@@ -488,9 +497,9 @@ class CFuncDeclaratorNode(CDeclaratorNode):
# Catch attempted C-style func(void) decl
if type.is_void:
error(arg_node.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
if type.is_pyobject and self.nogil:
error(self.pos,
"Function with Python argument cannot be declared nogil")
# if type.is_pyobject and self.nogil:
# error(self.pos,
# "Function with Python argument cannot be declared nogil")
func_type_args.append(
PyrexTypes.CFuncTypeArg(name, type, arg_node.pos))
if arg_node.default:
......@@ -537,9 +546,6 @@ class CFuncDeclaratorNode(CDeclaratorNode):
error(self.exception_value.pos,
"Exception value incompatible with function return type")
exc_check = self.exception_check
if return_type.is_pyobject and self.nogil:
error(self.pos,
"Function with Python return type cannot be declared nogil")
if return_type.is_array:
error(self.pos,
"Function cannot return an array")
......@@ -867,6 +873,9 @@ class FuncDefNode(StatNode, BlockNode):
genv = env.global_scope()
lenv = LocalScope(name = self.entry.name, outer_scope = genv)
lenv.return_type = self.return_type
type = self.entry.type
if type.is_cfunction:
lenv.nogil = type.nogil and not type.with_gil
code.init_labels()
self.declare_arguments(lenv)
transforms.run('before_analyse_function', self, env=env, lenv=lenv, genv=genv)
......@@ -1113,8 +1122,12 @@ class CFuncDefNode(FuncDefNode):
self.declare_argument(env, arg)
def need_gil_acquisition(self, lenv):
type = self.type
with_gil = self.type.with_gil
if self.type.nogil and not with_gil:
if type.nogil and not with_gil:
if type.return_type.is_pyobject:
error(self.pos,
"Function with Python return type cannot be declared nogil")
for entry in lenv.var_entries + lenv.temp_entries:
if entry.type.is_pyobject:
error(self.pos, "Function declared nogil has Python locals or temporaries")
......@@ -2216,6 +2229,7 @@ class SingleAssignmentNode(AssignmentNode):
def analyse_types(self, env, use_temp = 0):
self.rhs.analyse_types(env)
self.lhs.analyse_target_types(env)
self.lhs.gil_assignment_check(env)
self.rhs = self.rhs.coerce_to(self.lhs.type, env)
if use_temp:
self.rhs = self.rhs.coerce_to_temp(env)
......@@ -2280,6 +2294,7 @@ class CascadedAssignmentNode(AssignmentNode):
self.coerced_rhs_list = []
for lhs in self.lhs_list:
lhs.analyse_target_types(env)
lhs.gil_assignment_check(env)
rhs = CloneNode(self.rhs)
rhs = rhs.coerce_to(lhs.type, env)
self.coerced_rhs_list.append(rhs)
......@@ -2522,15 +2537,9 @@ class PrintStatNode(StatNode):
self.arg_tuple = self.arg_tuple.coerce_to_pyobject(env)
self.arg_tuple.release_temp(env)
env.use_utility_code(printing_utility_code)
return
for i in range(len(self.args)):
arg = self.args[i]
arg.analyse_types(env)
arg = arg.coerce_to_pyobject(env)
arg.allocate_temps(env)
arg.release_temp(env)
self.args[i] = arg
#env.recycle_pending_temps() # TEMPORARY
self.gil_check(env)
gil_message = "Python print statement"
def generate_execution_code(self, code):
self.arg_tuple.generate_evaluation_code(code)
......@@ -2559,10 +2568,14 @@ class DelStatNode(StatNode):
def analyse_expressions(self, env):
for arg in self.args:
arg.analyse_target_expression(env, None)
if not arg.type.is_pyobject:
if arg.type.is_pyobject:
self.gil_check(env)
else:
error(arg.pos, "Deletion of non-Python object")
#arg.release_target_temp(env)
gil_message = "Deleting Python object"
def generate_execution_code(self, code):
for arg in self.args:
if arg.type.is_pyobject:
......@@ -2649,7 +2662,11 @@ class ReturnStatNode(StatNode):
and not return_type.is_pyobject
and not return_type.is_returncode):
error(self.pos, "Return value required")
if return_type.is_pyobject:
self.gil_check(env)
gil_message = "Returning Python object"
def generate_execution_code(self, code):
code.mark_pos(self.pos)
if not self.return_type:
......@@ -2711,11 +2728,11 @@ class RaiseStatNode(StatNode):
self.exc_value.release_temp(env)
if self.exc_tb:
self.exc_tb.release_temp(env)
# if not (self.exc_type or self.exc_value or self.exc_tb):
# env.use_utility_code(reraise_utility_code)
# else:
env.use_utility_code(raise_utility_code)
self.gil_check(env)
gil_message = "Raising exception"
def generate_execution_code(self, code):
if self.exc_type:
self.exc_type.generate_evaluation_code(code)
......@@ -2764,8 +2781,11 @@ class ReraiseStatNode(StatNode):
child_attrs = []
def analyse_expressions(self, env):
self.gil_check(env)
env.use_utility_code(raise_utility_code)
gil_message = "Raising exception"
def generate_execution_code(self, code):
vars = code.exc_vars
if vars:
......@@ -2792,7 +2812,10 @@ class AssertStatNode(StatNode):
self.cond.release_temp(env)
if self.value:
self.value.release_temp(env)
self.gil_check(env)
#env.recycle_pending_temps() # TEMPORARY
gil_message = "Raising exception"
def generate_execution_code(self, code):
code.putln("#ifndef PYREX_WITHOUT_ASSERTIONS")
......@@ -2888,7 +2911,6 @@ class IfClauseNode(Node):
self.condition = \
self.condition.analyse_temp_boolean_expression(env)
self.condition.release_temp(env)
#env.recycle_pending_temps() # TEMPORARY
self.body.analyse_expressions(env)
def generate_execution_code(self, code, end_label):
......@@ -3250,6 +3272,7 @@ class TryExceptStatNode(StatNode):
except_clause.analyse_declarations(env)
if self.else_clause:
self.else_clause.analyse_declarations(env)
self.gil_check(env)
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
......@@ -3258,7 +3281,10 @@ class TryExceptStatNode(StatNode):
except_clause.analyse_expressions(env)
if self.else_clause:
self.else_clause.analyse_expressions(env)
self.gil_check(env)
gil_message = "Try-except statement"
def generate_execution_code(self, code):
old_error_label = code.new_error_label()
our_error_label = code.error_label
......@@ -3418,16 +3444,11 @@ class TryFinallyStatNode(StatNode):
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
self.cleanup_list = env.free_temp_entries[:]
#self.exc_vars = (
# env.allocate_temp(PyrexTypes.py_object_type),
# env.allocate_temp(PyrexTypes.py_object_type),
# env.allocate_temp(PyrexTypes.py_object_type))
#self.lineno_var = \
# env.allocate_temp(PyrexTypes.c_int_type)
self.finally_clause.analyse_expressions(env)
#for var in self.exc_vars:
# env.release_temp(var)
self.gil_check(env)
gil_message = "Try-finally statement"
def generate_execution_code(self, code):
old_error_label = code.error_label
old_labels = code.all_new_labels()
......@@ -3572,6 +3593,15 @@ class GILStatNode(TryFinallyStatNode):
body = body,
finally_clause = GILExitNode(pos, state = state))
def analyse_expressions(self, env):
was_nogil = env.nogil
env.nogil = 1
TryFinallyStatNode.analyse_expressions(self, env)
env.nogil = was_nogil
def gil_check(self, env):
pass
def generate_execution_code(self, code):
code.putln("/*with %s:*/ {" % self.state)
if self.state == 'gil':
......@@ -3582,19 +3612,6 @@ class GILStatNode(TryFinallyStatNode):
TryFinallyStatNode.generate_execution_code(self, code)
code.putln("}")
#class GILEntryNode(StatNode):
# # state string 'gil' or 'nogil'
#
# def analyse_expressions(self, env):
# pass
#
# def generate_execution_code(self, code):
# if self.state == 'gil':
# code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
# else:
# code.putln("PyThreadState *_save;")
# code.putln("Py_UNBLOCK_THREADS")
class GILExitNode(StatNode):
# Used as the 'finally' block in a GILStatNode
......
......@@ -695,9 +695,10 @@ class CFuncType(CType):
return 0
if not self.same_calling_convention_as(other_type):
return 0
if self.nogil != other_type.nogil:
return 0
return 1
def compatible_signature_with(self, other_type, as_cmethod = 0):
return self.compatible_signature_with_resolved_type(other_type.resolve(), as_cmethod)
......@@ -789,22 +790,24 @@ class CFuncType(CType):
arg_decl_code = ", ".join(arg_decl_list)
if not arg_decl_code and not pyrex:
arg_decl_code = "void"
exc_clause = ""
trailer = ""
if (pyrex or for_display) and not self.return_type.is_pyobject:
if self.exception_value and self.exception_check:
exc_clause = " except? %s" % self.exception_value
trailer = " except? %s" % self.exception_value
elif self.exception_value:
exc_clause = " except %s" % self.exception_value
trailer = " except %s" % self.exception_value
elif self.exception_check == '+':
exc_clause = " except +"
trailer = " except +"
else:
" except *"
" except *" # ignored
if self.nogil:
trailer += " nogil"
cc = self.calling_convention_prefix()
if (not entity_code and cc) or entity_code.startswith("*"):
entity_code = "(%s%s)" % (cc, entity_code)
cc = ""
return self.return_type.declaration_code(
"%s%s(%s)%s" % (cc, entity_code, arg_decl_code, exc_clause),
"%s%s(%s)%s" % (cc, entity_code, arg_decl_code, trailer),
for_display, dll_linkage, pyrex)
def function_header_code(self, func_name, arg_code):
......
......@@ -150,12 +150,14 @@ class Scope:
# pystring_entries [Entry] String const entries newly used as
# Python strings in this scope
# control_flow ControlFlow Used for keeping track of environment state
# nogil boolean In a nogil section
is_py_class_scope = 0
is_c_class_scope = 0
is_module_scope = 0
scope_prefix = ""
in_cinclude = 0
nogil = 0
def __init__(self, name, outer_scope, parent_scope):
# The outer_scope is the next scope in the lookup chain.
......@@ -1324,6 +1326,7 @@ class CClassScope(ClassScope):
# entry.type = type
else:
error(pos, "Signature not compatible with previous declaration")
error(entry.pos, "Previous declaration is here")
else:
if self.defined:
error(pos,
......@@ -1363,8 +1366,8 @@ class CClassScope(ClassScope):
entry.is_variable = 1
self.inherited_var_entries.append(entry)
for base_entry in base_scope.cfunc_entries:
entry = self.add_cfunction(base_entry.name, base_entry.type, None,
adapt(base_entry.cname), base_entry.visibility)
entry = self.add_cfunction(base_entry.name, base_entry.type,
base_entry.pos, adapt(base_entry.cname), base_entry.visibility)
entry.is_inherited = 1
def allocate_temp(self, type):
......
......@@ -17,7 +17,7 @@ CFLAGS = os.getenv('CFLAGS', '').split()
class ErrorWriter(object):
match_error = re.compile('(warning:)?(?:.*:)?([-0-9]+):([-0-9]+):(.*)').match
match_error = re.compile('(warning:)?(?:.*:)?\s*([-0-9]+)\s*:\s*([-0-9]+)\s*:\s*(.*)').match
def __init__(self):
self.output = []
self.write = self.output.append
......@@ -31,8 +31,9 @@ class ErrorWriter(object):
is_warning, line, column, message = match.groups()
if (is_warning and collect_warnings) or \
(not is_warning and collect_errors):
result.append( "%d:%d:%s" % (int(line), int(column), message.strip()) )
return result
result.append( (int(line), int(column), message.strip()) )
result.sort()
return [ "%d:%d:%s" % values for values in result ]
def geterrors(self):
return self._collect(True, False)
......
void e1(void);
void *e2(void);
cdef extern void g(int x) nogil
cdef extern object g(object x) nogil
cdef extern void g2(object x) nogil
cdef extern from "nogil.h":
void e1() nogil
int *e2() nogil
cdef void f(int x) nogil:
cdef int y
y = 42
cdef int y
y = 42
cdef void h(object x) nogil:
cdef void *p
g2(x)
g2(<object>p)
p = <void *>x
e1()
e2()
cdef object f(object x) nogil:
pass
cdef void g(int x) nogil:
cdef object z
z = None
cdef void h(int x) nogil:
p()
cdef object p() nogil:
pass
cdef void r() nogil:
q()
cdef object m():
cdef object x, y, obj
cdef int i, j, k
global fred
q()
with nogil:
r()
q()
i = 42
obj = None
17L
7j
help
`"Hello"`
import fred
from fred import obj
for x in obj:
pass
obj[i]
obj[i:j]
obj[i:j:k]
obj.fred
(x, y)
[x, y]
{x: y}
obj and x
t(obj)
# f(42) # Cython handles this internally
x + obj
-obj
x = y = obj
x, y = y, x
obj[i] = x
obj.fred = x
print obj
del fred
return obj
raise obj
if obj:
pass
while obj:
pass
for x <= obj <= y:
pass
try:
pass
except:
pass
try:
pass
finally:
pass
cdef void q():
pass
cdef class C:
pass
cdef void t(C c) nogil:
pass
_ERRORS = u"""
1: 5: Function with Python return type cannot be declared nogil
6: 6: Assignment of Python object not allowed without gil
4: 5: Function declared nogil has Python locals or temporaries
8: 5: Function declared nogil has Python locals or temporaries
11: 5: Function with Python return type cannot be declared nogil
15: 5: Calling gil-requiring function without gil
24: 9: Calling gil-requiring function without gil
26:12: Assignment of Python object not allowed without gil
27: 8: Constructing Python long int not allowed without gil
28: 8: Constructing complex number not allowed without gil
29:12: Accessing Python global or builtin not allowed without gil
30: 8: Backquote expression not allowed without gil
31:15: Python import not allowed without gil
31:15: Assignment of Python object not allowed without gil
32:13: Python import not allowed without gil
32:25: Constructing Python list not allowed without gil
33:17: Iterating over Python object not allowed without gil
35:11: Indexing Python object not allowed without gil
36:11: Slicing Python object not allowed without gil
37:11: Constructing Python slice object not allowed without gil
37:11: Indexing Python object not allowed without gil
37:13: Converting to Python object not allowed without gil
37:15: Converting to Python object not allowed without gil
37:17: Converting to Python object not allowed without gil
38:11: Accessing Python attribute not allowed without gil
39: 9: Constructing Python tuple not allowed without gil
40: 8: Constructing Python list not allowed without gil
41: 8: Constructing Python dict not allowed without gil
42:12: Creating temporary Python reference not allowed without gil
42:12: Truth-testing Python object not allowed without gil
42:17: Creating temporary Python reference not allowed without gil
43:13: Python type test not allowed without gil
#44: 4: Converting to Python object not allowed without gil
45:10: Operation not allowed without gil
46: 8: Operation not allowed without gil
47:10: Assignment of Python object not allowed without gil
47:14: Assignment of Python object not allowed without gil
48: 9: Assignment of Python object not allowed without gil
48:13: Assignment of Python object not allowed without gil
48:16: Creating temporary Python reference not allowed without gil
48:19: Creating temporary Python reference not allowed without gil
49:11: Indexing Python object not allowed without gil
49:11: Assignment of Python object not allowed without gil
50:11: Accessing Python attribute not allowed without gil
50:11: Assignment of Python object not allowed without gil
51: 8: Constructing Python tuple not allowed without gil
51: 8: Python print statement not allowed without gil
52: 8: Deleting Python object not allowed without gil
53: 8: Returning Python object not allowed without gil
54: 8: Raising exception not allowed without gil
55:14: Truth-testing Python object not allowed without gil
57:17: Truth-testing Python object not allowed without gil
59: 8: Converting to Python object not allowed without gil
61: 8: Try-except statement not allowed without gil
65: 8: Try-finally statement not allowed without gil
"""
cdef extern from *:
cdef void f() nogil
cdef void (*fp)()
fp = f
_ERRORS = u"""
5:6: Cannot assign type 'void (void) nogil' to 'void (*)(void)'
"""
......@@ -18,5 +18,5 @@ def g():
h()
return 1
cdef int h() except -1:
cdef int h() nogil except -1:
pass
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