[pypy-commit] pypy py3.5-ssl: merge py3.5

plan_rich pypy.commits at gmail.com
Tue Nov 1 09:36:54 EDT 2016


Author: Richard Plangger <planrichi at gmail.com>
Branch: py3.5-ssl
Changeset: r88030:89ea2e4a319d
Date: 2016-11-01 14:36 +0100
http://bitbucket.org/pypy/pypy/changeset/89ea2e4a319d/

Log:	merge py3.5

diff too long, truncating to 2000 out of 2128 lines

diff --git a/lib-python/3/test/test_copy.py b/lib-python/3/test/test_copy.py
--- a/lib-python/3/test/test_copy.py
+++ b/lib-python/3/test/test_copy.py
@@ -7,6 +7,7 @@
 from operator import le, lt, ge, gt, eq, ne
 
 import unittest
+from test import support
 
 order_comparisons = le, lt, ge, gt
 equality_comparisons = eq, ne
diff --git a/lib-python/3/test/test_long.py b/lib-python/3/test/test_long.py
--- a/lib-python/3/test/test_long.py
+++ b/lib-python/3/test/test_long.py
@@ -967,7 +967,7 @@
             self.assertIs(type(got), int)
 
         # bad second argument
-        bad_exponents = ('brian', 2.0, 0j, None)
+        bad_exponents = ('brian', 2.0, 0j)
         for e in bad_exponents:
             self.assertRaises(TypeError, round, 3, e)
 
diff --git a/lib-python/3/test/test_weakset.py b/lib-python/3/test/test_weakset.py
--- a/lib-python/3/test/test_weakset.py
+++ b/lib-python/3/test/test_weakset.py
@@ -11,6 +11,7 @@
 from collections import UserString as ustr
 import gc
 import contextlib
+from test import support
 
 
 class Foo:
diff --git a/lib-python/3/test/test_xml_etree.py b/lib-python/3/test/test_xml_etree.py
--- a/lib-python/3/test/test_xml_etree.py
+++ b/lib-python/3/test/test_xml_etree.py
@@ -2085,12 +2085,14 @@
         self.assertEqual(self._ilist(doc), all_tags)
         self.assertEqual(self._ilist(doc, '*'), all_tags)
 
+    @impl_detail
     def test_copy(self):
         a = ET.Element('a')
         it = a.iter()
         with self.assertRaises(TypeError):
             copy.copy(it)
 
+    @impl_detail
     def test_pickle(self):
         a = ET.Element('a')
         it = a.iter()
diff --git a/lib_pypy/_tkinter/tclobj.py b/lib_pypy/_tkinter/tclobj.py
--- a/lib_pypy/_tkinter/tclobj.py
+++ b/lib_pypy/_tkinter/tclobj.py
@@ -160,7 +160,7 @@
         encoded = value.encode('utf-16')[2:]
         buf = tkffi.new("char[]", encoded)
         inbuf = tkffi.cast("Tcl_UniChar*", buf)
