From 021488a5a1e0116188fe38c857387a838c967066 Mon Sep 17 00:00:00 2001
From: Lisandro Dalcin <dalcinl@gmail.com>
Date: Thu, 10 Sep 2009 10:50:11 -0300
Subject: [PATCH] extern ctypedef integral <-> python object conversion (ticket
 #333)

---
 Cython/Compiler/ExprNodes.py               |   5 +-
 Cython/Compiler/Nodes.py                   |   5 +-
 Cython/Compiler/PyrexTypes.py              | 182 ++++--
 tests/run/ctypedef_int_types_T333.pyx      | 674 +++++++++++++++++++++
 tests/run/ctypedef_int_types_chdr_T333.h   |  10 +
 tests/run/ctypedef_int_types_defs_T333.pxd |  15 +
 6 files changed, 845 insertions(+), 46 deletions(-)
 create mode 100644 tests/run/ctypedef_int_types_T333.pyx
 create mode 100644 tests/run/ctypedef_int_types_chdr_T333.h
 create mode 100644 tests/run/ctypedef_int_types_defs_T333.pxd

diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index af94ed033..abf575ab6 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -3933,8 +3933,7 @@ class TypecastNode(NewTempExprNode):
         if from_py and not to_py and self.operand.is_ephemeral() and not self.type.is_numeric:
             error(self.pos, "Casting temporary Python object to non-numeric non-Python type")
         if to_py and not from_py:
-            if (self.operand.type.to_py_function and
-                    self.operand.type.create_to_py_utility_code(env)):
+            if self.operand.type.create_to_py_utility_code(env):
                 self.result_ctype = py_object_type
                 self.operand = self.operand.coerce_to_pyobject(env)
             else:
@@ -3942,7 +3941,7 @@ class TypecastNode(NewTempExprNode):
                     warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.operand.type, self.type))
                 self.operand = self.operand.coerce_to_simple(env)
         elif from_py and not to_py:
-            if self.type.from_py_function:
+            if self.type.create_from_py_utility_code(env):
                 self.operand = self.operand.coerce_to(self.type, env)
             elif self.type.is_ptr and not (self.type.base_type.is_void or self.type.base_type.is_struct):
                 error(self.pos, "Python objects cannot be casted to pointers of primitive types")
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index a1efb2558..e1b4524f9 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -1964,8 +1964,9 @@ class DefNode(FuncDefNode):
             or self.starstar_arg is not None or has_kwonly_args
 
         for arg in self.args:
-            if not arg.type.is_pyobject and arg.type.from_py_function is None:
-                arg.type.create_from_py_utility_code(env)
+            if not arg.type.is_pyobject:
+                done = arg.type.create_from_py_utility_code(env)
+                if not done: pass # will fail later
 
         if not self.signature_has_generic_args():
             if has_star_or_kw_args:
diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py
index 3048d36dc..2c393992b 100644
--- a/Cython/Compiler/PyrexTypes.py
+++ b/Cython/Compiler/PyrexTypes.py
@@ -163,12 +163,15 @@ class CTypedefType(BaseType):
     
     is_typedef = 1
     typedef_is_external = 0
+
+    to_py_utility_code = None
+    from_py_utility_code = None
+    
     
     def __init__(self, cname, base_type, is_external=0):
         self.typedef_cname = cname
         self.typedef_base_type = base_type
         self.typedef_is_external = is_external
-
         # Make typecodes in external typedefs use typesize-neutral macros
         if is_external:
             typecode = None
@@ -206,13 +209,70 @@ class CTypedefType(BaseType):
             return self.typedef_base_type.cast_code(expr_code)
         else:
             return BaseType.cast_code(self, expr_code)
-    
+
     def __repr__(self):
         return "<CTypedefType %s>" % self.typedef_cname
     
     def __str__(self):
         return self.declaration_name(for_display = 1)
