summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoam Hershtig <noam@beeeye.co>2019-02-23 02:27:21 +0200
committerNoam Hershtig <noam@beeeye.co>2019-02-23 22:13:56 +0200
commit73133f68bf9ce72b77d0a54662af18834860bc1b (patch)
treec31cf669b5fd046f52156d44172c4a74e6abd14c
parent5ff75cdabb810221cbb656643e07031651a55757 (diff)
downloadcython-73133f68bf9ce72b77d0a54662af18834860bc1b.tar.gz
Create run tests for conditional GILStatNode
-rw-r--r--Cython/Compiler/Nodes.py2
-rw-r--r--Cython/Compiler/Optimize.py2
-rw-r--r--Cython/Compiler/ParseTreeTransforms.py12
-rw-r--r--tests/run/nogil_conditional.pyx267
4 files changed, 279 insertions, 4 deletions
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index 1e49021cf..8da95cc39 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -7794,7 +7794,7 @@ class GILStatNode(NogilTryFinallyStatNode):
#
# state string 'gil' or 'nogil'
- child_attrs = ["body", "condition", "finally_clause", "finally_except_clause"]
+ child_attrs = ["condition"] + NogilTryFinallyStatNode.child_attrs
state_temp = None
def __init__(self, pos, state, body, condition=None):
diff --git a/Cython/Compiler/Optimize.py b/Cython/Compiler/Optimize.py
index 03af40780..ffba4c72d 100644
--- a/Cython/Compiler/Optimize.py
+++ b/Cython/Compiler/Optimize.py
@@ -4700,7 +4700,7 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
node.condition = None
# Condition is False - the body of the GILStatNode
- # should run without changing changing the state of the gil
+ # should run without changing the state of the gil
# return the body of the GILStatNode
else:
return node.body
diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py
index d1f9f598f..189804ed0 100644
--- a/Cython/Compiler/ParseTreeTransforms.py
+++ b/Cython/Compiler/ParseTreeTransforms.py
@@ -2916,8 +2916,9 @@ class GilCheck(VisitorTransform):
def visit_GILStatNode(self, node):
if node.condition is not None:
- error(node.pos, "Non-constant condition in a "
- "`with %s(<condition>)` statement" % node.state)
+ error(node.condition.pos,
+ "Non-constant condition in a "
+ "`with %s(<condition>)` statement" % node.state)
return node
if self.nogil and node.nogil_check:
@@ -3259,6 +3260,13 @@ class ReplaceFusedTypeChecks(VisitorTransform):
self.visitchildren(node)
return self.transform(node)
+ def visit_GILStatNode(self, node):
+ """
+ Fold constant condition of GILStatNode.
+ """
+ self.visitchildren(node)
+ return self.transform(node)
+
def visit_PrimaryCmpNode(self, node):
with Errors.local_errors(ignore=True):
type1 = node.operand1.analyse_as_type(self.local_scope)
diff --git a/tests/run/nogil_conditional.pyx b/tests/run/nogil_conditional.pyx
new file mode 100644
index 000000000..56a05bb5c
--- /dev/null
+++ b/tests/run/nogil_conditional.pyx
@@ -0,0 +1,267 @@
+# mode: run
+
+try:
+ from StringIO import StringIO
+except ImportError:
+ from io import StringIO
+
+
+def test(int x):
+ """
+ >>> test(0)
+ 110
+ """
+ with nogil(True):
+ x = f_nogil(x)
+ with gil(True):
+ x = f_gil(x)
+ return x
+
+
+cdef int f_nogil(int x) nogil:
+ cdef int y
+ y = x + 10
+ return y
+
+
+def f_gil(x):
+ y = 0
+ y = x + 100
+ return y
+
+
+cdef int with_gil_func() except? -1 with gil:
+ raise Exception("error!")
+
+
+cdef int nogil_func() nogil except? -1:
+ with_gil_func()
+
+
+def test_nogil_exception_propagation():
+ """
+ >>> test_nogil_exception_propagation()
+ Traceback (most recent call last):
+ ...
+ Exception: error!
+ """
+ with nogil:
+ with gil:
+ with nogil(True):
+ nogil_func()
+
+
+cdef int write_unraisable() nogil:
+ with gil:
+ raise ValueError()
+
+
+def test_unraisable():
+ """
+ >>> print(test_unraisable()) # doctest: +ELLIPSIS
+ ValueError
+ Exception...ignored...
+ """
+ import sys
+ old_stderr = sys.stderr
+ stderr = sys.stderr = StringIO()
+ try:
+ write_unraisable()
+ finally:
+ sys.stderr = old_stderr
+ return stderr.getvalue().strip()
+
+
+def test_nested():
+ """
+ >>> test_nested()
+ 240
+ """
+ cdef int res = 0
+
+ with nogil(True):
+ res = f_nogil(res)
+ with gil(1 < 2):
+ res = f_gil(res)
+ with nogil:
+ res = f_nogil(res)
+
+ with gil:
+ res = f_gil(res)
+ with nogil(True):
+ res = f_nogil(res)
+ with nogil:
+ res = f_nogil(res)
+
+ return res
+
+
+def test_nested_condition_false():
+ """
+ >>> test_nested_condition_false()
+ 220
+ """
+ cdef int res = 0
+
+ with gil(False):
+ res = f_gil(res)
+ with nogil(False):
+ res = f_gil(res)
+
+ with nogil(True):
+ res = f_nogil(res)
+ with gil(False):
+ res = f_nogil(res)
+
+ return res
+
+def test_try_finally():
+ """
+ >>> test_try_finally()
+ 113
+ """
+ cdef int res = 0
+
+ try:
+ with nogil(True):
+ try:
+ res = f_nogil(res)
+ with gil(1 < 2):
+ try:
+ res = f_gil(res)
+ finally:
+ res += 1
+ finally:
+ res = res + 1
+ finally:
+ res += 1
+
+ return res
+
+
+ctypedef fused number_or_object:
+ int
+ float
+ object
+
+
+def test_fused(number_or_object x) -> number_or_object:
+ """
+ >>> test_fused[int](1)
+ 2
+ >>> test_fused[float](1.0)
+ 2.0
+ >>> test_fused[object](1)
+ 2
+ >>> test_fused[object](1.0)
+ 2.0
+ """
+ cdef number_or_object res = x
+
+ with nogil(number_or_object is not object):
+ res = res + 1
+
+ return res
+
+
+ctypedef fused int_or_object:
+ int
+ object
+
+
+def test_fused_object(int_or_object x):
+ """
+ >>> test_fused_object[object]("spam")
+ 456
+ >>> test_fused_object[int](1000)
+ 1000
+ """
+ cdef int res = 0
+
+ if int_or_object is object:
+ with nogil(False):
+ res += len(x)
+
+ try:
+ with nogil(int_or_object is object):
+ try:
+ with gil(int_or_object is object):
+ res = f_gil(res)
+ with gil:
+ res = f_gil(res)
+ with gil(False):
+ res = f_nogil(res)
+
+ with gil(int_or_object is not object):
+ res = f_nogil(res)
+ with nogil(False):
+ res = f_nogil(res)
+
+ res = f_nogil(res)
+ finally:
+ res = res + 1
+
+ with nogil(int_or_object is not object):
+ res = f_gil(res)
+
+ with gil(int_or_object is not object):
+ res = f_gil(res)
+
+ with nogil(int_or_object is object):
+ res = f_nogil(res)
+
+ finally:
+ res += 1
+ else:
+ res = x
+
+ return res
+
+
+def test_fused_int(int_or_object x):
+ """
+ >>> test_fused_int[object]("spam")
+ 4
+ >>> test_fused_int[int](1000)
+ 1452
+ """
+ cdef int res = 0
+
+ if int_or_object is int:
+ res += x
+
+ try:
+ with nogil(int_or_object is int):
+ try:
+ with gil(int_or_object is int):
+ res = f_gil(res)
+ with gil:
+ res = f_gil(res)
+ with gil(False):
+ res = f_nogil(res)
+
+ with gil(int_or_object is not int):
+ res = f_nogil(res)
+ with nogil(False):
+ res = f_nogil(res)
+
+ res = f_nogil(res)
+ finally:
+ res = res + 1
+
+ with nogil(int_or_object is not int):
+ res = f_gil(res)
+
+ with gil(int_or_object is not int):
+ res = f_gil(res)
+
+ with nogil(int_or_object is int):
+ res = f_nogil(res)
+
+ finally:
+ res += 1
+ else:
+ with nogil(False):
+ res = len(x)
+
+ return res