diff --git a/CHANGES.rst b/CHANGES.rst
index b1a3373109d64038b1a84a6f85a746cce889cfff_Q0hBTkdFUy5yc3Q=..4e18ac0cf0c675d54023beb5be318b735e7e99ba_Q0hBTkdFUy5yc3Q= 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -456,7 +456,7 @@
 * Support for Python 2.6 was removed.
 
 
-0.29.21 (2020-0?-??)
+0.29.21 (2020-07-09)
 ====================
 
 Bugs fixed
@@ -465,6 +465,12 @@
 * Fix a regression in 0.29.20 where ``__div__`` failed to be found in extension types.
   (Github issue #3688)
 
+* Fix a regression in 0.29.20 where a call inside of a finally clause could fail to compile.
+  Patch by David Woods.  (Github issue #3712)
+
+* Zero-sized buffers could fail to validate as C/Fortran-contiguous.
+  Patch by Clemens Hofreither.  (Github issue #2093)
+
 * ``exec()`` did not allow recent Python syntax features in Py3.8+ due to
   https://bugs.python.org/issue35975.
   (Github issue #3695)
@@ -472,9 +478,22 @@
 * Binding staticmethods of Cython functions were not behaving like Python methods in Py3.
   Patch by Jeroen Demeyer and Michał Górny.  (Github issue #3106)
 
-* The deprecated C-API functions ``PyUnicode_FromUnicode()`` and ``PyUnicode_AS_UNICODE()``
-  are no longer used.
-  Original patch by Inada Naoki.  (Github issue #3677)
+* Pythran calls to NumPy methods no longer generate useless method lookup code.
+
+* The ``PyUnicode_GET_LENGTH()`` macro was missing from the ``cpython.*`` declarations.
+  Patch by Thomas Caswell.  (Github issue #3692)
+
+* The deprecated ``PyUnicode_*()`` C-API functions are no longer used, except for Unicode
+  strings that contain lone surrogates.  Unicode strings that contain non-BMP characters
+  or surrogate pairs now generate different C code on 16-bit Python 2.x Unicode deployments
+  (such as MS-Windows).  Generating the C code on Python 3.x is recommended in this case.
+  Original patches by Inada Naoki and Victor Stinner.  (Github issues #3677, #3721, #3697)
+
+* Some template parameters were missing from the C++ ``std::unordered_map`` declaration.
+  Patch by will.  (Github issue #3685)
+
+* Several internal code generation issues regarding temporary variables were resolved.
+  (Github issue #3708)
 
 
 0.29.20 (2020-06-10)
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index b1a3373109d64038b1a84a6f85a746cce889cfff_Q3l0aG9uL0NvbXBpbGVyL0V4cHJOb2Rlcy5weQ==..4e18ac0cf0c675d54023beb5be318b735e7e99ba_Q3l0aG9uL0NvbXBpbGVyL0V4cHJOb2Rlcy5weQ== 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -1686,9 +1686,10 @@
                 # lone (unpaired) surrogates are not really portable and cannot be
                 # decoded by the UTF-8 codec in Py3.3
                 self.result_code = code.get_py_const(py_object_type, 'ustring')
-                data_cname = code.get_pyunicode_ptr_const(self.value)
+                data_cname = code.get_string_const(
+                    StringEncoding.BytesLiteral(self.value.encode('unicode_escape')))
                 const_code = code.get_cached_constants_writer(self.result_code)
                 if const_code is None:
                     return  # already initialised
                 const_code.mark_pos(self.pos)
                 const_code.putln(
@@ -1690,9 +1691,9 @@
                 const_code = code.get_cached_constants_writer(self.result_code)
                 if const_code is None:
                     return  # already initialised
                 const_code.mark_pos(self.pos)
                 const_code.putln(
-                    "%s = PyUnicode_FromUnicode(%s, (sizeof(%s) / sizeof(Py_UNICODE))-1); %s" % (
+                    "%s = PyUnicode_DecodeUnicodeEscape(%s, sizeof(%s) - 1, NULL); %s" % (
                         self.result_code,
                         data_cname,
                         data_cname,
diff --git a/tests/run/unicodeliterals.pyx b/tests/run/unicodeliterals.pyx
index b1a3373109d64038b1a84a6f85a746cce889cfff_dGVzdHMvcnVuL3VuaWNvZGVsaXRlcmFscy5weXg=..4e18ac0cf0c675d54023beb5be318b735e7e99ba_dGVzdHMvcnVuL3VuaWNvZGVsaXRlcmFscy5weXg= 100644
--- a/tests/run/unicodeliterals.pyx
+++ b/tests/run/unicodeliterals.pyx
@@ -86,5 +86,5 @@
     True
     >>> h == u'\\ud800' # unescaped by Python (required by doctest)
     True
-    >>> p == u'\\ud800\\udc00' # unescaped by Python (required by doctest)
+    >>> p == (u'\\ud800\\udc00' if sys.maxunicode == 1114111 else u'\\U00010000')  or  p  # unescaped by Python (required by doctest)
     True
@@ -90,3 +90,3 @@
     True
-    >>> q == u'\\udc00\\ud800' # unescaped by Python (required by doctest)
+    >>> q == u'\\udc00\\ud800'  or  q  # unescaped by Python (required by doctest)
     True
@@ -92,3 +92,3 @@
     True
-    >>> k == u'\\N{SNOWMAN}' == u'\\u2603'
+    >>> k == u'\\N{SNOWMAN}' == u'\\u2603'  or  k
     True
@@ -94,3 +94,3 @@
     True
-    >>> m == u'abc\\\\xf8\\\\t\\u00f8\\U000000f8'  # unescaped by Python (required by doctest)
+    >>> m == u'abc\\\\xf8\\\\t\\u00f8\\U000000f8'  or  m  # unescaped by Python (required by doctest)
     True
@@ -96,5 +96,5 @@
     True
-    >>> add == u'Søk ik' + u'üÖä' + 'abc'
+    >>> add == u'Søk ik' + u'üÖä' + 'abc'  or  add
     True
     >>> null == u'\\x00' # unescaped by Python (required by doctest)
     True