-    
+
+    def _create_utility_code(self, template_utility_code,
+                             template_function_name):
+        type_name = self.typedef_cname.replace(" ","_")
+        utility_code = template_utility_code.specialize(
+            type     = self.typedef_cname,
+            TypeName = type_name)
+        function_name = template_function_name % type_name
+        return utility_code, function_name
+
+    def create_to_py_utility_code(self, env):
+        if self.typedef_is_external:
+            if not self.to_py_utility_code:
+                base_type = self.typedef_base_type
+                if base_type.is_int:
+                    self.to_py_utility_code, self.to_py_function = \
+                        self._create_utility_code(c_typedef_int_to_py_function,
+                                                  '__Pyx_PyInt_to_py_%s')
+                elif base_type.is_float:
+                    pass # XXX implement!
+                elif base_type.is_complex:
+                    pass # XXX implement!
+                    pass
+            if self.to_py_utility_code:
+                env.use_utility_code(self.to_py_utility_code)
+                return True
+        # delegation
+        return self.typedef_base_type.create_to_py_utility_code(env)
+
+    def create_from_py_utility_code(self, env):
+        if self.typedef_is_external:
+            if not self.from_py_utility_code:
+                base_type = self.typedef_base_type
+                if base_type.is_int:
+                    self.from_py_utility_code, self.from_py_function = \
+                        self._create_utility_code(c_typedef_int_from_py_function,
+                                                  '__Pyx_PyInt_from_py_%s')
+                elif base_type.is_float:
+                    pass # XXX implement!
+                elif base_type.is_complex:
+                    pass # XXX implement!
+            if self.from_py_utility_code:
+                env.use_utility_code(self.from_py_utility_code)
+                return True
+        # delegation
+        return self.typedef_base_type.create_from_py_utility_code(env)
+
+    def error_condition(self, result_code):
+        if self.typedef_is_external:
+            if self.exception_value:
+                condition = "(%s == (%s)%s)" % (
+                    result_code, self.typedef_cname, self.exception_value)
+                if self.exception_check:
+                    condition += " && PyErr_Occurred()"
+                return condition
+        # delegation
+        return self.typedef_base_type.error_condition(result_code)
+
     def __getattr__(self, name):
         return getattr(self.typedef_base_type, name)
 
@@ -540,9 +600,12 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) {
         long val = __Pyx_PyInt_AsLong(x);
         if (unlikely(val != (long)(%(type)s)val)) {
             if (unlikely(val == -1 && PyErr_Occurred()))
-                return (%(type)s)-1;""" + \
-           "%(IntValSignTest)s" + \
-"""
+                return (%(type)s)-1;
+            if (((%(type)s)-1) > ((%(type)s)0) && unlikely(val < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to %(type)s");
+                return (%(type)s)-1;
+            }
             PyErr_SetString(PyExc_OverflowError,
                            "value too large to convert to %(type)s");
             return (%(type)s)-1;
@@ -552,12 +615,6 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) {
     return (%(type)s)__Pyx_PyInt_As%(SignWord)sLong(x);
 }
 """)
-intval_signtest = """
-            if (unlikely(%(var)s < 0)) {
-                PyErr_SetString(PyExc_OverflowError,
-                                "can't convert negative value to %(type)s");
-                return (%(type)s)-1;
-            }"""
 
 c_long_from_py_function = UtilityCode(
 proto="""
@@ -566,17 +623,25 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject *);
 impl="""
 static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) {
 #if PY_VERSION_HEX < 0x03000000
-    if (likely(PyInt_CheckExact(x) || PyInt_Check(x))) {
-        long val = PyInt_AS_LONG(x);""" + \
-       "%(IntValSignTest)s" + \
-"""
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (((%(type)s)-1) > ((%(type)s)0) && unlikely(val < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to %(type)s");
+            return (%(type)s)-1;
+        }
         return (%(type)s)val;
     } else
 #endif
-    if (likely(PyLong_CheckExact(x) || PyLong_Check(x))) {""" +\
-       "%(PyLongSignTest)s" + \
-"""
-        return %(PyLongConvert)s(x);
+    if (likely(PyLong_Check(x))) {
+        if (((%(type)s)-1) > ((%(type)s)0) && unlikely(Py_SIZE(x) < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to %(type)s");
+            return (%(type)s)-1;
+        }
+        return (((%(type)s)-1) < ((%(type)s)0)) ?
+               PyLong_As%(TypeName)s(x) :
+               PyLong_AsUnsigned%(TypeName)s(x);
     } else {
         %(type)s val;
         PyObject *tmp = __Pyx_PyNumber_Int(x);
@@ -587,14 +652,63 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) {
     }
 }
 """)
