From 0e71f50a863e199992746e6caf7a23a3aecfa7f9 Mon Sep 17 00:00:00 2001
From: Dag Sverre Seljebotn <dagss@student.matnat.uio.no>
Date: Thu, 25 Sep 2008 18:33:27 +0200
Subject: [PATCH] nonecheck directive for buffer accesses

---
 Cython/Compiler/ExprNodes.py | 20 ++++++++++++++++++++
 tests/run/nonecheck.pyx      | 18 ++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index cd9a5a461..2c7aaf440 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -1498,6 +1498,8 @@ class IndexNode(ExprNode):
 
     def generate_result_code(self, code):
         if self.is_buffer_access:
+            if code.globalstate.directives['nonecheck']:
+                self.put_nonecheck(code)
             ptrcode = self.buffer_lookup_code(code)
             code.putln("%s = *%s;" % (
                 self.result(),
@@ -1541,6 +1543,8 @@ class IndexNode(ExprNode):
 
     def generate_buffer_setitem_code(self, rhs, code, op=""):
         # Used from generate_assignment_code and InPlaceAssignmentNode
+        if code.globalstate.directives['nonecheck']:
+            self.put_nonecheck(code)
         ptrexpr = self.buffer_lookup_code(code)
         if self.buffer_type.dtype.is_pyobject:
             # Must manage refcounts. Decref what is already there
@@ -1607,6 +1611,13 @@ class IndexNode(ExprNode):
                                              options=code.globalstate.directives,
                                              pos=self.pos, code=code)
 
+    def put_nonecheck(self, code):
+        code.globalstate.use_utility_code(raise_noneindex_error_utility_code)
+        code.putln("if (%s) {" % code.unlikely("%s == Py_None") % self.base.result_as(PyrexTypes.py_object_type))
+        code.putln("__Pyx_RaiseNoneIndexingError();")
+        code.putln(code.error_goto(self.pos))
+        code.putln("}")
+
 class SliceIndexNode(ExprNode):
     #  2-element slice indexing
     #
@@ -4587,3 +4598,12 @@ static INLINE void __Pyx_RaiseNoneAttributeError(char* attrname) {
     PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", attrname);
 }
 """]
+
+raise_noneindex_error_utility_code = [
+"""
+static INLINE void __Pyx_RaiseNoneIndexingError();
+""", """
+static INLINE void __Pyx_RaiseNoneIndexingError() {
+    PyErr_SetString(PyExc_TypeError, "'NoneType' object is unsubscriptable");
+}
+"""]
diff --git a/tests/run/nonecheck.pyx b/tests/run/nonecheck.pyx
index 7645acd03..79ba6f101 100644
--- a/tests/run/nonecheck.pyx
+++ b/tests/run/nonecheck.pyx
@@ -32,6 +32,16 @@ Traceback (most recent call last):
    ...
 AttributeError: 'NoneType' object has no attribute 'a'
 
+>>> check_buffer_get(None)
+Traceback (most recent call last):
+   ...
+TypeError: 'NoneType' object is unsubscriptable
+
+>>> check_buffer_set(None)
+Traceback (most recent call last):
+   ...
+TypeError: 'NoneType' object is unsubscriptable
+
 """
 
 cimport cython
@@ -70,3 +80,11 @@ def check_and_assign(MyClass var):
         var = None
         print var.a
 
+@cython.nonecheck(True)
+def check_buffer_get(object[int] buf):
+    return buf[0]
+
+@cython.nonecheck(True)
+def check_buffer_set(object[int] buf):
+    buf[0] = 1
+
-- 
2.30.9