Imported Upstream version 0.28.3 upstream/0.28.3
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 03:08:50 +0000 (12:08 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 03:08:50 +0000 (12:08 +0900)
17 files changed:
CHANGES.rst
Cython/Compiler/ExprNodes.py
Cython/Compiler/ModuleNode.py
Cython/Compiler/Symtab.py
Cython/Shadow.py
Cython/Utility/Exceptions.c
Cython/Utility/ModuleSetupCode.c
Cython/Utility/Optimize.c
Cython/Utility/TypeConversion.c
docs/CONTRIBUTING.txt [new file with mode: 0644]
docs/src/userguide/wrapping_CPlusPlus.rst
tests/run/cpp_bool_template_return.pyx [new file with mode: 0644]
tests/run/cpp_operators.pyx
tests/run/cpp_operators_helper.h
tests/run/cpp_templates_helper.h
tests/run/fstring.pyx
tests/run/libcpp_all.pyx

index 19f3323..45b7055 100644 (file)
@@ -2,6 +2,21 @@
 Cython Changelog
 ================
 
+0.28.3 (2018-05-27)
+===================
+
+Bugs fixed
+----------
+
+* Set iteration was broken in non-CPython since 0.28.
+
+* ``UnicodeEncodeError`` in Py2 when ``%s`` formatting is optimised for
+  unicode strings.  (Github issue #2276)
+
+* Work around a crash bug in g++ 4.4.x by disabling the size reduction setting
+  of the module init function in this version.  (Github issue #2235)
+
+
 0.28.2 (2018-04-13)
 ===================
 
@@ -14,7 +29,7 @@ Features added
   ``libcpp.string``.  Patch by Alex Huszagh.  (Github issue #2123)
 
 * The C++11 methods ``reserve()`` and ``bucket_count()`` are declared for
-  ``std::unordered_map``.  Patch by Valentin Valls.  (Github issue #2168)
+  ``libcpp.unordered_map``.  Patch by Valentin Valls.  (Github issue #2168)
 
 Bugs fixed
 ----------
index b3dbd9d..2c538df 100644 (file)
@@ -3164,7 +3164,7 @@ class FormattedValueNode(ExprNode):
     c_format_spec = None
 
     find_conversion_func = {
-        's': 'PyObject_Str',
+        's': 'PyObject_Unicode',
         'r': 'PyObject_Repr',
         'a': 'PyObject_ASCII',  # NOTE: mapped to PyObject_Repr() in Py2
     }.get
@@ -11053,9 +11053,8 @@ class CBinopNode(BinopNode):
         cpp_type = None
         if type1.is_cpp_class or type1.is_ptr:
             cpp_type = type1.find_cpp_operation_type(self.operator, type2)
-        # FIXME: handle the reversed case?
-        #if cpp_type is None and (type2.is_cpp_class or type2.is_ptr):
-        #    cpp_type = type2.find_cpp_operation_type(self.operator, type1)
+        if cpp_type is None and (type2.is_cpp_class or type2.is_ptr):
+            cpp_type = type2.find_cpp_operation_type(self.operator, type1)
         # FIXME: do we need to handle other cases here?
         return cpp_type
 
index bd1db3a..9449502 100644 (file)
@@ -707,7 +707,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         code.putln('static PyObject *%s = NULL;' % env.module_cname)
         code.putln('static PyObject *%s;' % env.module_dict_cname)
         code.putln('static PyObject *%s;' % Naming.builtins_cname)
-        code.putln('static PyObject *%s;' % Naming.cython_runtime_cname)
+        code.putln('static PyObject *%s = NULL;' % Naming.cython_runtime_cname)
         code.putln('static PyObject *%s;' % Naming.empty_tuple)
         code.putln('static PyObject *%s;' % Naming.empty_bytes)
         code.putln('static PyObject *%s;' % Naming.empty_unicode)
index 21e89e7..4fe903c 100644 (file)
@@ -907,10 +907,28 @@ class Scope(object):
                 if res is not None:
                     return res
         function = self.lookup("operator%s" % operator)
-        if function is None:
+        function_alternatives = []
+        if function is not None:
+            function_alternatives = function.all_alternatives()
+
+        # look-up nonmember methods listed within a class
+        method_alternatives = []
+        if len(operands)==2: # binary operators only
+            for n in range(2):
+                if operands[n].type.is_cpp_class:
+                    obj_type = operands[n].type
+                    method = obj_type.scope.lookup("operator%s" % operator)
+                    if method is not None:
+                        method_alternatives += method.all_alternatives()
+
+        if (not method_alternatives) and (not function_alternatives):
             return None
+
+        # select the unique alternatives
+        all_alternatives = list(set(method_alternatives + function_alternatives))
+
         return PyrexTypes.best_match([arg.type for arg in operands],
-                                     function.all_alternatives())
+                                     all_alternatives)
 
     def lookup_operator_for_types(self, pos, operator, types):
         from .Nodes import Node
index 8d68bc0..0f14a58 100644 (file)
@@ -1,7 +1,7 @@
 # cython.* namespace for pure mode.
 from __future__ import absolute_import
 
-__version__ = "0.28.2"
+__version__ = "0.28.3"
 
 try:
     from __builtin__ import basestring
index 1774156..8628e3a 100644 (file)
@@ -617,6 +617,12 @@ static int __Pyx_CLineForTraceback(CYTHON_UNUSED PyThreadState *tstate, int c_li
 #if CYTHON_COMPILING_IN_CPYTHON
     PyObject **cython_runtime_dict;
 #endif
+
+    if (unlikely(!${cython_runtime_cname})) {
+        // Very early error where the runtime module is not set up yet.
+        return c_line;
+    }
+
     __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback);
 
 #if CYTHON_COMPILING_IN_CPYTHON
index 2aeabd2..c1ba400 100644 (file)
@@ -558,6 +558,7 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) {
   #define PyString_Type                PyUnicode_Type
   #define PyString_Check               PyUnicode_Check
   #define PyString_CheckExact          PyUnicode_CheckExact
+  #define PyObject_Unicode             PyObject_Str
 #endif
 
 #if PY_MAJOR_VERSION >= 3
@@ -668,7 +669,8 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) {
 #ifndef CYTHON_SMALL_CODE
 #if defined(__clang__)
     #define CYTHON_SMALL_CODE
-#elif defined(__GNUC__)
+#elif defined(__GNUC__) && (!(defined(__cplusplus)) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4)))
+    // At least g++ 4.4.7 can generate crashing code with this option. (GH #2235)
     #define CYTHON_SMALL_CODE __attribute__((optimize("Os")))
 #else
     #define CYTHON_SMALL_CODE
index fa5a8d5..13277ab 100644 (file)
@@ -438,17 +438,17 @@ static CYTHON_INLINE PyObject* __Pyx_set_iterator(PyObject* iterable, int is_set
 #if CYTHON_COMPILING_IN_CPYTHON
     is_set = is_set || likely(PySet_CheckExact(iterable) || PyFrozenSet_CheckExact(iterable));
     *p_source_is_set = is_set;
-    if (unlikely(!is_set))
-        return PyObject_GetIter(iterable);
-    *p_orig_length = PySet_Size(iterable);
-    Py_INCREF(iterable);
-    return iterable;
+    if (likely(is_set)) {
+        *p_orig_length = PySet_Size(iterable);
+        Py_INCREF(iterable);
+        return iterable;
+    }
 #else
     (void)is_set;
     *p_source_is_set = 0;
+#endif
     *p_orig_length = 0;
     return PyObject_GetIter(iterable);
-#endif
 }
 
 static CYTHON_INLINE int __Pyx_set_iter_next(
@@ -462,7 +462,7 @@ static CYTHON_INLINE int __Pyx_set_iter_next(
         }
         (void)orig_length;
         (void)ppos;
-        return 0;
+        return 1;
     }
 #if CYTHON_COMPILING_IN_CPYTHON
     if (unlikely(PySet_GET_SIZE(iter_obj) != orig_length)) {
@@ -480,9 +480,9 @@ static CYTHON_INLINE int __Pyx_set_iter_next(
             Py_INCREF(*value);
             return 1;
         }
-        return 0;
     }
 #endif
+    return 0;
 }
 
 /////////////// py_set_discard_unhashable ///////////////
index 734e293..bf8d3b1 100644 (file)
@@ -84,7 +84,7 @@ static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) {
 
 #define __Pyx_NewRef(obj) (Py_INCREF(obj), obj)
 #define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None)
-#define __Pyx_PyBool_FromLong(b) ((b) ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False))
+static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b);
 static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
 static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x);
 
@@ -402,6 +402,12 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
   return ival;
 }
 
+
+static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) {
+  return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False);
+}
+
+
 static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) {
     return PyInt_FromSize_t(ival);
 }