-pylong_signtest = """
-        if (unlikely(Py_SIZE(%(var)s) < 0)) {
-            PyErr_SetString(PyExc_OverflowError,
-                            "can't convert negative value to %(type)s");
-            return (%(type)s)-1;
-        }"""
 
+c_typedef_int_from_py_function = UtilityCode(
+proto="""
+static INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject *);
+""",
+impl="""
+static INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject* x) {
+  /**/ if (sizeof(%(type)s) == sizeof(char))
+     return (((%(type)s)-1) < ((%(type)s)0)) ?
+            (%(type)s)__Pyx_PyInt_AsSignedChar(x) :
+            (%(type)s)__Pyx_PyInt_AsUnsignedChar(x);
+  else if (sizeof(%(type)s) == sizeof(short))
+     return (((%(type)s)-1) < ((%(type)s)0)) ?
+            (%(type)s)__Pyx_PyInt_AsSignedShort(x) :
+            (%(type)s)__Pyx_PyInt_AsUnsignedShort(x);
+  else if (sizeof(%(type)s) == sizeof(int))
+     return (((%(type)s)-1) < ((%(type)s)0)) ?
+            (%(type)s)__Pyx_PyInt_AsSignedInt(x) :
+            (%(type)s)__Pyx_PyInt_AsUnsignedInt(x);
+  else if (sizeof(%(type)s) == sizeof(long))
+     return (((%(type)s)-1) < ((%(type)s)0)) ?
+            (%(type)s)__Pyx_PyInt_AsSignedLong(x) :
+            (%(type)s)__Pyx_PyInt_AsUnsignedLong(x);
+  else if (sizeof(%(type)s) == sizeof(PY_LONG_LONG))
+     return (((%(type)s)-1) < ((%(type)s)0)) ?
+            (%(type)s)__Pyx_PyInt_AsSignedLongLong(x) :
+            (%(type)s)__Pyx_PyInt_AsUnsignedLongLong(x);
+#if 0
+  else if (sizeof(%(type)s) > sizeof(short) &&
+           sizeof(%(type)s) < sizeof(int)) /*  __int32 ILP64 ? */
+     return (((%(type)s)-1) < ((%(type)s)0)) ?
+            (%(type)s)__Pyx_PyInt_AsSignedInt(x) :
+            (%(type)s)__Pyx_PyInt_AsUnsignedInt(x);
+#endif
+  PyErr_SetString(PyExc_TypeError, "%(TypeName)s");
+  return (%(type)s)-1;
+}
+""")
 
+c_typedef_int_to_py_function = UtilityCode(
+proto="""
+static INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s);
+""",
+impl="""
+static INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s val) {
+  /**/ if (sizeof(%(type)s) <  sizeof(long))
+      return PyInt_FromLong((long)val);
+  else if (sizeof(%(type)s) == sizeof(long))
+     return (((%(type)s)-1) < ((%(type)s)0)) ? 
+            PyInt_FromLong((long)val) :
+            PyLong_FromUnsignedLong((unsigned long)val);
+  else /* (sizeof(%(type)s) >  sizeof(long)) */
+     return (((%(type)s)-1) < ((%(type)s)0)) ?
+            PyLong_FromLongLong((PY_LONG_LONG)val) :
+            PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val);
+}
+""")
 
 class CIntType(CNumericType):
 
@@ -620,27 +734,13 @@ class CIntType(CNumericType):
         type_name = type_name.replace("PY_LONG_LONG","long long")
         SignWord  = sign_word.title()
         TypeName  = type_name.title().replace(" ", "")