-        return tklib.Tcl_NewUnicodeObj(inbuf, len(encoded)/2)
+        return tklib.Tcl_NewUnicodeObj(inbuf, len(encoded)//2)
     if isinstance(value, Tcl_Obj):
         tklib.Tcl_IncrRefCount(value._value)
         return value._value
diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py
--- a/lib_pypy/cffi/cparser.py
+++ b/lib_pypy/cffi/cparser.py
@@ -334,6 +334,8 @@
                         realtype, quals = self._get_type_and_quals(
                             decl.type, name=decl.name, partial_length_ok=True)
                     self._declare('typedef ' + decl.name, realtype, quals=quals)
+                elif decl.__class__.__name__ == 'Pragma':
+                    pass    # skip pragma, only in pycparser 2.15
                 else:
                     raise api.CDefError("unrecognized construct", decl)
         except api.FFIError as e:
diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py
--- a/lib_pypy/cffi/model.py
+++ b/lib_pypy/cffi/model.py
@@ -519,10 +519,18 @@
             smallest_value = min(self.enumvalues)
             largest_value = max(self.enumvalues)
         else:
-            raise api.CDefError("%r has no values explicitly defined: "
-                                "refusing to guess which integer type it is "
-                                "meant to be (unsigned/signed, int/long)"
-                % self._get_c_name())
+            import warnings
+            try:
+                # XXX!  The goal is to ensure that the warnings.warn()
+                # will not suppress the warning.  We want to get it
+                # several times if we reach this point several times.
+                __warningregistry__.clear()
+            except NameError:
+                pass
+            warnings.warn("%r has no values explicitly defined; "
+                          "guessing that it is equivalent to 'unsigned int'"
+                          % self._get_c_name())
+            smallest_value = largest_value = 0
         if smallest_value < 0:   # needs a signed type
             sign = 1
             candidate1 = PrimitiveType("int")
diff --git a/lib_pypy/cffi/setuptools_ext.py b/lib_pypy/cffi/setuptools_ext.py
--- a/lib_pypy/cffi/setuptools_ext.py
+++ b/lib_pypy/cffi/setuptools_ext.py
@@ -1,4 +1,5 @@
 import os
+import sys
 
 try:
     basestring
@@ -74,8 +75,13 @@
     Add py_limited_api to kwds if setuptools >= 26 is in use.
     Do not alter the setting if it already exists.
     Setuptools takes care of ignoring the flag on Python 2 and PyPy.
+
+    CPython itself should ignore the flag in a debugging version
+    (by not listing .abi3.so in the extensions it supports), but
+    it doesn't so far, creating troubles.  That's why we check
+    for "not sys.flags.debug". (http://bugs.python.org/issue28401)
     """
-    if 'py_limited_api' not in kwds:
+    if 'py_limited_api' not in kwds and not sys.flags.debug:
         import setuptools
         try:
             setuptools_major_version = int(setuptools.__version__.partition('.')[0])
diff --git a/pypy/doc/release-pypy2.7-v5.6.0.rst b/pypy/doc/release-pypy2.7-v5.6.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-pypy2.7-v5.6.0.rst
@@ -0,0 +1,142 @@
+============
+PyPy2.7 v5.6
+============
+
+We have released PyPy2.7 v5.6, about two months after PyPy2.7 v5.4.
+This new PyPy2.7 release includes the upstream stdlib version 2.7.12.
+
+We continue to make incremental improvements to our C-API
+compatability layer (cpyext). We pass all but a few of the tests in the
+upstream numpy `test suite`_. 
+
+Work proceeds at a good pace on the PyPy3.5
+version due to a grant_ from the Mozilla Foundation, and some of those
+changes have been backported to PyPy2.7 where relevant
+
+We changed ``timeit`` to now report average +- standard deviation, which is
+better than the misleading minimum value reported in CPython.
+
+XXX
+
+As always, this release fixed many issues and bugs raised by the
+growing community of PyPy users. We strongly recommend updating.
+
+You can download the PyPy2.7 v5.6 release here:
+
+    http://pypy.org/download.html
+
+We would like to thank our donors for the continued support of the PyPy
+project.
+
+We would also like to thank our contributors and
+encourage new people to join the project. PyPy has many
+layers and we need help with all of them: `PyPy`_ and `RPython`_ documentation
+improvements, tweaking popular `modules`_ to run on pypy, or general `help`_
+with making RPython's JIT even better.
+
+.. _`test suite`: https://bitbucket.org/pypy/pypy/wiki/Adventures%20in%20cpyext%20compatibility
+.. _cffi: https://cffi.readthedocs.org
+.. _grant: https://morepypy.blogspot.com/2016/08/pypy-gets-funding-from-mozilla-for.html
+.. _`PyPy`: http://doc.pypy.org
+.. _`RPython`: https://rpython.readthedocs.org
+.. _`modules`: http://doc.pypy.org/en/latest/project-ideas.html#make-more-python-modules-pypy-friendly
+.. _`help`: http://doc.pypy.org/en/latest/project-ideas.html
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`PyPy and CPython 2.7.x`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+We also welcome developers of other `dynamic languages`_ to see what RPython
+can do for them.
+
+This release supports: 
+
+  * **x86** machines on most common operating systems
+    (Linux 32/64 bits, Mac OS X 64 bits, Windows 32 bits, OpenBSD, FreeBSD)
+  
+  * newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux,
+  
+  * big- and little-endian variants of **PPC64** running Linux,
+
+  * **s390x** running Linux
+
+.. _`PyPy and CPython 2.7.x`: http://speed.pypy.org
+.. _`dynamic languages`: http://pypyjs.org
+
+Other Highlights (since 5.4 released Aug 31, 2016)
+=========================================================
+
+* New features
+  * Allow tests run with `-A` to find `libm.so` even if it is a script not a
+    dynamically loadable file
+  * Backport fixes to rposix on windows from py2.5
+  * Allow user-defined ``__getitem__`` on subclasses of ``str`` and ``unicode``
+  * Add ``inode`` to ``scandir()`` on posix systems
+  * Support more attributes on ``super``
+  * Issue #2386: non-latin1 unicode keys were ignored in ``unicode.format(**d)``
+  * Restore the ability to translate with CPython
+  * Update to CFFI 1.8.4
+  * Support the new buffer protocol in cpyext and numpypy
+  * Add ``rposix.sync()``
+  * Support full-precision nanosecond times in os.stat()
+  * Add documentation about the assembler backends to RPYthon
+  * Search for the stdlibs from the libpypy shared object rather than the pypy-c exe,
+    changes downstream packaging requirments
+  * Add ``try_inline``, like ``always_inline`` and ``dont_inline`` to RPython
+  * Reject ``'a'.strip(buffer(' '))`` like cpython (the argument to strip must
+    be ``str`` or ``unicode``)
+  * Allow ``warning.warn(('something', 1), Warning)`` like on CPython
+  * Refactor ``rclock`` and add some more ``CLOCK_xxx`` constants on
+    relevant platforms
+  * Backport the ``'faulthandler`` module from py3.5
+  * Improve the error message when trying to call a method where the ``self``
+    parameter is missing in the definition
+  * Implement ``rposix.cpu_count``
+  * Support translation on FreeBSD running on PowerPC
+  * Implement ``__rmod__`` on ``str`` and ``unicode`` types
+  * Issue warnings for stricter handling of ``__new__``, ``__init__`` args
+
+* Bug Fixes
+  * Tweak a float comparison with 0 in `backendopt.inline` to avoid rounding errors
+  * Fix translation of the sandbox
+  * Fix for an issue where `unicode.decode('utf8', 'custom_replace')` messed up
+    the last byte of a unicode string sometimes
+  * fix some calls to functions through window's COM interface
+  * fix minor leak when the C call to socketpair() fails
+  * make sure (-1.0 + 0j).__hash__(), (-1.0).__hash__() returns -2
+  * Fix for an issue where PyBytesResize was called on a fresh pyobj
+  * Fix bug in codewriter about passing the ``exitswitch`` variable to a call
+  * Don't crash in ``merge_if_blocks`` if the values are symbolics
+  * Issue #2325/2361: __class__ assignment between two classes with the same
+    slots
+  * Issue #2409: don't leak the file descriptor when doing ``open('some-dir')``
+  * Windows fixes around vmprof
+  * Don't use ``sprintf()`` from inside a signal handler
+  * Test and fix bug from the ``guard_not_forced_2`` branch, which didn't
+    save the floating-point register
+  * ``_numpypy.add.reduce`` returns a scalar now
+
+* Performance improvements:
+  * Improve method calls on oldstyle classes
+  * Clean and refactor code for testing cpyext to allow sharing with py3.5
+  * Refactor a building the map of reflected ops in ``_numpypy``
+  * Improve merging of virtual states in the JIT in order to avoid jumping to the
+    preamble
+  * In JIT residual calls, if the called function starts with a fast-path like
+    ``if x.foo != 0: return x.foo``, then inline the check before doing the
+     ``CALL``.
+  * Ensure ``make_inputargs`` fails properly when given arguments with type 
+    information
+  * Makes ``optimiseopt`` iterative instead of recursive so it can be reasoned
+    about more easily and debugging is faster
+  * Refactor and remove dead code from ``optimizeopt``, ``resume``
+  
+
+.. _resolved: http://doc.pypy.org/en/latest/whatsnew-5.6.0.html
+
+Please update, and continue to help us make PyPy better.
+
+Cheers
diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -370,48 +370,24 @@
             l += 1
         return l
 
-    def visit_FunctionDef(self, func):
+    def _visit_function(self, func, function_code_generator, extra_flag):
         self.update_position(func.lineno, True)
         # Load decorators first, but apply them after the function is created.
         self.visit_sequence(func.decorator_list)
         args = func.args
         assert isinstance(args, ast.arguments)
+        self.visit_sequence(args.defaults)
         kw_default_count = 0
         if args.kwonlyargs:
             kw_default_count = self._visit_kwonlydefaults(args)
-        self.visit_sequence(args.defaults)
         num_annotations = self._visit_annotations(func, args, func.returns)
         num_defaults = len(args.defaults) if args.defaults is not None else 0
         oparg = num_defaults
         oparg |= kw_default_count << 8
         oparg |= num_annotations << 16
-        code, qualname = self.sub_scope(FunctionCodeGenerator, func.name, func,
-                                        func.lineno)
-        self._make_function(code, oparg, qualname=qualname)
-        # Apply decorators.
-        if func.decorator_list:
-            for i in range(len(func.decorator_list)):
-                self.emit_op_arg(ops.CALL_FUNCTION, 1)
-        self.name_op(func.name, ast.Store)
-    
-    def visit_AsyncFunctionDef(self, func):
-        self.update_position(func.lineno, True)
-        # Load decorators first, but apply them after the function is created.
-        self.visit_sequence(func.decorator_list)
-        args = func.args
-        assert isinstance(args, ast.arguments)
-        kw_default_count = 0
-        if args.kwonlyargs:
-            kw_default_count = self._visit_kwonlydefaults(args)
-        self.visit_sequence(args.defaults)
-        num_annotations = self._visit_annotations(func, args, func.returns)
-        num_defaults = len(args.defaults) if args.defaults is not None else 0
-        oparg = num_defaults
-        oparg |= kw_default_count << 8
-        oparg |= num_annotations << 16
-        code, qualname = self.sub_scope(AsyncFunctionCodeGenerator, func.name, func,
-                                        func.lineno)
-        code.co_flags |= consts.CO_COROUTINE
+        code, qualname = self.sub_scope(function_code_generator, func.name,
+                                        func, func.lineno)
+        code.co_flags |= extra_flag
         self._make_function(code, oparg, qualname=qualname)
         # Apply decorators.
         if func.decorator_list:
@@ -419,14 +395,21 @@
                 self.emit_op_arg(ops.CALL_FUNCTION, 1)
         self.name_op(func.name, ast.Store)
 
+    def visit_FunctionDef(self, func):
+        self._visit_function(func, FunctionCodeGenerator, 0)
+
+    def visit_AsyncFunctionDef(self, func):
+        self._visit_function(func, AsyncFunctionCodeGenerator,
+                             consts.CO_COROUTINE)
+
     def visit_Lambda(self, lam):
         self.update_position(lam.lineno)
         args = lam.args
         assert isinstance(args, ast.arguments)
+        self.visit_sequence(args.defaults)
         kw_default_count = 0
         if args.kwonlyargs:
             kw_default_count = self._visit_kwonlydefaults(args)
-        self.visit_sequence(args.defaults)
         default_count = len(args.defaults) if args.defaults is not None else 0
         code, qualname = self.sub_scope(
             LambdaCodeGenerator, "<lambda>", lam, lam.lineno)
@@ -935,14 +918,22 @@
 
     def visit_With(self, wih):
         self.update_position(wih.lineno, True)
-        self.handle_withitem(wih, 0)
+        self.handle_withitem(wih, 0, is_async=False)
 
-    def handle_withitem(self, wih, pos):
+    def handle_withitem(self, wih, pos, is_async):
         body_block = self.new_block()
         cleanup = self.new_block()
         witem = wih.items[pos]
         witem.context_expr.walkabout(self)
-        self.emit_jump(ops.SETUP_WITH, cleanup)
+        if not is_async:
+            self.emit_jump(ops.SETUP_WITH, cleanup)
+        else:
+            self.emit_op(ops.BEFORE_ASYNC_WITH)
+            self.emit_op(ops.GET_AWAITABLE)
+            self.load_const(self.space.w_None)
+            self.emit_op(ops.YIELD_FROM)
+            self.emit_jump(ops.SETUP_ASYNC_WITH, cleanup)
+
         self.use_next_block(body_block)
         self.push_frame_block(F_BLOCK_FINALLY, body_block)
         if witem.optional_vars:
@@ -952,54 +943,24 @@
         if pos == len(wih.items) - 1:
             self.visit_sequence(wih.body)
         else:
-            self.handle_withitem(wih, pos + 1)
+            self.handle_withitem(wih, pos + 1, is_async=is_async)
         self.emit_op(ops.POP_BLOCK)
         self.pop_frame_block(F_BLOCK_FINALLY, body_block)
         self.load_const(self.space.w_None)
         self.use_next_block(cleanup)
         self.push_frame_block(F_BLOCK_FINALLY_END, cleanup)
         self.emit_op(ops.WITH_CLEANUP_START)
+        if is_async:
+            self.emit_op(ops.GET_AWAITABLE)
+            self.load_const(self.space.w_None)
+            self.emit_op(ops.YIELD_FROM)
         self.emit_op(ops.WITH_CLEANUP_FINISH)
         self.emit_op(ops.END_FINALLY)
         self.pop_frame_block(F_BLOCK_FINALLY_END, cleanup)
 
     def visit_AsyncWith(self, wih):
         self.update_position(wih.lineno, True)
-        self.handle_asyncwithitem(wih, 0)
-
-    def handle_asyncwithitem(self, wih, pos):
-        body_block = self.new_block()
-        cleanup = self.new_block()
-        witem = wih.items[pos]
-        witem.context_expr.walkabout(self)
-        self.emit_op(ops.BEFORE_ASYNC_WITH)
-        self.emit_op(ops.GET_AWAITABLE)
-        self.load_const(self.space.w_None)
-        self.emit_op(ops.YIELD_FROM)
-        self.emit_jump(ops.SETUP_ASYNC_WITH, cleanup)
-        self.use_next_block(body_block)
-        self.push_frame_block(F_BLOCK_FINALLY, body_block)
-        if witem.optional_vars:
-            witem.optional_vars.walkabout(self)
-        else:
-            self.emit_op(ops.POP_TOP)
-        if pos == len(wih.items) - 1:
-            self.visit_sequence(wih.body)
-        else:
-            self.handle_asyncwithitem(wih, pos + 1)
-        self.emit_op(ops.POP_BLOCK)
-        self.pop_frame_block(F_BLOCK_FINALLY, body_block)
-        self.load_const(self.space.w_None)
-        self.use_next_block(cleanup)
-        self.push_frame_block(F_BLOCK_FINALLY_END, cleanup)
-        self.emit_op(ops.WITH_CLEANUP_START)
-        self.emit_op(ops.GET_AWAITABLE)
-        self.load_const(self.space.w_None)
-        self.emit_op(ops.YIELD_FROM)
-        self.emit_op(ops.WITH_CLEANUP_FINISH)
-        self.emit_op(ops.END_FINALLY)
-        self.pop_frame_block(F_BLOCK_FINALLY_END, cleanup)
-
+        self.handle_asyncwithitem(wih, 0, is_async=True)
 
     def visit_Raise(self, rais):
         self.update_position(rais.lineno, True)
diff --git a/pypy/interpreter/astcompiler/symtable.py b/pypy/interpreter/astcompiler/symtable.py
--- a/pypy/interpreter/astcompiler/symtable.py
+++ b/pypy/interpreter/astcompiler/symtable.py
@@ -232,11 +232,7 @@
 class ModuleScope(Scope):
 
     def __init__(self):
-        Scope.__init__(self, "top")
-
-    def note_await(self, await_node):
-        raise SyntaxError("'await' outside async function", await_node.lineno,
-                          await_node.col_offset)
+        Scope.__init__(self, "<top-level>")
 
 
 class FunctionScope(Scope):
@@ -270,8 +266,11 @@
             self.has_yield_inside_try = True
             
     def note_await(self, await_node):
-        raise SyntaxError("'await' outside async function", await_node.lineno,
-                          await_node.col_offset)
+        if self.name == '<genexpr>':
+            msg = "'await' expressions in comprehensions are not supported"
+        else:
+            msg = "'await' outside async function"
+        raise SyntaxError(msg, await_node.lineno, await_node.col_offset)
 
     def note_return(self, ret):
         if ret.value:
@@ -305,11 +304,9 @@
         if (self.has_free or self.child_has_free) and not self.optimized:
             raise AssertionError("unknown reason for unoptimization")
 
+
 class AsyncFunctionScope(FunctionScope):
 
-    def __init__(self, name, lineno, col_offset):
-        FunctionScope.__init__(self, name, lineno, col_offset)
-
     def note_yield(self, yield_node):
         raise SyntaxError("'yield' inside async function", yield_node.lineno,
                           yield_node.col_offset)
@@ -521,7 +518,7 @@
         assert isinstance(args, ast.arguments)
         self.visit_sequence(args.defaults)
         self.visit_kwonlydefaults(args.kw_defaults)
-        new_scope = FunctionScope("lambda", lamb.lineno, lamb.col_offset)
+        new_scope = FunctionScope("<lambda>", lamb.lineno, lamb.col_offset)
         self.push_scope(new_scope, lamb)
         lamb.args.walkabout(self)
         lamb.body.walkabout(self)
@@ -531,7 +528,7 @@
         outer = comps[0]
         assert isinstance(outer, ast.comprehension)
         outer.iter.walkabout(self)
-        new_scope = FunctionScope("genexp", node.lineno, node.col_offset)
+        new_scope = FunctionScope("<genexpr>", node.lineno, node.col_offset)
         self.push_scope(new_scope, node)
         self.implicit_arg(0)
         outer.target.walkabout(self)
diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py
--- a/pypy/interpreter/astcompiler/test/test_compiler.py
+++ b/pypy/interpreter/astcompiler/test/test_compiler.py
@@ -1132,6 +1132,15 @@
         """
         py.test.raises(SyntaxError, self.simple_test, source, None, None)
 
+    def test_error_message_1(self):
+        source = """if 1:
+        async def f():
+            {await a for a in b}
+        """
+        e = py.test.raises(SyntaxError, self.simple_test, source, None, None)
+        assert e.value.msg == (
+            "'await' expressions in comprehensions are not supported")
+
 
 class AppTestCompiler:
 
diff --git a/pypy/interpreter/astcompiler/test/test_symtable.py b/pypy/interpreter/astcompiler/test/test_symtable.py
--- a/pypy/interpreter/astcompiler/test/test_symtable.py
+++ b/pypy/interpreter/astcompiler/test/test_symtable.py
@@ -44,7 +44,7 @@
         gen_scope = mod_scope.children[0]
         assert isinstance(gen_scope, symtable.FunctionScope)
         assert not gen_scope.children
-        assert gen_scope.name == "genexp"
+        assert gen_scope.name == "<genexpr>"
         return mod_scope, gen_scope
 
     def check_unknown(self, scp, *names):
@@ -251,7 +251,7 @@
         assert len(scp.children) == 1
         lscp = scp.children[0]
         assert isinstance(lscp, symtable.FunctionScope)
-        assert lscp.name == "lambda"
+        assert lscp.name == "<lambda>"
         assert lscp.lookup("x") == symtable.SCOPE_LOCAL
         assert lscp.lookup("y") == symtable.SCOPE_GLOBAL_IMPLICIT
         scp = self.mod_scope("lambda x=a: b")
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1582,7 +1582,7 @@
         from rpython.rlib import rstring
         result = self.str_w(w_obj)
         if '\x00' in result:
-            raise oefmt(self.w_TypeError,
+            raise oefmt(self.w_ValueError,
                         "argument must be a string without NUL characters")
         return rstring.assert_str0(result)
 
@@ -1591,7 +1591,7 @@
         from rpython.rlib import rstring
         result = self.bytes_w(w_obj)
         if '\x00' in result:
-            raise oefmt(self.w_TypeError,
+            raise oefmt(self.w_ValueError,
                         "argument must be a string without NUL characters")
         return rstring.assert_str0(result)
 
@@ -1637,7 +1637,7 @@
         from rpython.rlib import rstring
         result = w_obj.unicode_w(self)
         if u'\x00' in result:
-            raise oefmt(self.w_TypeError,
+            raise oefmt(self.w_ValueError,
                         "argument must be a unicode string without NUL "
                         "characters")
         return rstring.assert_str0(result)
@@ -1671,7 +1671,7 @@
             w_obj = self.fsencode(w_obj)
         result = self.bufferstr_w(w_obj, self.BUF_FULL_RO)
         if '\x00' in result:
-            raise oefmt(self.w_TypeError,
+            raise oefmt(self.w_ValueError,
                         "argument must be a string without NUL characters")
         return rstring.assert_str0(result)
 
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -254,12 +254,10 @@
         operr.normalize_exception(space)
 
         # note: w_yielded_from is always None if 'self.running'
-        w_yf = self.w_yielded_from
-        if (w_yf is not None and
+        if (self.w_yielded_from is not None and
                     operr.match(space, space.w_GeneratorExit)):
-            self.w_yielded_from = None
             try:
-                gen_close_iter(space, w_yf)
+                self._gen_close_iter(space)
             except OperationError as e:
                 return self.send_error(e)
 
@@ -270,6 +268,16 @@
                 operr.set_traceback(tb)
         return self.send_error(operr)
 
+    def _gen_close_iter(self, space):
+        assert not self.running
+        w_yf = self.w_yielded_from
+        self.w_yielded_from = None
+        self.running = True
+        try:
+            gen_close_iter(space, w_yf)
+        finally:
+            self.running = False
+
     def descr_close(self):
         """close() -> raise GeneratorExit inside generator/coroutine."""
         if self.frame is None:
@@ -279,9 +287,8 @@
         # note: w_yielded_from is always None if 'self.running'
         w_yf = self.w_yielded_from
         if w_yf is not None:
-            self.w_yielded_from = None
             try:
-                gen_close_iter(space, w_yf)
+                self._gen_close_iter(space)
             except OperationError as e:
                 operr = e
         try:
@@ -343,11 +350,11 @@
     KIND = "generator"
 
     def descr__iter__(self):
-        """x.__iter__() <==> iter(x)"""
+        """Implement iter(self)."""
         return self.space.wrap(self)
 
     def descr_next(self):
-        """x.__next__() <==> next(x)"""
+        """Implement next(self)."""
         return self.send_ex(self.space.w_None)
 
     # Results can be either an RPython list of W_Root, or it can be an
diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py
--- a/pypy/interpreter/module.py
+++ b/pypy/interpreter/module.py
@@ -147,6 +147,21 @@
             __file__ = space.unicode_w(space.repr(w___file__))
             return space.wrap(u"<module %s from %s>" % (name, __file__))
 
+    def descr_getattribute(self, space, w_attr):
+        from pypy.objspace.descroperation import object_getattribute
+        try:
+            return space.call_function(object_getattribute(space), self, w_attr)
+        except OperationError as e:
+            if not e.match(space, space.w_AttributeError):
+                raise
+            w_name = space.finditem(self.w_dict, space.wrap('__name__'))
+            if w_name is None:
+                raise oefmt(space.w_AttributeError,
+                    "module has no attribute %R", w_attr)
+            else:
+                raise oefmt(space.w_AttributeError,
+                    "module %R has no attribute %R", w_name, w_attr)
+
     def descr_module__dir__(self, space):
         w_dict = space.getattr(self, space.wrap('__dict__'))
         if not space.isinstance_w(w_dict, space.w_dict):
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -38,7 +38,7 @@
 # time you make pyc files incompatible.  This value ends up in the frozen
 # importlib, via MAGIC_NUMBER in module/_frozen_importlib/__init__.
 
-pypy_incremental_magic = 80 # bump it by 16
+pypy_incremental_magic = 96 # bump it by 16
 assert pypy_incremental_magic % 16 == 0
 assert pypy_incremental_magic < 3000 # the magic number of Python 3. There are
                                      # no known magic numbers below this value
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -1258,7 +1258,6 @@
             w_ann = space.newdict(strdict=True)
             for i in range(len(names_w) - 1, -1, -1):
                 space.setitem(w_ann, names_w[i], self.popvalue())
-        defaultarguments = self.popvalues(posdefaults)
         kw_defs_w = None
         if kwdefaults:
             kw_defs_w = []
@@ -1266,7 +1265,9 @@
                 w_defvalue = self.popvalue()
                 w_defname = self.popvalue()
                 kw_defs_w.append((w_defname, w_defvalue))
-        fn = function.Function(space, codeobj, self.get_w_globals(), defaultarguments,
+        defaultarguments = self.popvalues(posdefaults)
+        fn = function.Function(space, codeobj, self.get_w_globals(),
+                               defaultarguments,
                                kw_defs_w, freevars, w_ann, qualname=qualname)
         self.pushvalue(space.wrap(fn))
 
diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py
--- a/pypy/interpreter/test/test_compiler.py
+++ b/pypy/interpreter/test/test_compiler.py
@@ -944,6 +944,19 @@
         exc = raises(ValueError, compile, mod, 'filename', 'exec')
         assert str(exc.value) == "empty targets on Delete"
 
+    def test_evaluate_argument_definition_order(self): """
+        lst = [1, 2, 3, 4]
+        def f(a=lst.pop(), b=lst.pop(), *, c=lst.pop(), d=lst.pop()):
+            return (a, b, c, d)
+        assert f('a') == ('a', 3, 2, 1), repr(f('a'))
+        assert f() == (4, 3, 2, 1), repr(f())
+        #
+        lst = [1, 2, 3, 4]
+        f = lambda a=lst.pop(), b=lst.pop(), *, c=lst.pop(), d=lst.pop(): (
+            a, b, c, d)
+        assert f('a') == ('a', 3, 2, 1), repr(f('a'))
+        assert f() == (4, 3, 2, 1), repr(f())
+        """
 
 
 class AppTestOptimizer(object):
diff --git a/pypy/interpreter/test/test_generator.py b/pypy/interpreter/test/test_generator.py
--- a/pypy/interpreter/test/test_generator.py
+++ b/pypy/interpreter/test/test_generator.py
@@ -417,6 +417,25 @@
         assert gen.gi_yieldfrom is None
         """
 
+    def test_gi_running_in_throw_generatorexit(self): """
+        # We must force gi_running to be True on the outer generators
+        # when running an inner custom close() method.
+        class A:
+            def __iter__(self):
+                return self
+            def __next__(self):
+                return 42
+            def close(self):
+                closed.append(gen.gi_running)
+        def g():
+            yield from A()
+        gen = g()
+        assert next(gen) == 42
+        closed = []
+        raises(GeneratorExit, gen.throw, GeneratorExit)
+        assert closed == [True]
+        """
+
 
 def test_should_not_inline(space):
     from pypy.interpreter.generator import should_not_inline
diff --git a/pypy/interpreter/test/test_module.py b/pypy/interpreter/test/test_module.py
--- a/pypy/interpreter/test/test_module.py
+++ b/pypy/interpreter/test/test_module.py
@@ -3,7 +3,7 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.module import Module
 
-class TestModule: 
+class TestModule:
     def test_name(self, space):
         w = space.wrap
         m = Module(space, space.wrap('m'))
@@ -31,7 +31,7 @@
         py.test.raises(OperationError, space.getattr, w(m), w('__file__'))
 
 
-class AppTest_ModuleObject: 
+class AppTest_ModuleObject:
     def test_attr(self):
         m = __import__('builtins')
         m.x = 15
@@ -66,7 +66,7 @@
             skip("need PyPy for _pypy_interact")
         r = repr(sys)
         assert r == "<module 'sys' (built-in)>"
-        
+
         import _pypy_interact # known to be in lib_pypy
         r = repr(_pypy_interact)
         assert (r.startswith("<module '_pypy_interact' from ") and
@@ -123,7 +123,7 @@
         test_module.__loader__ = CustomLoaderWithRaisingRepr
         mod_repr = repr(test_module)
 
-        # The module has no __file__ attribute, so the repr should use 
+        # The module has no __file__ attribute, so the repr should use
         # the loader and name
         loader_repr = repr(test_module.__loader__)
         expected_repr = "<module 'test_module' ({})>".format(loader_repr)
@@ -174,3 +174,21 @@
         m = type(sys)('日本')
         assert m.__name__ == '日本'
         assert repr(m).startswith("<module '日本'")
+
+    def test_AttributeError_message(self):
+        import sys
+        test_module = type(sys)("test_module", "doc")
+        excinfo = raises(AttributeError, 'test_module.does_not_exist')
+        assert (excinfo.value.args[0] ==
+            "module 'test_module' has no attribute 'does_not_exist'")
+
+        nameless = type(sys)("nameless", "doc")
+        del nameless.__name__
+        assert not hasattr(nameless, '__name__')
+        excinfo = raises(AttributeError, 'nameless.does_not_exist')
+        assert (excinfo.value.args[0] ==
+            "module has no attribute 'does_not_exist'")
+
+    def test_weakrefable(self):
+        import weakref
+        weakref.ref(weakref)
diff --git a/pypy/interpreter/test/test_objspace.py b/pypy/interpreter/test/test_objspace.py
--- a/pypy/interpreter/test/test_objspace.py
+++ b/pypy/interpreter/test/test_objspace.py
@@ -210,9 +210,9 @@
         space = self.space
         w = space.wrap
         assert space.str0_w(w("123")) == "123"
-        exc = space.raises_w(space.w_TypeError, space.str0_w, w("123\x004"))
+        exc = space.raises_w(space.w_ValueError, space.str0_w, w("123\x004"))
         assert space.unicode0_w(w(u"123")) == u"123"
-        exc = space.raises_w(space.w_TypeError, space.unicode0_w, w(u"123\x004"))
+        exc = space.raises_w(space.w_ValueError, space.unicode0_w, w(u"123\x004"))
 
     def test_identifier_w(self):
         space = self.space
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -628,10 +628,12 @@
     __new__ = interp2app(Module.descr_module__new__.im_func),
     __init__ = interp2app(Module.descr_module__init__),
     __repr__ = interp2app(Module.descr_module__repr__),
+    __getattribute__=interp2app(Module.descr_getattribute),
     __dir__ = interp2app(Module.descr_module__dir__),
     __reduce__ = interp2app(Module.descr__reduce__),
     __dict__ = GetSetProperty(descr_get_dict, cls=Module), # module dictionaries are readonly attributes
-    __doc__ = 'module(name[, doc])\n\nCreate a module object.\nThe name must be a string; the optional doc argument can have any type.'
+    __doc__ = 'module(name[, doc])\n\nCreate a module object.\nThe name must be a string; the optional doc argument can have any type.',
+    __weakref__ = make_weakref_descr(Module),
     )
 
 getset_func_doc = GetSetProperty(Function.fget_func_doc,
diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py
--- a/pypy/module/__builtin__/functional.py
+++ b/pypy/module/__builtin__/functional.py
@@ -335,8 +335,16 @@
     def descr___iter__(self, space):
         return space.wrap(self)
 
-    def descr_length(self, space):
-        return space.wrap(0 if self.remaining == -1 else self.remaining + 1)
+    def descr_length_hint(self, space):
+        # bah, there is even a CPython test that checks that this
+        # actually calls 'len_w(w_sequence)'.  Obscure.
+        res = 0
+        if self.remaining >= 0:
+            total_length = space.len_w(self.w_sequence)
+            rem_length = self.remaining + 1
+            if rem_length <= total_length:
+                res = rem_length
+        return space.wrap(res)
 
     def descr_next(self, space):
         if self.remaining >= 0:
@@ -383,7 +391,7 @@
 W_ReversedIterator.typedef = TypeDef("reversed",
     __new__         = interp2app(W_ReversedIterator.descr___new__2),
     __iter__        = interp2app(W_ReversedIterator.descr___iter__),
-    __length_hint__ = interp2app(W_ReversedIterator.descr_length),
+    __length_hint__ = interp2app(W_ReversedIterator.descr_length_hint),
     __next__        = interp2app(W_ReversedIterator.descr_next),
     __reduce__      = interp2app(W_ReversedIterator.descr___reduce__),
     __setstate__      = interp2app(W_ReversedIterator.descr___setstate__),
diff --git a/pypy/module/__builtin__/test/test_functional.py b/pypy/module/__builtin__/test/test_functional.py
--- a/pypy/module/__builtin__/test/test_functional.py
+++ b/pypy/module/__builtin__/test/test_functional.py
@@ -527,6 +527,25 @@
         assert list(reversed(list(reversed("hello")))) == ['h','e','l','l','o']
         raises(TypeError, reversed, reversed("hello"))
 
+    def test_reversed_length_hint(self):
+        lst = [1, 2, 3]
+        r = reversed(lst)
+        assert r.__length_hint__() == 3
+        assert next(r) == 3
+        assert r.__length_hint__() == 2
+        lst.pop()
+        assert r.__length_hint__() == 2
+        lst.pop()
+        assert r.__length_hint__() == 0
+        raises(StopIteration, next, r)
+        #
+        r = reversed(lst)
+        assert r.__length_hint__() == 1
+        assert next(r) == 1
+        assert r.__length_hint__() == 0
+        raises(StopIteration, next, r)
+        assert r.__length_hint__() == 0
+
 
 class AppTestAllAny:
     """
diff --git a/pypy/module/_cffi_backend/cbuffer.py b/pypy/module/_cffi_backend/cbuffer.py
--- a/pypy/module/_cffi_backend/cbuffer.py
+++ b/pypy/module/_cffi_backend/cbuffer.py
@@ -3,6 +3,7 @@
 from pypy.interpreter.gateway import unwrap_spec, interp2app
 from pypy.interpreter.typedef import TypeDef, make_weakref_descr
 from pypy.module._cffi_backend import cdataobj, ctypeptr, ctypearray
+from pypy.module._cffi_backend import ctypestruct
 
 from rpython.rlib.buffer import Buffer
 from rpython.rtyper.annlowlevel import llstr
@@ -89,7 +90,12 @@
     ctype = w_cdata.ctype
     if isinstance(ctype, ctypeptr.W_CTypePointer):
         if size < 0:
-            size = ctype.ctitem.size
+            structobj = w_cdata.get_structobj()
+            if (structobj is not None and
+                isinstance(structobj.ctype, ctypestruct.W_CTypeStructOrUnion)):
+                size = structobj._sizeof()
+            if size < 0:
+                size = ctype.ctitem.size
     elif isinstance(ctype, ctypearray.W_CTypeArray):
         if size < 0:
             size = w_cdata._sizeof()
diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -329,7 +329,7 @@
     def getattr(self, w_attr):
         cfield = self.getcfield(w_attr)
         with self as ptr:
-            w_res = cfield.read(ptr)
+            w_res = cfield.read(ptr, self)
         return w_res
 
     def setattr(self, w_attr, w_value):
@@ -432,6 +432,9 @@
         lst = ct.cdata_dir()
         return space.newlist([space.wrap(s) for s in lst])
 
+    def get_structobj(self):
+        return None
+
 
 class W_CDataMem(W_CData):
     """This is used only by the results of cffi.cast('int', x)
@@ -453,28 +456,36 @@
     by newp().  They create and free their own memory according to an
     allocator."""
 
-    # the 'length' is either >= 0 for arrays, or -1 for pointers.
-    _attrs_ = ['length']
-    _immutable_fields_ = ['length']
+    # the 'allocated_length' is >= 0 for arrays; for var-sized
+    # structures it is the total size in bytes; otherwise it is -1.
+    _attrs_ = ['allocated_length']
+    _immutable_fields_ = ['allocated_length']
 
     def __init__(self, space, cdata, ctype, length=-1):
         W_CData.__init__(self, space, cdata, ctype)
-        self.length = length
+        self.allocated_length = length
 
     def _repr_extra(self):
         return self._repr_extra_owning()
 
     def _sizeof(self):
         ctype = self.ctype
-        if self.length >= 0:
+        if self.allocated_length >= 0:
             from pypy.module._cffi_backend import ctypearray
-            assert isinstance(ctype, ctypearray.W_CTypeArray)
-            return self.length * ctype.ctitem.size
+            if isinstance(ctype, ctypearray.W_CTypeArray):
+                return self.allocated_length * ctype.ctitem.size
+            else:
+                return self.allocated_length    # var-sized struct size
         else:
             return ctype.size
 
     def get_array_length(self):
-        return self.length
+        from pypy.module._cffi_backend import ctypearray
+        assert isinstance(self.ctype, ctypearray.W_CTypeArray)
+        return self.allocated_length
+
+    def get_structobj(self):
+        return self
 
 
 class W_CDataNewStd(W_CDataNewOwning):
@@ -508,12 +519,19 @@
         self.structobj = structobj
 
     def _repr_extra(self):
-        return self._repr_extra_owning()
+        return self.structobj._repr_extra_owning()
 
     def _do_getitem(self, ctype, i):
         assert i == 0
         return self.structobj
 
+    def get_structobj(self):
+        structobj = self.structobj
+        if isinstance(structobj, W_CDataNewOwning):
+            return structobj
+        else:
+            return None
+
 
 class W_CDataSliced(W_CData):
     """Subclass with an explicit length, for slices."""
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -213,13 +213,16 @@
             # a W_CDataPtrToStruct object which has a strong reference
             # to a W_CDataNewOwning that really contains the structure.
             #
-            if not space.is_w(w_init, space.w_None):
-                ctitem.force_lazy_struct()
-                if ctitem._with_var_array:
+            varsize_length = -1
+            ctitem.force_lazy_struct()
+            if ctitem._with_var_array:
+                if not space.is_w(w_init, space.w_None):
                     datasize = ctitem.convert_struct_from_object(
                         lltype.nullptr(rffi.CCHARP.TO), w_init, datasize)
+                varsize_length = datasize
             #
-            cdatastruct = allocator.allocate(space, datasize, ctitem)
+            cdatastruct = allocator.allocate(space, datasize, ctitem,
+                                             length=varsize_length)
             ptr = cdatastruct.unsafe_escaping_ptr()
             cdata = cdataobj.W_CDataPtrToStructOrUnion(space, ptr,
                                                        self, cdatastruct)
diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -210,7 +210,7 @@
         return W_CField(self.ctype, offset + self.offset,
                         self.bitshift, self.bitsize, self.flags | fflags)
 
-    def read(self, cdata):
+    def read(self, cdata, w_cdata):
         cdata = rffi.ptradd(cdata, self.offset)
         if self.bitshift == self.BS_REGULAR:
             return self.ctype.convert_to_object(cdata)
@@ -218,6 +218,14 @@
             from pypy.module._cffi_backend import ctypearray
             ctype = self.ctype
             assert isinstance(ctype, ctypearray.W_CTypeArray)
+            structobj = w_cdata.get_structobj()
+            if structobj is not None:
+                # variable-length array
+                size = structobj.allocated_length - self.offset
+                if size >= 0:
+                    arraylen = size // ctype.ctitem.size
+                    return cdataobj.W_CDataSliced(ctype.space, cdata, ctype,
+                                                  arraylen)
             return cdataobj.W_CData(ctype.space, cdata, ctype.ctptr)
         else:
             return self.convert_bitfield_to_object(cdata)
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -353,7 +353,7 @@
         if fbitsize < 0:
             # not a bitfield: common case
 
-            if isinstance(ftype, ctypearray.W_CTypeArray) and ftype.length==0:
+            if isinstance(ftype, ctypearray.W_CTypeArray) and ftype.length<=0:
                 bs_flag = ctypestruct.W_CField.BS_EMPTY_ARRAY
             else:
                 bs_flag = ctypestruct.W_CField.BS_REGULAR
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -3161,17 +3161,19 @@
     assert d[1][0] == 'y'
     assert d[1][1].type is BArray
     assert d[1][1].offset == size_of_int()
-    assert d[1][1].bitshift == -1
+    assert d[1][1].bitshift == -2
     assert d[1][1].bitsize == -1
     #
     p = newp(new_pointer_type(BStruct))
     p.x = 42
     assert p.x == 42
-    assert typeof(p.y) is BIntP
+    assert typeof(p.y) is BArray
+    assert len(p.y) == 0
     assert p.y == cast(BIntP, p) + 1
     #
     p = newp(new_pointer_type(BStruct), [100])
     assert p.x == 100
+    assert len(p.y) == 0
     #
     # Tests for
     #    ffi.new("struct_with_var_array *", [field.., [the_array_items..]])
@@ -3186,6 +3188,10 @@
             p.y[0] = 200
             assert p.y[2] == 0
             p.y[2] = 400
+        assert len(p.y) == 3
+        assert len(p[0].y) == 3
+        assert len(buffer(p)) == sizeof(BInt) * 4
+        assert sizeof(p[0]) == sizeof(BInt) * 4
         plist.append(p)
     for i in range(20):
         p = plist[i]
@@ -3193,13 +3199,31 @@
         assert p.y[0] == 200
         assert p.y[1] == i
         assert p.y[2] == 400
-        assert list(p.y[0:3]) == [200, i, 400]
+        assert list(p.y) == [200, i, 400]
     #
     # the following assignment works, as it normally would, for any array field
-    p.y = [500, 600]
-    assert list(p.y[0:3]) == [500, 600, 400]
+    p.y = [501, 601]
+    assert list(p.y) == [501, 601, 400]
+    p[0].y = [500, 600]
+    assert list(p[0].y) == [500, 600, 400]
+    assert repr(p) == "<cdata 'foo *' owning %d bytes>" % (
+        sizeof(BStruct) + 3 * sizeof(BInt),)
+    assert repr(p[0]) == "<cdata 'foo' owning %d bytes>" % (
+        sizeof(BStruct) + 3 * sizeof(BInt),)
+    assert sizeof(p[0]) == sizeof(BStruct) + 3 * sizeof(BInt)
+    #
+    # from a non-owning pointer, we can't get the length
+    q = cast(new_pointer_type(BStruct), p)
+    assert q.y[0] == 500
+    assert q[0].y[0] == 500
+    py.test.raises(TypeError, len, q.y)
+    py.test.raises(TypeError, len, q[0].y)
+    assert typeof(q.y) is BIntP
+    assert typeof(q[0].y) is BIntP
+    assert sizeof(q[0]) == sizeof(BStruct)
     #
     # error cases
+    py.test.raises(IndexError, "p.y[4]")
     py.test.raises(TypeError, "p.y = cast(BIntP, 0)")
     py.test.raises(TypeError, "p.y = 15")
     py.test.raises(TypeError, "p.y = None")
@@ -3264,6 +3288,33 @@
         assert p.x[5] == 60
         assert p.x[6] == 70
 
+def test_struct_array_not_aligned():
+    # struct a { int x; char y; char z[]; };
+    # ends up of size 8, but 'z' is at offset 5
+    BChar = new_primitive_type("char")
+    BInt = new_primitive_type("int")
+    BCharP = new_pointer_type(BChar)
+    BArray = new_array_type(BCharP, None)
+    BStruct = new_struct_type("foo")
+    complete_struct_or_union(BStruct, [('x', BInt),
+                                       ('y', BChar),
+                                       ('z', BArray)])
+    assert sizeof(BStruct) == 2 * size_of_int()
+    def offsetof(BType, fieldname):
+        return typeoffsetof(BType, fieldname)[1]
+    base = offsetof(BStruct, 'z')
+    assert base == size_of_int() + 1
+    #
+    p = newp(new_pointer_type(BStruct), {'z': 3})
+    assert sizeof(p[0]) == base + 3
+    q = newp(new_pointer_type(BStruct), {'z': size_of_int()})
+    assert sizeof(q) == size_of_ptr()
+    assert sizeof(q[0]) == base + size_of_int()
+    assert len(p.z) == 3
+    assert len(p[0].z) == 3
+    assert len(q.z) == size_of_int()
+    assert len(q[0].z) == size_of_int()
+
 def test_ass_slice():
     BChar = new_primitive_type("char")
     BArray = new_array_type(new_pointer_type(BChar), None)
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -408,11 +408,14 @@
             'test_misdeclared_field_1',
             "struct foo_s { int a[6]; };")
         assert ffi.sizeof("struct foo_s") == 24  # found by the actual C code
-        p = ffi.new("struct foo_s *")
-        # lazily build the fields and boom:
-        e = raises(ffi.error, getattr, p, "a")
-        assert str(e.value).startswith("struct foo_s: wrong size for field 'a' "
-                                       "(cdef says 20, but C compiler says 24)")
+        try:
+            # lazily build the fields and boom:
+            p = ffi.new("struct foo_s *")
+            p.a
+            assert False, "should have raised"
+        except ffi.error as e:
+            assert str(e).startswith("struct foo_s: wrong size for field 'a' "
+                                     "(cdef says 20, but C compiler says 24)")
 
     def test_open_array_in_struct(self):
         ffi, lib = self.prepare(
@@ -420,8 +423,10 @@
             'test_open_array_in_struct',
             "struct foo_s { int b; int a[]; };")
         assert ffi.sizeof("struct foo_s") == 4
-        p = ffi.new("struct foo_s *", [5, [10, 20, 30]])
+        p = ffi.new("struct foo_s *", [5, [10, 20, 30, 40]])
         assert p.a[2] == 30
+        assert ffi.sizeof(p) == ffi.sizeof("void *")
+        assert ffi.sizeof(p[0]) == 5 * ffi.sizeof("int")
 
     def test_math_sin_type(self):
         ffi, lib = self.prepare(
@@ -954,6 +959,7 @@
             "struct foo_s { int x; int a[5][8]; int y; };")
         assert ffi.sizeof('struct foo_s') == 42 * ffi.sizeof('int')
         s = ffi.new("struct foo_s *")
+        assert ffi.typeof(s.a) == ffi.typeof("int[5][8]")
         assert ffi.sizeof(s.a) == 40 * ffi.sizeof('int')
         assert s.a[4][7] == 0
         raises(IndexError, 's.a[4][8]')
@@ -961,6 +967,18 @@
         assert ffi.typeof(s.a) == ffi.typeof("int[5][8]")
         assert ffi.typeof(s.a[0]) == ffi.typeof("int[8]")
 
+    def test_struct_array_guess_length_3(self):
+        ffi, lib = self.prepare(
+            "struct foo_s { int a[][...]; };",
+            'test_struct_array_guess_length_3',
+            "struct foo_s { int x; int a[5][7]; int y; };")
+        assert ffi.sizeof('struct foo_s') == 37 * ffi.sizeof('int')
+        s = ffi.new("struct foo_s *")
+        assert ffi.typeof(s.a) == ffi.typeof("int[][7]")
+        assert s.a[4][6] == 0
+        raises(IndexError, 's.a[4][7]')
+        assert ffi.typeof(s.a[0]) == ffi.typeof("int[7]")
+
     def test_global_var_array_2(self):
         ffi, lib = self.prepare(
             "int a[...][...];",
diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py
--- a/pypy/module/_multiprocessing/interp_semaphore.py
+++ b/pypy/module/_multiprocessing/interp_semaphore.py
@@ -35,6 +35,9 @@
         rwin32.BOOL,
         save_err=rffi.RFFI_SAVE_LASTERROR)
 
+    def sem_unlink(name):
+        pass
+
 else:
     from rpython.rlib import rposix
 
@@ -325,12 +328,7 @@
 else:
     def create_semaphore(space, name, val, max):
         sem = sem_open(name, os.O_CREAT | os.O_EXCL, 0600, val)
-        try:
-            sem_unlink(name)
-        except OSError:
-            pass
-        else:
-            rgc.add_memory_pressure(SEM_T_SIZE)
+        rgc.add_memory_pressure(SEM_T_SIZE)
         return sem
 
     def delete_semaphore(handle):
diff --git a/pypy/module/_multiprocessing/test/test_semaphore.py b/pypy/module/_multiprocessing/test/test_semaphore.py
--- a/pypy/module/_multiprocessing/test/test_semaphore.py
+++ b/pypy/module/_multiprocessing/test/test_semaphore.py
@@ -22,8 +22,10 @@
     @py.test.mark.skipif("sys.platform == 'win32'")
     def test_sem_unlink(self):
         from _multiprocessing import sem_unlink
-        try: sem_unlink("non-existent")
-        except OSError: pass
+        try:
+            sem_unlink("non-existent")
+        except OSError:
+            pass
 
     def test_semaphore(self):
         from _multiprocessing import SemLock
@@ -35,7 +37,7 @@
         maxvalue = 1
         # the following line gets OSError: [Errno 38] Function not implemented
         # if /dev/shm is not mounted on Linux
-        sem = SemLock(kind, value, maxvalue, "1", False)
+        sem = SemLock(kind, value, maxvalue, "1", unlink=True)
         assert sem.kind == kind
         assert sem.maxvalue == maxvalue
         assert isinstance(sem.handle, int)
@@ -68,7 +70,7 @@
         maxvalue = 1
         # the following line gets OSError: [Errno 38] Function not implemented
         # if /dev/shm is not mounted on Linux
-        sem = SemLock(kind, value, maxvalue, "2", False)
+        sem = SemLock(kind, value, maxvalue, "2", unlink=True)
 
         sem.acquire()
         sem.release()
@@ -88,7 +90,7 @@
         kind = self.SEMAPHORE
         value = 1
         maxvalue = 1
-        sem = SemLock(kind, value, maxvalue, "3", False)
+        sem = SemLock(kind, value, maxvalue, "3", unlink=True)
 
         res = sem.acquire()
         assert res == True
@@ -100,7 +102,7 @@
         kind = self.SEMAPHORE
         value = 1
         maxvalue = 1
-        sem = SemLock(kind, value, maxvalue, "4", False)
+        sem = SemLock(kind, value, maxvalue, "4", unlink=True)
 
         sem2 = SemLock._rebuild(sem.handle, kind, value, "10")
         assert sem.handle == sem2.handle
@@ -110,8 +112,13 @@
         kind = self.SEMAPHORE
         value = 1
         maxvalue = 1
-        sem = SemLock(kind, value, maxvalue, "5", False)
+        sem = SemLock(kind, value, maxvalue, "5", unlink=True)
 
         with sem:
             assert sem._count() == 1
         assert sem._count() == 0
+
+    def test_unlink(self):
+        from _multiprocessing import SemLock
+        sem = SemLock(self.SEMAPHORE, 1, 1, '/mp-123', unlink=True)
+        assert sem._count() == 0
diff --git a/pypy/module/cpyext/test/test_ztranslation.py b/pypy/module/cpyext/test/test_ztranslation.py
deleted file mode 100644
--- a/pypy/module/cpyext/test/test_ztranslation.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from pypy.objspace.fake.checkmodule import checkmodule
-from pypy.module.cpyext import pyobject
-
-def test_cpyext_translates(monkeypatch):
-    def from_ref(space, ref):
-        # XXX: avoid 'assert isinstance(w_type, W_TypeObject)' from the
-        # original from_ref, just return w_some_obj
-        return space.w_object
-    monkeypatch.setattr(pyobject, 'from_ref', from_ref)
-    checkmodule('cpyext', '_rawffi', translate_startup=False)
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -273,7 +273,7 @@
         if len(slot_names) == 1:
             if not getattr(pto, slot_names[0]):
                 setattr(pto, slot_names[0], slot_func_helper)
-        elif (w_type.getname(space) in ('list', 'tuple') and
+        elif ((w_type is space.w_list or w_type is space.w_tuple) and
               slot_names[0] == 'c_tp_as_number'):
             # XXX hack - hwo can we generalize this? The problem is method
             # names like __mul__ map to more than one slot, and we have no
diff --git a/pypy/module/math/__init__.py b/pypy/module/math/__init__.py
--- a/pypy/module/math/__init__.py
+++ b/pypy/module/math/__init__.py
@@ -11,6 +11,8 @@
     interpleveldefs = {
        'e'              : 'interp_math.get(space).w_e',
        'pi'             : 'interp_math.get(space).w_pi',
+       'inf'            : 'interp_math.get(space).w_inf',
+       'nan'            : 'interp_math.get(space).w_nan',
        'pow'            : 'interp_math.pow',
        'cosh'           : 'interp_math.cosh',
        'copysign'       : 'interp_math.copysign',
diff --git a/pypy/module/math/app_math.py b/pypy/module/math/app_math.py
--- a/pypy/module/math/app_math.py
+++ b/pypy/module/math/app_math.py
@@ -1,4 +1,5 @@
 import sys
+from _operator import index
 
 def factorial(x):
     """factorial(x) -> Integral
@@ -45,8 +46,8 @@
 
 def gcd(x, y):
     """greatest common divisor of x and y"""
-    x = abs(x)
-    y = abs(y)
+    x = abs(index(x))
+    y = abs(index(y))
     while x > 0:
         x, y = y % x, x
     return y
diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py
--- a/pypy/module/math/interp_math.py
+++ b/pypy/module/math/interp_math.py
@@ -10,6 +10,8 @@
     def __init__(self, space):
         self.w_e = space.wrap(math.e)
         self.w_pi = space.wrap(math.pi)
+        self.w_inf = space.wrap(rfloat.INFINITY)
+        self.w_nan = space.wrap(rfloat.NAN)
 def get(space):
     return space.fromcache(State)
 
diff --git a/pypy/module/math/test/test_math.py b/pypy/module/math/test/test_math.py
--- a/pypy/module/math/test/test_math.py
+++ b/pypy/module/math/test/test_math.py
@@ -369,3 +369,10 @@
         assert math.gcd(-4, -10) == 2
         assert math.gcd(0, -10) == 10
         assert math.gcd(0, 0) == 0
+        raises(TypeError, math.gcd, 0, 0.0)
+
+    def test_inf_nan(self):
+        import math
+        assert math.isinf(math.inf)
+        assert math.inf > -math.inf
+        assert math.isnan(math.nan)
diff --git a/pypy/module/micronumpy/test/test_ztranslation.py b/pypy/module/micronumpy/test/test_ztranslation.py
deleted file mode 100644
--- a/pypy/module/micronumpy/test/test_ztranslation.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from pypy.objspace.fake.checkmodule import checkmodule
-
-def test_numpy_translates():
-    checkmodule('micronumpy')
diff --git a/pypy/module/operator/app_operator.py b/pypy/module/operator/app_operator.py
--- a/pypy/module/operator/app_operator.py
+++ b/pypy/module/operator/app_operator.py
@@ -56,6 +56,17 @@
             for attrs in self._multi_attrs
         ])
 
+    def __repr__(self):
+        try:
+            a = repr(self._simple_attr)
+        except AttributeError:
+            try:
+                a = repr('.'.join(self._single_attr))
+            except AttributeError:
+                lst = self._multi_attrs
+                a = ', '.join([repr('.'.join(a1)) for a1 in lst])
+        return 'operator.attrgetter(%s)' % (a,)
+
 
 class itemgetter(object):
     def __init__(self, item, *items):
@@ -71,12 +82,29 @@
         else:
             return tuple([obj[i] for i in self._idx])
 
+    def __repr__(self):
+        if self._single:
+            a = repr(self._idx)
+        else:
+            a = ', '.join([repr(i) for i in self._idx])
+        return 'operator.itemgetter(%s)' % (a,)
+
 
 class methodcaller(object):
     def __init__(self, method_name, *args, **kwargs):
+        if not isinstance(method_name, str):
+            raise TypeError("method name must be a string")
         self._method_name = method_name
         self._args = args
         self._kwargs = kwargs
 
     def __call__(self, obj):
         return getattr(obj, self._method_name)(*self._args, **self._kwargs)
+
+    def __repr__(self):
+        args = [repr(self._method_name)]
+        for a in self._args:
+            args.append(repr(a))
+        for key, value in self._kwargs.items():
+            args.append('%s=%r' % (key, value))
+        return 'operator.methodcaller(%s)' % (', '.join(args),)
diff --git a/pypy/module/operator/interp_operator.py b/pypy/module/operator/interp_operator.py
--- a/pypy/module/operator/interp_operator.py
+++ b/pypy/module/operator/interp_operator.py
@@ -210,7 +210,7 @@
     return space.inplace_add(w_obj1, w_obj2)
 
 @unwrap_spec(default=int)
-def length_hint(space, w_iterable, default):
+def length_hint(space, w_iterable, default=0):
     """Return an estimate of the number of items in obj.
     This is useful for presizing containers when building from an iterable.
     If the object supports len(), the result will be exact.
diff --git a/pypy/module/operator/test/test_operator.py b/pypy/module/operator/test/test_operator.py
--- a/pypy/module/operator/test/test_operator.py
+++ b/pypy/module/operator/test/test_operator.py
@@ -182,6 +182,11 @@
         assert methodcaller("method", 4, 5)(x) == (4, 5)
         assert methodcaller("method", 4, arg2=42)(x) == (4, 42)
 
+    def test_methodcaller_not_string(self):
+        import _operator as operator
+        e = raises(TypeError, operator.methodcaller, 42)
+        assert str(e.value) == "method name must be a string"
+
     def test_index(self):
         import _operator as operator
         assert operator.index(42) == 42
@@ -322,3 +327,27 @@
         assert operator._compare_digest(u'asd', u'asd')
         assert not operator._compare_digest(u'asd', u'qwe')
         raises(TypeError, operator._compare_digest, u'asd', b'qwe')
+
+    def test_length_hint(self):
+        import _operator as operator
+        assert operator.length_hint([1, 2]) == 2
+
+    def test_repr_attrgetter(self):
+        import _operator as operator
+        assert repr(operator.attrgetter("foo")) == "operator.attrgetter('foo')"
+        assert repr(operator.attrgetter("foo", 'bar')) == (
+            "operator.attrgetter('foo', 'bar')")
+        assert repr(operator.attrgetter("foo.bar")) == (
+            "operator.attrgetter('foo.bar')")
+        assert repr(operator.attrgetter("foo", 'bar.baz')) == (
+            "operator.attrgetter('foo', 'bar.baz')")
+
+    def test_repr_itemgetter(self):
+        import _operator as operator
+        assert repr(operator.itemgetter(2)) == "operator.itemgetter(2)"
+        assert repr(operator.itemgetter(2, 3)) == "operator.itemgetter(2, 3)"
+
+    def test_repr_methodcaller(self):
+        import _operator as operator
+        assert repr(operator.methodcaller("foo", "bar", baz=42)) == (
+            "operator.methodcaller('foo', 'bar', baz=42)")
diff --git a/pypy/module/struct/interp_struct.py b/pypy/module/struct/interp_struct.py
--- a/pypy/module/struct/interp_struct.py
+++ b/pypy/module/struct/interp_struct.py
@@ -108,6 +108,27 @@
     return _unpack(space, format, buf)
 
 
+class W_UnpackIter(W_Root):
+    def __init__(self, w_struct, buf):
+        self.w_struct = w_struct
+        self.buf = buf
+        self.index = 0
+
+    def descr_iter(self, space):
+        return self
+
+    def descr_next(self, space):
+        if self.w_struct is None:
+            raise OperationError(space.w_StopIteration, space.w_None)
+        if self.index >= self.buf.getlength():
+            raise OperationError(space.w_StopIteration, space.w_None)
+        size = self.w_struct.size
+        buf = SubBuffer(self.buf, self.index, size)
+        w_res = _unpack(space, self.w_struct.format, buf)
+        self.index += size
+        return w_res
+
+
 class W_Struct(W_Root):
     _immutable_fields_ = ["format", "size"]
 
@@ -135,6 +156,10 @@
     def descr_unpack_from(self, space, w_buffer, offset=0):
         return unpack_from(space, jit.promote_string(self.format), w_buffer, offset)
 
+    def descr_iter_unpack(self, space, w_buffer):
+        buf = space.buffer_w(w_buffer, space.BUF_SIMPLE)
+        return W_UnpackIter(self, buf)
+
 W_Struct.typedef = TypeDef("Struct",
     __new__=interp2app(W_Struct.descr__new__.im_func),
     format=interp_attrproperty_bytes("format", cls=W_Struct),
@@ -144,6 +169,21 @@
     unpack=interp2app(W_Struct.descr_unpack),
     pack_into=interp2app(W_Struct.descr_pack_into),
     unpack_from=interp2app(W_Struct.descr_unpack_from),
+    iter_unpack=interp2app(W_Struct.descr_iter_unpack),
+)
+
+ at unwrap_spec(w_struct=W_Struct)
+def new_unpackiter(space, w_subtype, w_struct, w_buffer):
+    buf = space.buffer_w(w_buffer, space.BUF_SIMPLE)
+    w_res = space.allocate_instance(W_UnpackIter, w_subtype)
+    w_res.__init__(w_struct, buf)
+    return w_res
+
+W_UnpackIter.typedef = TypeDef("unpack_iterator",
+    __new__=interp2app(new_unpackiter),
+    __iter__=interp2app(W_UnpackIter.descr_iter),
+    __next__=interp2app(W_UnpackIter.descr_next),
+    #__length_hint__=
 )
 
 def clearcache(space):
diff --git a/pypy/module/struct/test/test_struct.py b/pypy/module/struct/test/test_struct.py
--- a/pypy/module/struct/test/test_struct.py
+++ b/pypy/module/struct/test/test_struct.py
@@ -394,6 +394,13 @@
         exc = raises(self.struct.error, self.struct.unpack_from, "ii", memoryview(b''))
         assert str(exc.value) == "unpack_from requires a buffer of at least 8 bytes"
 
+    def test_iter_unpack(self):
+        import array
+        b = array.array('b', b'\0' * 16)
+        s = self.struct.Struct('ii')
+        it = s.iter_unpack(b)
+        assert list(it) == [(0, 0), (0, 0)]
+
     def test___float__(self):
         class MyFloat(object):
             def __init__(self, x):
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
@@ -1356,15 +1356,15 @@
         assert ffi.getctype("e1*") == 'e1 *'
 
     def test_opaque_enum(self):
+        import warnings
         ffi = FFI(backend=self.Backend())
         ffi.cdef("enum foo;")
-        from cffi import __version_info__
-        if __version_info__ < (1, 8):
-            py.test.skip("re-enable me in version 1.8")
-        e = py.test.raises(CDefError, ffi.cast, "enum foo", -1)
-        assert str(e.value) == (
-            "'enum foo' has no values explicitly defined: refusing to guess "
-            "which integer type it is meant to be (unsigned/signed, int/long)")
+        with warnings.catch_warnings(record=True) as log:
+            n = ffi.cast("enum foo", -1)
+            assert int(n) == 0xffffffff
+        assert str(log[0].message) == (
+            "'enum foo' has no values explicitly defined; "
+            "guessing that it is equivalent to 'unsigned int'")
 
     def test_new_ctype(self):
         ffi = FFI(backend=self.Backend())
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py
@@ -283,10 +283,20 @@
         ffi.cdef("struct foo_s { int x; int a[]; };")
         p = ffi.new("struct foo_s *", [100, [200, 300, 400]])
         assert p.x == 100
-        assert ffi.typeof(p.a) is ffi.typeof("int *")   # no length available
+        assert ffi.typeof(p.a) is ffi.typeof("int[]")
+        assert len(p.a) == 3                            # length recorded
         assert p.a[0] == 200
         assert p.a[1] == 300
         assert p.a[2] == 400
+        assert list(p.a) == [200, 300, 400]
+        q = ffi.cast("struct foo_s *", p)
+        assert q.x == 100
+        assert ffi.typeof(q.a) is ffi.typeof("int *")   # no length recorded
+        py.test.raises(TypeError, len, q.a)
+        assert q.a[0] == 200
+        assert q.a[1] == 300
+        assert q.a[2] == 400
+        py.test.raises(TypeError, list, q.a)
 
     @pytest.mark.skipif("sys.platform != 'win32'")
     def test_getwinerror(self):
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py
@@ -562,7 +562,8 @@
                      "int bar(struct foo_s *f) { return f->a[14]; }\n")
     assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *")
-    assert ffi.typeof(s.a) is ffi.typeof('int *')   # because no length
+    assert ffi.typeof(s.a) is ffi.typeof('int[]')   # implicit max length
+    assert len(s.a) == 18  # max length, computed from the size and start offset
     s.a[14] = 4242
     assert lib.bar(s) == 4242
     # with no declared length, out-of-bound accesses are not detected
@@ -592,10 +593,15 @@
     ffi.verify("struct foo_s { int x; int a[]; };")
     assert ffi.sizeof('struct foo_s') == 1 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *", [424242, 4])
-    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')   # the same in C
+    assert ffi.sizeof(ffi.typeof(s[0])) == 1 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
+    # ^^^ explanation: if you write in C: "char x[5];", then
+    # "sizeof(x)" will evaluate to 5.  The behavior above is
+    # a generalization of that to "struct foo_s[len(a)=5] x;"
+    # if you could do that in C.
     assert s.a[3] == 0
     s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
-    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
     assert s.a[3] == -10
     s = ffi.new("struct foo_s *")
     assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
@@ -610,10 +616,10 @@
     ffi.verify("struct foo_s { int x, y; int a[]; };")
     assert ffi.sizeof('struct foo_s') == 2 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *", [424242, 4])
-    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
     assert s.a[3] == 0
     s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
-    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
     assert s.a[3] == -10
     s = ffi.new("struct foo_s *")
     assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_new_ffi_1.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_new_ffi_1.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_new_ffi_1.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_new_ffi_1.py
@@ -1634,10 +1634,19 @@
         # struct array_no_length { int x; int a[]; };
         p = ffi.new("struct array_no_length *", [100, [200, 300, 400]])
         assert p.x == 100
-        assert ffi.typeof(p.a) is ffi.typeof("int *")   # no length available
+        assert ffi.typeof(p.a) is ffi.typeof("int[]")   # length available
         assert p.a[0] == 200
         assert p.a[1] == 300
         assert p.a[2] == 400
+        assert len(p.a) == 3
+        assert list(p.a) == [200, 300, 400]
+        q = ffi.cast("struct array_no_length *", p)
+        assert ffi.typeof(q.a) is ffi.typeof("int *")   # no length available
+        assert q.a[0] == 200
+        assert q.a[1] == 300
+        assert q.a[2] == 400
+        py.test.raises(TypeError, len, q.a)
+        py.test.raises(TypeError, list, q.a)
 
     def test_from_buffer(self):
         import array
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
@@ -400,11 +400,14 @@
         pass    # ok, fail during compilation already (e.g. C++)
     else:
         assert ffi.sizeof("struct foo_s") == 24  # found by the actual C code
-        p = ffi.new("struct foo_s *")
-        # lazily build the fields and boom:
-        e = py.test.raises(ffi.error, "p.a")
-        assert str(e.value).startswith("struct foo_s: wrong size for field 'a' "
-                                       "(cdef says 20, but C compiler says 24)")
+        try:
+            # lazily build the fields and boom:
+            p = ffi.new("struct foo_s *")
+            p.a
+            assert False, "should have raised"
+        except ffi.error as e:
+            assert str(e).startswith("struct foo_s: wrong size for field 'a' "
+                                     "(cdef says 20, but C compiler says 24)")
 
 def test_open_array_in_struct():
     ffi = FFI()
@@ -412,8 +415,10 @@
     verify(ffi, 'test_open_array_in_struct',
            "struct foo_s { int b; int a[]; };")
     assert ffi.sizeof("struct foo_s") == 4
-    p = ffi.new("struct foo_s *", [5, [10, 20, 30]])
+    p = ffi.new("struct foo_s *", [5, [10, 20, 30, 40]])
     assert p.a[2] == 30
+    assert ffi.sizeof(p) == ffi.sizeof("void *")
+    assert ffi.sizeof(p[0]) == 5 * ffi.sizeof("int")
 
 def test_math_sin_type():
     ffi = FFI()
@@ -999,6 +1004,7 @@
                  "struct foo_s { int x; int a[5][8]; int y; };")
     assert ffi.sizeof('struct foo_s') == 42 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *")
+    assert ffi.typeof(s.a) == ffi.typeof("int[5][8]")
     assert ffi.sizeof(s.a) == 40 * ffi.sizeof('int')
     assert s.a[4][7] == 0
     py.test.raises(IndexError, 's.a[4][8]')
@@ -1013,7 +1019,7 @@
                  "struct foo_s { int x; int a[5][7]; int y; };")
     assert ffi.sizeof('struct foo_s') == 37 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *")
-    assert ffi.typeof(s.a) == ffi.typeof("int(*)[7]")
+    assert ffi.typeof(s.a) == ffi.typeof("int[][7]")
     assert s.a[4][6] == 0
     py.test.raises(IndexError, 's.a[4][7]')
     assert ffi.typeof(s.a[0]) == ffi.typeof("int[7]")
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
@@ -547,7 +547,8 @@
                      "int bar(struct foo_s *f) { return f->a[14]; }\n")
     assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *")
-    assert ffi.typeof(s.a) is ffi.typeof('int *')   # because no length
+    assert ffi.typeof(s.a) is ffi.typeof('int[]')   # implicit max length
+    assert len(s.a) == 18  # max length, computed from the size and start offset
     s.a[14] = 4242
     assert lib.bar(s) == 4242
     # with no declared length, out-of-bound accesses are not detected
@@ -577,10 +578,15 @@
     ffi.verify("struct foo_s { int x; int a[]; };")
     assert ffi.sizeof('struct foo_s') == 1 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *", [424242, 4])
-    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')   # the same in C
+    assert ffi.sizeof(ffi.typeof(s[0])) == 1 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
+    # ^^^ explanation: if you write in C: "char x[5];", then
+    # "sizeof(x)" will evaluate to 5.  The behavior above is
+    # a generalization of that to "struct foo_s[len(a)=5] x;"
+    # if you could do that in C.
     assert s.a[3] == 0
     s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
-    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
     assert s.a[3] == -10
     s = ffi.new("struct foo_s *")
     assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
@@ -595,10 +601,10 @@
     ffi.verify("struct foo_s { int x, y; int a[]; };")
     assert ffi.sizeof('struct foo_s') == 2 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *", [424242, 4])
-    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
     assert s.a[3] == 0
     s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
-    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
     assert s.a[3] == -10
     s = ffi.new("struct foo_s *")
     assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -291,6 +291,9 @@
     def type(self, w_obj):
         return w_some_type()
 
+    def lookup_in_type_where(self, w_type, key):
+        return w_some_obj(), w_some_obj()
+
     def issubtype_w(self, w_sub, w_type):
         is_root(w_sub)
         is_root(w_type)
diff --git a/pypy/objspace/std/complexobject.py b/pypy/objspace/std/complexobject.py
--- a/pypy/objspace/std/complexobject.py
+++ b/pypy/objspace/std/complexobject.py
@@ -132,12 +132,11 @@
     return format_float(x, 'g', DTSF_STR_PRECISION)
 
 
-def unpackcomplex(space, w_complex, strict_typing=True):
+def unpackcomplex(space, w_complex):
     """
-    convert w_complex into a complex and return the unwrapped (real, imag)
-    tuple. If strict_typing==True, we also typecheck the value returned by
-    __complex__ to actually be a complex (and not e.g. a float).
-    See test___complex___returning_non_complex.
+    Convert w_complex into a complex and return the unwrapped (real, imag)
+    tuple. Also, typecheck the value returned by __complex__ to actually be a
+    complex (and not e.g. a float).
     """
     if type(w_complex) is W_ComplexObject:
         return (w_complex.realval, w_complex.imagval)
@@ -149,12 +148,9 @@
         w_z = space.get_and_call_function(w_method, w_complex)
     #
     if w_z is not None:
-        # __complex__() must return a complex or (float,int,long) object
+        # __complex__() must return a complex
         # (XXX should not use isinstance here)
-        if not strict_typing and (space.isinstance_w(w_z, space.w_int) or
-                                  space.isinstance_w(w_z, space.w_float)):
-            return (space.float_w(w_z), 0.0)
-        elif isinstance(w_z, W_ComplexObject):
+        if isinstance(w_z, W_ComplexObject):
             return (w_z.realval, w_z.imagval)
         raise oefmt(space.w_TypeError,
                     "__complex__() must return a complex number")
@@ -302,14 +298,12 @@
 
         else:
             # non-string arguments
-            realval, imagval = unpackcomplex(space, w_real,
-                                             strict_typing=False)
+            realval, imagval = unpackcomplex(space, w_real)
 
             # now take w_imag into account
             if not noarg2:
                 # complex(x, y) == x+y*j, even if 'y' is already a complex.
-                realval2, imagval2 = unpackcomplex(space, w_imag,
-                                                   strict_typing=False)
+                realval2, imagval2 = unpackcomplex(space, w_imag)
 
                 # try to preserve the signs of zeroes of realval and realval2
                 if imagval2 != 0.0:
diff --git a/pypy/objspace/std/stringmethods.py b/pypy/objspace/std/stringmethods.py
--- a/pypy/objspace/std/stringmethods.py
+++ b/pypy/objspace/std/stringmethods.py
@@ -612,14 +612,8 @@
 
     def _startswith(self, space, value, w_prefix, start, end):
         prefix = self._op_val(space, w_prefix)
-        if start > len(value):
-            return self._starts_ends_overflow(prefix)
         return startswith(value, prefix, start, end)
 
-    def _starts_ends_overflow(self, prefix):
-        return False     # bug-to-bug compat: this is for strings and
-                         # bytearrays, but overridden for unicodes
-
     def descr_endswith(self, space, w_suffix, w_start=None, w_end=None):
         (value, start, end) = self._convert_idx_params(space, w_start, w_end)
         if space.isinstance_w(w_suffix, space.w_tuple):
@@ -643,8 +637,6 @@
 
     def _endswith(self, space, value, w_prefix, start, end):
         prefix = self._op_val(space, w_prefix)
-        if start > len(value):
-            return self._starts_ends_overflow(prefix)
         return endswith(value, prefix, start, end)
 
     def _strip(self, space, w_chars, left, right):
diff --git a/pypy/objspace/std/test/test_complexobject.py b/pypy/objspace/std/test/test_complexobject.py
--- a/pypy/objspace/std/test/test_complexobject.py
+++ b/pypy/objspace/std/test/test_complexobject.py
@@ -265,41 +265,26 @@
         assert self.close(complex(5.3, 9.8).conjugate(), 5.3-9.8j)
 
     def test_constructor(self):
-        class OS:
-            def __init__(self, value):
-                self.value = value
-            def __complex__(self):
-                return self.value
         class NS(object):
             def __init__(self, value):
                 self.value = value
             def __complex__(self):
                 return self.value
-        assert complex(OS(1+10j)) == 1+10j
         assert complex(NS(1+10j)) == 1+10j
-        assert complex(OS(1+10j), 5) == 1+15j
         assert complex(NS(1+10j), 5) == 1+15j
-        assert complex(OS(1+10j), 5j) == -4+10j
         assert complex(NS(1+10j), 5j) == -4+10j
-        assert complex(OS(2.0)) == 2+0j
-        assert complex(NS(2.0)) == 2+0j
-        assert complex(OS(2)) == 2+0j
-        assert complex(NS(2)) == 2+0j
-        raises(TypeError, complex, OS(None))
+        raises(TypeError, complex, NS(2.0))
+        raises(TypeError, complex, NS(2))
         raises(TypeError, complex, NS(None))
         raises(TypeError, complex, b'10')
 
         # -- The following cases are not supported by CPython, but they
         # -- are supported by PyPy, which is most probably ok
-        #raises((TypeError, AttributeError), complex, OS(1+10j), OS(1+10j))
-        #raises((TypeError, AttributeError), complex, NS(1+10j), OS(1+10j))
-        #raises((TypeError, AttributeError), complex, OS(1+10j), NS(1+10j))
         #raises((TypeError, AttributeError), complex, NS(1+10j), NS(1+10j))
 
         class F(object):
             def __float__(self):
                 return 2.0
-        assert complex(OS(1+10j), F()) == 1+12j
         assert complex(NS(1+10j), F()) == 1+12j
 
         assert self.almost_equal(complex("1+10j"), 1+10j)
@@ -393,23 +378,6 @@
         assert complex(s) == 1+2j
         assert complex('\N{EM SPACE}(\N{EN SPACE}1+1j ) ') == 1+1j
 
-    def test___complex___returning_non_complex(self):
-        import cmath
-        class Obj(object):
-            def __init__(self, value):
-                self.value = value
-            def __complex__(self):
-                return self.value
-
-        # "bug-to-bug" compatibility to CPython: complex() is more relaxed in
-        # what __complex__ can return. cmath functions really wants a complex
-        # number to be returned by __complex__.
-        assert complex(Obj(2.0)) == 2+0j
-        assert complex(Obj(2)) == 2+0j
-        #
-        assert cmath.polar(1) == (1.0, 0.0)
-        raises(TypeError, "cmath.polar(Obj(1))")
-
     def test_hash(self):
         for x in range(-30, 30):
             assert hash(x) == hash(complex(x, 0))


More information about the pypy-commit mailing list