diff --git a/docs/CONTRIBUTING.txt b/docs/CONTRIBUTING.txt
new file mode 100644 (file)
index 0000000..90c2fe9
--- /dev/null
@@ -0,0 +1,11 @@
+Welcome, and thank you for your interest in contributing!
+=========================================================
+
+If you are looking for a good way to contribute to the Cython project, please
+- have a look at the [Cython Hacker Guide](https://github.com/cython/cython/wiki/HackerGuide)
+- look through the [issues that need help](https://github.com/cython/cython/issues?q=is%3Aissue+is%3Aopen+view+label%3A%22help+wanted%22)
+- look through the [issues that are a good entry point for beginners](https://github.com/cython/cython/issues?q=is%3Aissue+is%3Aopen+view+label%3A%22good+first+issue%22)
+
+If you have code that you want to contribute, please make sure that it
+- includes tests in the `tests/` directory (see the [Hacker Guide on Testing](https://github.com/cython/cython/wiki/HackerGuide#the-test-suite))
+- comes in form of a pull request
index eb6301b..b1e9a6b 100644 (file)
@@ -321,6 +321,10 @@ Cython uses C++ naming for overloading operators::
             Foo operator-(Foo)
             int operator*(Foo)
             int operator/(int)
+            int operator*(int, Foo) # allows 1*Foo()
+        # nonmember operators can also be specified outside the class
+        double operator/(double, Foo)
+
 
     cdef Foo foo = new Foo()
 
@@ -330,6 +334,13 @@ Cython uses C++ naming for overloading operators::
     x = foo * foo2
     x = foo / 1
 
+    x = foo[0] * foo2
+    x = foo[0] / 1
+    x = 1*foo[0]
+
+    cdef double y
+    y = 2.0/foo[0]
+
 Note that if one has *pointers* to C++ objects, dereferencing must be done
 to avoid doing pointer arithmetic rather than arithmetic on the objects
 themselves::
diff --git a/tests/run/cpp_bool_template_return.pyx b/tests/run/cpp_bool_template_return.pyx
new file mode 100644 (file)
index 0000000..fced8ad
--- /dev/null
@@ -0,0 +1,16 @@
+# tag: cpp
+
+from libcpp cimport bool
+
+cdef extern from "cpp_templates_helper.h":
+    cdef cppclass BinaryAnd[T1, T2]:
+        @staticmethod
+        T1 call(T1 x, T2 y)
+
+
+def test_compound_bool_return(bool x, bool y):
+    """
+    >>> test_compound_bool_return(True, False)
+    False
+    """
+    return BinaryAnd[bool, bool].call(x, y)
index e1877d1..aca865f 100644 (file)
@@ -27,18 +27,29 @@ cdef extern from "cpp_operators_helper.h" nogil:
         const_char* operator--(int)
 
         const_char* operator+(int)
+        const_char* operator+(int,const TestOps&)
         const_char* operator-(int)
+        const_char* operator-(int,const TestOps&)
         const_char* operator*(int)
+        # deliberately omitted operator* to test case where only defined outside class
         const_char* operator/(int)
+        const_char* operator/(int,const TestOps&)
         const_char* operator%(int)
+        const_char* operator%(int,const TestOps&)
 
         const_char* operator|(int)
+        const_char* operator|(int,const TestOps&)
         const_char* operator&(int)
+        const_char* operator&(int,const TestOps&)
         const_char* operator^(int)
+        const_char* operator^(int,const TestOps&)
         const_char* operator,(int)
+        const_char* operator,(int,const TestOps&)
 
         const_char* operator<<(int)
+        const_char* operator<<(int,const TestOps&)
         const_char* operator>>(int)
+        const_char* operator>>(int,const TestOps&)
 
         const_char* operator==(int)
         const_char* operator!=(int)
@@ -49,6 +60,23 @@ cdef extern from "cpp_operators_helper.h" nogil:
 
         const_char* operator[](int)
         const_char* operator()(int)
+    
+    # Defining the operator outside the class does work
+    # but doesn't help when importing from pxd files
+    # (they don't get imported)
+    const_char* operator+(float,const TestOps&)
+    # deliberately omitted operator- to test case where only defined in class
+    const_char* operator*(float,const TestOps&)
+    const_char* operator/(float,const TestOps&)
+    const_char* operator%(float,const TestOps&)
+
+    const_char* operator|(float,const TestOps&)
+    const_char* operator&(float,const TestOps&)
+    const_char* operator^(float,const TestOps&)
+    const_char* operator,(float,const TestOps&)
+
+    const_char* operator<<(float,const TestOps&)
+    const_char* operator>>(float,const TestOps&)
 
     cdef cppclass TruthClass:
         TruthClass()
@@ -129,6 +157,63 @@ def test_binop():
     out(x, typeof(x))
     del t
 
+def test_nonmember_binop():
+    """
+    >>> test_nonmember_binop()
+    nonmember binary + [const_char *]
+    nonmember binary - [const_char *]
+    nonmember binary / [const_char *]
+    nonmember binary % [const_char *]
+    nonmember binary & [const_char *]
+    nonmember binary | [const_char *]
+    nonmember binary ^ [const_char *]
+    nonmember binary << [const_char *]
+    nonmember binary >> [const_char *]
+    nonmember binary COMMA [const_char *]
+    nonmember binary2 + [const_char *]
+    nonmember binary2 * [const_char *]
+    nonmember binary2 / [const_char *]
+    nonmember binary2 % [const_char *]
+    nonmember binary2 & [const_char *]
+    nonmember binary2 | [const_char *]
+    nonmember binary2 ^ [const_char *]
+    nonmember binary2 << [const_char *]
+    nonmember binary2 >> [const_char *]
+    nonmember binary2 COMMA [const_char *]
+    """
+    
+    cdef TestOps* t = new TestOps()
+    out(1 + t[0], typeof(1 + t[0]))
+    out(1 - t[0], typeof(1 - t[0]))
+    # * deliberately omitted
+    out(1 / t[0], typeof(1 / t[0]))
+    out(1 % t[0], typeof(1 % t[0]))
+    out(1 & t[0], typeof(1 & t[0]))
+    out(1 | t[0], typeof(1 | t[0]))
+    out(1 ^ t[0], typeof(1 ^ t[0]))
+    out(1 << t[0], typeof(1 << t[0]))
+    out(1 >> t[0], typeof(1 >> t[0]))
+    
+    x = cython.operator.comma(1, t[0])
+    out(x, typeof(x))
+    
+    # now test float operators defined outside class
+    out(1. + t[0], typeof(1. + t[0]))
+    # operator - deliberately omitted
+    out(1. * t[0], typeof(1. * t[0]))
+    out(1. / t[0], typeof(1. / t[0]))
+    out(1. % t[0], typeof(1. % t[0]))
+    out(1. & t[0], typeof(1. & t[0]))
+    out(1. | t[0], typeof(1. | t[0]))
+    out(1. ^ t[0], typeof(1. ^ t[0]))
+    out(1. << t[0], typeof(1. << t[0]))
+    out(1. >> t[0], typeof(1. >> t[0]))
+    
+    # for some reason we need a cdef here - not sure this is quite right
+    y = cython.operator.comma(1., t[0])
+    out(y, typeof(y))
+    del t
+
 def test_cmp():
     """
     >>> test_cmp()
index 36685c5..5ae21ff 100644 (file)
@@ -1,6 +1,8 @@
 #define UN_OP(op) const char* operator op () { return "unary "#op; }
 #define POST_UN_OP(op) const char* operator op (int x) { x++; return "post "#op; }
 #define BIN_OP(op) const char* operator op (int x) { x++; return "binary "#op; }
+#define NONMEMBER_BIN_OP(op) const char* operator op (int x, const TestOps&) { x++; return "nonmember binary "#op; }
+#define NONMEMBER_BIN_OP2(op) const char* operator op (double x, const TestOps&) { x++; return "nonmember binary2 "#op; }
 
 #define COMMA ,
 
@@ -46,6 +48,34 @@ public:
 
 };
 
+NONMEMBER_BIN_OP(+)
+NONMEMBER_BIN_OP(-)
+NONMEMBER_BIN_OP(*)
+NONMEMBER_BIN_OP(/)
+NONMEMBER_BIN_OP(%)
+
+NONMEMBER_BIN_OP(<<)
+NONMEMBER_BIN_OP(>>)
+
+NONMEMBER_BIN_OP(|)
+NONMEMBER_BIN_OP(&)
+NONMEMBER_BIN_OP(^)
+NONMEMBER_BIN_OP(COMMA)
+
+NONMEMBER_BIN_OP2(+)
+NONMEMBER_BIN_OP2(-)
+NONMEMBER_BIN_OP2(*)
+NONMEMBER_BIN_OP2(/)
+NONMEMBER_BIN_OP2(%)
+
+NONMEMBER_BIN_OP2(<<)
+NONMEMBER_BIN_OP2(>>)
+
+NONMEMBER_BIN_OP2(|)
+NONMEMBER_BIN_OP2(&)
+NONMEMBER_BIN_OP2(^)
+NONMEMBER_BIN_OP2(COMMA)
+
 class TruthClass {
 public:
   TruthClass() : value(false) {}
index 8973e6c..629ac65 100644 (file)
@@ -44,3 +44,9 @@ class Div {
 public:
     static T half(T value) { return value / 2; }
 };
+
+template <class T1, class T2>
+class BinaryAnd {
+public:
+    static T1 call(T1 x, T2 y) { return x & y; }
+};
index b12387d..7abbb4f 100644 (file)
@@ -500,3 +500,16 @@ def generated_fstring(int i, unicode u not None, o):
         u, u, u, u,
         o, o, o, o,
     )
+
+
+@cython.test_assert_path_exists(
+    "//FormattedValueNode",
+    "//JoinedStrNode",
+)
+def percent_s_unicode(u, int i):
+    u"""
+    >>> u = u'x\u0194z'
+    >>> print(percent_s_unicode(u, 12))
+    x\u0194z-12
+    """
+    return u"%s-%d" % (u, i)
index 45983ba..2930807 100644 (file)
@@ -94,6 +94,7 @@ cdef const_vector_to_list(const vector[double]& cv):
         cython.operator.preincrement(iter)
     return lst
 
+
 cdef double dmax = numeric_limits[double].max()
 cdef double dmin = numeric_limits[double].min()
 cdef double deps = numeric_limits[double].epsilon()
@@ -124,4 +125,23 @@ def convert_to_vector(I):
     """
     cdef vector[int] x = I
 
-    
+
+def complex_operators():
+    """
+    >>> complex_operators()
+    [-1.0, 0.0, 0.0, 2.0, 0.0, 2.0]
+    """
+    cdef libcpp.complex.complex[double] a = libcpp.complex.complex[double](0.0,1.0)
+    cdef libcpp.complex.complex[double] r1=a*a
+    cdef libcpp.complex.complex[double] r2=a*2.0
+    cdef libcpp.complex.complex[double] r3=2.0*a
+    return [r1.real(), r1.imag(), r2.real(), r2.imag(), r3.real(), r3.imag()]
+
+def pair_comparison():
+    """
+    >>> pair_comparison()
+    [False, True, False, True, False]
+    """
+    cdef pair[double, double] p1 = pair[double, double](1.0,2.0)
+    cdef pair[double, double] p2 = pair[double, double](2.0,2.0)
+    return [p1==p2,p1==p1,p1>p2,p1<p2,p2>p2]