-        data = {'IntValSignTest' : "",
-                'PyLongSignTest' : "",
-                'PyLongConvert'  : "",
-                }
-        if not self.signed:
-            data['IntValSignTest'] = intval_signtest % {'var':"val", 'type':ctype}
-            data['PyLongSignTest'] = pylong_signtest % {'var':"x",   'type':ctype}
         if "Long" in TypeName:
-            data['PyLongConvert'] = \
-                "PyLong_As" + SignWord.replace("Signed", "") + TypeName
-            # the replaces below are just for generating well indented C code
-            data['IntValSignTest'] = "\n".join(
-                [ln.replace(" "*4, "", 1) for ln in data['IntValSignTest'].split('\n')]
-                )
             utility_code = c_long_from_py_function
         else:
             utility_code = c_int_from_py_function
         utility_code.specialize(self,
                                 SignWord=SignWord,
-                                TypeName=TypeName,
-                                **data)
+                                TypeName=TypeName)
         func_name = "__Pyx_PyInt_As%s%s" % (SignWord, TypeName)
         return func_name
 
diff --git a/tests/run/ctypedef_int_types_T333.pyx b/tests/run/ctypedef_int_types_T333.pyx
new file mode 100644
index 000000000..5d9371b7f
--- /dev/null
+++ b/tests/run/ctypedef_int_types_T333.pyx
@@ -0,0 +1,674 @@
+__doc__ = u""
+
+# -------------------------------------------------------------------
+
+cdef extern from "ctypedef_int_types_chdr_T333.h":
+     ctypedef int SChar     ## "signed char"
+     ctypedef int UChar     ## "unsigned char"
+     ctypedef int SShort    ## "signed short"
+     ctypedef int UShort    ## "unsigned short"
+     ctypedef int SInt      ## "signed int"
+     ctypedef int UInt      ## "unsigned int"
+     ctypedef int SLong     ## "signed long"
+     ctypedef int ULong     ## "unsigned long"
+     ctypedef int SLongLong ## "signed PY_LONG_LONG"
+     ctypedef int ULongLong ## "unsigned PY_LONG_LONG"
+
+# -------------------------------------------------------------------
+
+SCHAR_MAX = <SChar>((<UChar>-1)>>1)
+SCHAR_MIN = (-SCHAR_MAX-1)
+
+def test_schar(SChar x):
+   u"""
+   >>> test_schar(-129) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_schar(-128)
+   -128
+   >>> test_schar(0)
+   0
+   >>> test_schar(127)
+   127
+   >>> test_schar(128) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   return x
+
+def test_add_schar(x, y):
+   u"""
+   >>> test_add_schar(SCHAR_MIN, -1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_add_schar(SCHAR_MIN, 0) == SCHAR_MIN
+   True
+   >>> test_add_schar(SCHAR_MIN, 1) == SCHAR_MIN+1
+   True
+   >>> test_add_schar(SCHAR_MAX, -1) == SCHAR_MAX-1
+   True
+   >>> test_add_schar(SCHAR_MAX, 0) == SCHAR_MAX
+   True
+   >>> test_add_schar(SCHAR_MAX, 1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   cdef SChar r = x + y
+   return r
+
+UCHAR_MAX = <UChar>((<UChar>-1))
+
+def test_uchar(UChar x):
+   u"""
+   >>> test_uchar(-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_uchar(0)
+   0
+   >>> test_uchar(1)
+   1
+   >>> test_uchar(UCHAR_MAX) == UCHAR_MAX
+   True
+   >>> test_uchar(UCHAR_MAX+1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   return x
+
+def test_add_uchar(x, y):
+   u"""
+   >>> test_add_uchar(UCHAR_MAX, 0) == UCHAR_MAX
+   True
+   >>> test_add_uchar(UCHAR_MAX, 1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   cdef UChar r = x + y
+   return r
+
+# -------------------------------------------------------------------
+
+SSHORT_MAX = <SShort>((<UShort>-1)>>1)
+SSHORT_MIN = (-SSHORT_MAX-1)
+
+def test_sshort(short x):
+   u"""
+   >>> test_sshort(SSHORT_MIN-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_sshort(SSHORT_MIN) == SSHORT_MIN
+   True
+   >>> test_sshort(-1)
+   -1
+   >>> test_sshort(0)
+   0
+   >>> test_sshort(1)
+   1
+   >>> test_sshort(SSHORT_MAX) == SSHORT_MAX
+   True
+   >>> test_sshort(SSHORT_MAX+1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   return x
+
+def test_add_sshort(x, y):
+   u"""
+   >>> test_add_sshort(SSHORT_MIN, -1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_add_sshort(SSHORT_MIN, 0) == SSHORT_MIN
+   True
+   >>> test_add_sshort(SSHORT_MIN, 1) == SSHORT_MIN+1
+   True
+   >>> test_add_sshort(SSHORT_MAX, -1) == SSHORT_MAX-1
+   True
+   >>> test_add_sshort(SSHORT_MAX, 0) == SSHORT_MAX
+   True
+   >>> test_add_sshort(SSHORT_MAX, 1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   cdef SShort r = x + y
+   return r
+
+USHORT_MAX = <UShort>((<UShort>-1))
+
+def test_ushort(UShort x):
+   u"""
+   >>> test_ushort(-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_ushort(0)
+   0
+   >>> test_ushort(1)
+   1
+   >>> test_ushort(USHORT_MAX) == USHORT_MAX
+   True
+   >>> test_ushort(USHORT_MAX+1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   return x
+
+def test_add_ushort(x, y):
+   u"""
+   >>> test_add_ushort(USHORT_MAX, 0) == USHORT_MAX
+   True
+   >>> test_add_ushort(USHORT_MAX, 1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   cdef UShort r = x + y
+   return r
+
+# -------------------------------------------------------------------
+
+SINT_MAX = <SInt>((<UInt>-1)>>1)
+SINT_MIN = (-SINT_MAX-1)
+
+def test_sint(int x):
+   u"""
+   >>> test_sint(SINT_MIN-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_sint(SINT_MIN) == SINT_MIN
+   True
+   >>> test_sint(-1)
+   -1
+   >>> test_sint(0)
+   0
+   >>> test_sint(1)
+   1
+   >>> test_sint(SINT_MAX) == SINT_MAX
+   True
+   >>> test_sint(SINT_MAX+1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   return x
+
+def test_add_sint(x, y):
+   u"""
+   >>> test_add_sint(SINT_MIN, -1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_add_sint(SINT_MIN, 0) == SINT_MIN
+   True
+   >>> test_add_sint(SINT_MIN, 1) == SINT_MIN+1
+   True
+   >>> test_add_sint(SINT_MAX, -1) == SINT_MAX-1
+   True
+   >>> test_add_sint(SINT_MAX, 0) == SINT_MAX
+   True
+   >>> test_add_sint(SINT_MAX, 1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   cdef SInt r = x + y
+   return r
+
+UINT_MAX = <UInt>(<UInt>-1)
+
+def test_uint(UInt x):
+   u"""
+   >>> test_uint(-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> print(test_uint(0))
+   0
+   >>> print(test_uint(1))
+   1
+   >>> test_uint(UINT_MAX) == UINT_MAX
+   True
+   >>> test_uint(UINT_MAX+1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   return x
+
+def test_add_uint(x, y):
+   u"""
+   >>> test_add_uint(UINT_MAX, 0) == UINT_MAX
+   True
+   >>> test_add_uint(UINT_MAX, 1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   cdef UInt r = x + y
+   return r
+
+# -------------------------------------------------------------------
+
+SLONG_MAX = <SLong>((<ULong>-1)>>1)
+SLONG_MIN = (-SLONG_MAX-1)
+
+def test_slong(long x):
+   u"""
+   >>> test_slong(SLONG_MIN-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_slong(SLONG_MIN) == SLONG_MIN
+   True
+   >>> test_slong(-1)
+   -1
+   >>> test_slong(0)
+   0
+   >>> test_slong(1)
+   1
+   >>> test_slong(SLONG_MAX) == SLONG_MAX
+   True
+   >>> test_slong(SLONG_MAX+1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   return x
+
+def test_add_slong(x, y):
+   u"""
+   >>> test_add_slong(SLONG_MIN, -1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_add_slong(SLONG_MIN, 0) == SLONG_MIN
+   True
+   >>> test_add_slong(SLONG_MIN, 1) == SLONG_MIN+1
+   True
+   >>> test_add_slong(SLONG_MAX, -1) == SLONG_MAX-1
+   True
+   >>> test_add_slong(SLONG_MAX, 0) == SLONG_MAX
+   True
+   >>> test_add_slong(SLONG_MAX, 1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   cdef SLong r = x + y
+   return r
+
+ULONG_MAX = <ULong>(<ULong>-1)
+
+def test_ulong(ULong x):
+   u"""
+   >>> test_ulong(-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> print(test_ulong(0))
+   0
+   >>> print(test_ulong(1))
+   1
+   >>> test_ulong(ULONG_MAX) == ULONG_MAX
+   True
+   >>> test_ulong(ULONG_MAX+1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   return x
+
+def test_add_ulong(x, y):
+   u"""
+   >>> test_add_ulong(ULONG_MAX, 0) == ULONG_MAX
+   True
+   >>> test_add_ulong(ULONG_MAX, 1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   cdef ULong r = x + y
+   return r
+
+# -------------------------------------------------------------------
+
+SLONGLONG_MAX = <SLongLong>((<ULongLong>-1)>>1)
+SLONGLONG_MIN = (-SLONGLONG_MAX-1)
+
+def test_slonglong(long long x):
+   u"""
+   >>> test_slonglong(SLONGLONG_MIN-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_slonglong(SLONGLONG_MIN) == SLONGLONG_MIN
+   True
+   >>> print(test_slonglong(-1))
+   -1
+   >>> print(test_slonglong(0))
+   0
+   >>> print(test_slonglong(1))
+   1
+   >>> test_slonglong(SLONGLONG_MAX) == SLONGLONG_MAX
+   True
+   >>> test_slonglong(SLONGLONG_MAX+1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   return x
+
+def test_add_slonglong(x, y):
+   u"""
+   >>> test_add_slonglong(SLONGLONG_MIN, -1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_add_slonglong(SLONGLONG_MIN, 0) == SLONGLONG_MIN
+   True
+   >>> test_add_slonglong(SLONGLONG_MIN, 1) == SLONGLONG_MIN+1
+   True
+   >>> test_add_slonglong(SLONGLONG_MAX, -1) == SLONGLONG_MAX-1
+   True
+   >>> test_add_slonglong(SLONGLONG_MAX, 0) == SLONGLONG_MAX
+   True
+   >>> test_add_slonglong(SLONGLONG_MAX, 1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   cdef SLongLong r = x + y
+   return r
+
+ULONGLONG_MAX = <ULongLong>(<ULongLong>-1)
+
+def test_ulonglong(ULongLong x):
+   u"""
+   >>> test_ulonglong(-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> print(test_ulonglong(0))
+   0
+   >>> print(test_ulonglong(1))
+   1
+   >>> test_ulonglong(ULONGLONG_MAX) == ULONGLONG_MAX
+   True
+   >>> test_ulonglong(ULONGLONG_MAX+1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   return x
+
+def test_add_ulonglong(x, y):
+   u"""
+   >>> test_add_ulonglong(ULONGLONG_MAX, 0) == ULONGLONG_MAX
+   True
+   >>> test_add_ulonglong(ULONGLONG_MAX, 1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   """
+   cdef ULongLong r = x + y
+   return r
+
+# -------------------------------------------------------------------
+
+cdef class MyClass:
+    """
+    >>> a = MyClass()
+
+    >>> vals = (SCHAR_MIN,     UCHAR_MAX,
+    ...         SSHORT_MIN,    USHORT_MAX,
+    ...         SINT_MIN,      UINT_MAX,
+    ...         SLONG_MIN,     ULONG_MAX,
+    ...         SLONGLONG_MIN, ULONGLONG_MAX)
+    >>> a.setvalues(*vals)
+    >>> a.getvalues() == vals
+    True
+
+    >>> vals = (SCHAR_MAX,     UCHAR_MAX,
+    ...         SSHORT_MAX,    USHORT_MAX,
+    ...         SINT_MAX,      UINT_MAX,
+    ...         SLONG_MAX,     ULONG_MAX,
+    ...         SLONGLONG_MAX, ULONGLONG_MAX)
+    >>> a.setvalues(*vals)
+    >>> a.getvalues() == vals
+    True
+
+    >>> vals = (0,) * 10
+    >>> a.setvalues(*vals)
+    >>> a.getvalues() == vals
+    True
+
+
+    """
+    cdef:
+       SChar     attr_schar
+       UChar     attr_uchar
+       SShort    attr_sshort
+       UShort    attr_ushort
+       SInt      attr_sint
+       UInt      attr_uint
+       SLong     attr_slong
+       ULong     attr_ulong
+       SLongLong attr_slonglong
+       ULongLong attr_ulonglong
+
+    cpdef setvalues(self,
+                    SChar     arg_schar     ,
+                    UChar     arg_uchar     ,
+                    SShort    arg_sshort    ,
+                    UShort    arg_ushort    ,
+                    SInt      arg_sint      ,
+                    UInt      arg_uint      ,
+                    SLong     arg_slong     ,
+                    ULong     arg_ulong     ,
+                    SLongLong arg_slonglong ,
+                    ULongLong arg_ulonglong ):
+        self.attr_schar     = arg_schar
+        self.attr_uchar     = arg_uchar
+        self.attr_sshort    = arg_sshort
+        self.attr_ushort    = arg_ushort
+        self.attr_sint      = arg_sint
+        self.attr_uint      = arg_uint
+        self.attr_slong     = arg_slong
+        self.attr_ulong     = arg_ulong
+        self.attr_slonglong = arg_slonglong
+        self.attr_ulonglong = arg_ulonglong
+
+    cpdef getvalues(self):
+        return (self.attr_schar     ,
+                self.attr_uchar     ,
+                self.attr_sshort    ,
+                self.attr_ushort    ,
+                self.attr_sint      ,
+                self.attr_uint      ,
+                self.attr_slong     ,
+                self.attr_ulong     ,
+                self.attr_slonglong ,
+                self.attr_ulonglong )
+
+
+# -------------------------------------------------------------------
+
+cdef extern from *:
+    ctypedef signed   MySInt1 "signed short"
+    ctypedef unsigned MyUInt1 "unsigned short"
+
+def test_MySInt1(MySInt1 x):
+   u"""
+   >>> test_MySInt1(-1)
+   -1
+   >>> test_MySInt1(0)
+   0
+   >>> test_MySInt1(1)
+   1
+   """
+   return x
+
+def test_MyUInt1(MyUInt1 x):
+   u"""
+   >>> test_MyUInt1(-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_MyUInt1(0)
+   0
+   >>> test_MyUInt1(1)
+   1
+   """
+   return x
+
+cdef extern from *:
+    ctypedef signed   MySInt2 "signed short"
+    ctypedef unsigned MyUInt2 "unsigned short"
+
+def test_MySInt2(MySInt2 x):
+   u"""
+   >>> test_MySInt2(-1)
+   -1
+   >>> test_MySInt2(0)
+   0
+   >>> test_MySInt2(1)
+   1
+   """
+   return x
+
+def test_MyUInt2(MyUInt2 x):
+   u"""
+   >>> test_MyUInt2(-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_MyUInt2(0)
+   0
+   >>> test_MyUInt2(1)
+   1
+   """
+   return x
+
+# -------------------------------------------------------------------
+
+cimport ctypedef_int_types_defs_T333 as defs
+
+def test_DefSInt(defs.SInt x):
+   u"""
+   >>> test_DeftSInt(-1)
+   -1
+   >>> test_DefSInt(0)
+   0
+   >>> test_DefSInt(1)
+   1
+   """
+   return x
+
+def test_DefUInt(defs.UInt x):
+   u"""
+   >>> test_DefUInt(-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_DefUInt(0)
+   0
+   >>> test_DefUInt(1)
+   1
+   """
+   return x
+
+def test_ExtSInt(defs.ExtSInt x):
+   u"""
+   >>> test_ExtSInt(-1)
+   -1
+   >>> test_ExtSInt(0)
+   0
+   >>> test_ExtSInt(1)
+   1
+   """
+   return x
+
+def test_ExtUInt(defs.ExtUInt x):
+   u"""
+   >>> test_ExtUInt(-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_ExtUInt(0)
+   0
+   >>> test_ExtUInt(1)
+   1
+   """
+   return x
+
+
+ctypedef defs.SShort LocSInt
+ctypedef defs.UShort LocUInt
+
+def test_LocSInt(LocSInt x):
+   u"""
+   >>> test_LocSInt(-1)
+   -1
+   >>> test_LocSInt(0)
+   0
+   >>> test_LocSInt(1)
+   1
+   """
+   return x
+
+def test_LocUInt(LocUInt x):
+   u"""
+   >>> test_LocUInt(-1) #doctest: +ELLIPSIS
+   Traceback (most recent call last):
+       ...
+   OverflowError: ...
+   >>> test_LocUInt(0)
+   0
+   >>> test_LocUInt(1)
+   1
+   """
+   return x
+
+# -------------------------------------------------------------------
+
+__doc__ = u"".join([
+      f.__doc__ for f in (
+         #
+         test_schar, test_add_schar,
+         test_uchar, test_add_uchar,
+         #
+         test_sshort, test_add_sshort,
+         test_ushort, test_add_ushort,
+         #
+         test_sint, test_add_sint,
+         test_uint, test_add_uint,
+         #
+         test_slong, test_add_slong,
+         test_ulong, test_add_ulong,
+         #
+         test_slonglong, test_add_slonglong,
+         test_ulonglong, test_add_ulonglong,
+         #
+         MyClass,
+         #
+         test_MySInt1, test_MyUInt1,
+         test_MySInt2, test_MyUInt2,
+         #
+         test_ExtSInt, test_ExtUInt,
+         test_LocSInt, test_LocUInt,
+         )
+    ])
+
+# -------------------------------------------------------------------
diff --git a/tests/run/ctypedef_int_types_chdr_T333.h b/tests/run/ctypedef_int_types_chdr_T333.h
new file mode 100644
index 000000000..66b6158c5
--- /dev/null
+++ b/tests/run/ctypedef_int_types_chdr_T333.h
@@ -0,0 +1,10 @@
+typedef signed   char  	    SChar;
+typedef unsigned char  	    UChar;
+typedef signed   short 	    SShort;
+typedef unsigned short 	    UShort;
+typedef signed   int   	    SInt;
+typedef unsigned int   	    UInt;
+typedef signed   long  	    SLong;
+typedef unsigned long  	    ULong;
+typedef signed   long long  SLongLong;
+typedef unsigned long long  ULongLong;
diff --git a/tests/run/ctypedef_int_types_defs_T333.pxd b/tests/run/ctypedef_int_types_defs_T333.pxd
new file mode 100644
index 000000000..8fbe0f510
--- /dev/null
+++ b/tests/run/ctypedef_int_types_defs_T333.pxd
@@ -0,0 +1,15 @@
+cdef extern from "ctypedef_int_types_chdr_T333.h":
+    ctypedef int SChar     ## "signed char"
+    ctypedef int UChar     ## "unsigned char"
+    ctypedef int SShort    ## "signed short"
+    ctypedef int UShort    ## "unsigned short"
+    ctypedef int SInt      ## "signed int"
+    ctypedef int UInt      ## "unsigned int"
+    ctypedef int SLong     ## "signed long"
+    ctypedef int ULong     ## "unsigned long"
+    ctypedef int SLongLong ## "signed PY_LONG_LONG"
+    ctypedef int ULongLong ## "unsigned PY_LONG_LONG"
+
+cdef extern from *:
+    ctypedef int ExtSInt "signed short"
+    ctypedef int ExtUInt "unsigned short"
-- 
2.30.9