diff options
author | Noam Hershtig <noam@beeeye.co> | 2019-02-23 02:27:21 +0200 |
---|---|---|
committer | Noam Hershtig <noam@beeeye.co> | 2019-02-23 22:13:56 +0200 |
commit | 73133f68bf9ce72b77d0a54662af18834860bc1b (patch) | |
tree | c31cf669b5fd046f52156d44172c4a74e6abd14c | |
parent | 5ff75cdabb810221cbb656643e07031651a55757 (diff) | |
download | cython-73133f68bf9ce72b77d0a54662af18834860bc1b.tar.gz |
Create run tests for conditional GILStatNode
-rw-r--r-- | Cython/Compiler/Nodes.py | 2 | ||||
-rw-r--r-- | Cython/Compiler/Optimize.py | 2 | ||||
-rw-r--r-- | Cython/Compiler/ParseTreeTransforms.py | 12 | ||||
-rw-r--r-- | tests/run/nogil_conditional.pyx | 267 |
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 |