Partial merge of trunk progress. Some tests still fail. minimal-visibility
authorW. Trevor King <wking@drexel.edu>
Mon, 2 May 2011 22:53:05 +0000 (18:53 -0400)
committerW. Trevor King <wking@drexel.edu>
Mon, 2 May 2011 22:53:09 +0000 (18:53 -0400)
Failing tests:
  publicapi_pxd_mix
  generators_py
  cppwrap
  cpp_overload_wrapper

34 files changed:
1  2 
Cython/Compiler/Buffer.py
Cython/Compiler/Builtin.py
Cython/Compiler/Code.py
Cython/Compiler/ExprNodes.py
Cython/Compiler/ModuleNode.py
Cython/Compiler/Nodes.py
Cython/Compiler/Optimize.py
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/Parsing.pxd
Cython/Compiler/Parsing.py
Cython/Compiler/PyrexTypes.py
Cython/Compiler/Symtab.py
runtests.py
tests/compile/cpdef.pyx
tests/errors/builtin_type_inheritance.pyx
tests/errors/cdef_members_T517.pyx
tests/errors/cdef_visibility.pyx
tests/errors/cdefspecial.pyx
tests/errors/cmethbasematch.pyx
tests/errors/cpdef_syntax.pyx
tests/errors/e_cdefemptysue.pyx
tests/errors/e_cmethbasematch.pyx
tests/errors/e_ctypedefornot.pyx
tests/errors/e_func_in_pxd.pyx
tests/errors/e_nogilcmeth.pyx
tests/errors/e_packedstruct_T290.pyx
tests/errors/e_undefexttype.pyx
tests/errors/missing_self_in_cpdef_method_T156.pyx
tests/errors/missing_self_in_cpdef_method_T165.pyx
tests/errors/nogil.pyx
tests/errors/nogilcmeth.pyx
tests/errors/pxd_cdef_class_declaration_T286.pyx
tests/errors/subtyping_final_class.pyx
tests/run/cdef_members_T517.pyx

Simple merge
Simple merge
index 9bb3927f5fcc50143d690bea8e852c5ca30d45b3,c4c766cb367c1bc83cb13b00f4ff8b31aee1c864..2c23b21bfc5b7342c45c4c6afe9b25e4891e4e30
@@@ -1391,3 -1462,26 +1461,27 @@@ class PyrexCodeWriter(object)
      def dedent(self):
          self.level -= 1
  
 -        self.klass.declare_var(pos=None, name=cname, cname=cname, type=type, is_cdef=True)
+ class ClosureTempAllocator(object):
+     def __init__(self, klass):
+         self.klass = klass
+         self.temps_allocated = {}
+         self.temps_free = {}
+         self.temps_count = 0
+     def reset(self):
+         for type, cnames in self.temps_allocated.items():
+             self.temps_free[type] = list(cnames)
+     def allocate_temp(self, type):
+         if not type in self.temps_allocated:
+             self.temps_allocated[type] = []
+             self.temps_free[type] = []
+         elif self.temps_free[type]:
+             return self.temps_free[type].pop(0)
+         cname = '%s%d' % (Naming.codewriter_temp_prefix, self.temps_count)
++        self.klass.declare_var(pos=None, name=cname, cname=cname, type=type,
++                               visibility='private', is_cdef=True)
+         self.temps_allocated[type].append(cname)
+         self.temps_count += 1
+         return cname
index da7a76ac5cf3fdf73c05a58077102a9c0d1e8008,27f0ccb9e86fd12de97b5718ddf5e3f11b020bde..d6669b5ea54320992c82f2005c5b3249fa8fbf0b
@@@ -1335,9 -1330,8 +1331,9 @@@ class NameNode(AtomicExprNode)
              if entry and entry.is_cfunction:
                  var_entry = entry.as_variable
                  if var_entry:
-                     if var_entry.is_builtin and Options.cache_builtins:
+                     if var_entry.is_builtin and var_entry.is_const:
 -                        var_entry = env.declare_builtin(var_entry.name, self.pos)
 +                        var_entry = env.declare_builtin(
 +                            name = var_entry.name, pos = self.pos)
                      node = NameNode(self.pos, name = self.name)
                      node.entry = var_entry
                      node.analyse_rvalue_entry(env)
index 7ccff3ed3f03214e4a9562d46ea44aa70ce0a43c,a3d34b390a9c10123977246de3c7ba946174cac7..1e6f89cb033a57c23af4fca1658ef67f6da9645e
@@@ -96,10 -96,12 +96,12 @@@ class ModuleNode(Nodes.Node, Nodes.Bloc
                  f.close()
  
      def generate_h_code(self, env, options, result):
-         def h_entries(entries, pxd = 0):
+         def h_entries(entries, api=0, pxd=0):
              return [entry for entry in entries
-                 if entry.c_visibility == 'public' or pxd and entry.defined_in_pxd]
-         h_types = h_entries(env.type_entries)
 -                    if ((entry.visibility == 'public') or
++                    if ((entry.c_visibility == 'public') or
+                         (api and entry.api) or
+                         (pxd and entry.defined_in_pxd))]
+         h_types = h_entries(env.type_entries, api=1)
          h_vars = h_entries(env.var_entries)
          h_funcs = h_entries(env.cfunc_entries)
          h_extension_types = h_entries(env.c_class_entries)
          code.putln("")
          name = entry.type.typeobj_cname
          if name:
 -            if entry.visibility == 'extern' and not entry.in_cinclude:
 +            if entry.c_visibility == 'extern' and not entry.in_cinclude:
-                 code.putln("%s DL_IMPORT(PyTypeObject) %s;" % (
+                 code.putln("%s %s %s;" % (
                      Naming.extern_c_macro,
+                     PyrexTypes.public_decl("PyTypeObject", "DL_IMPORT"),
                      name))
 -            elif entry.visibility == 'public':
 +            elif entry.c_visibility == 'public':
-                 code.putln("%s DL_EXPORT(PyTypeObject) %s;" % (
+                 code.putln("%s %s %s;" % (
                      Naming.extern_c_macro,
+                     PyrexTypes.public_decl("PyTypeObject", "DL_EXPORT"),
                      name))
              # ??? Do we really need the rest of this? ???
              #else:
      def generate_cfunction_predeclarations(self, env, code, definition):
          for entry in env.cfunc_entries:
              if entry.inline_func_in_pxd or (not entry.in_cinclude and (definition
 -                    or entry.defined_in_pxd or entry.visibility == 'extern')):
 -                if entry.visibility == 'public':
 +                    or entry.defined_in_pxd or entry.c_visibility == 'extern')):
 +                if entry.c_visibility in ('extern', 'public'):
+                     storage_class = "%s " % Naming.extern_c_macro
                      dll_linkage = "DL_EXPORT"
+                 elif entry.visibility == 'extern':
+                     storage_class = "%s " % Naming.extern_c_macro
+                     dll_linkage = "DL_IMPORT"
+                 elif entry.visibility == 'private':
+                     storage_class = "static "
+                     dll_linkage = None
                  else:
+                     storage_class = "static "
                      dll_linkage = None
                  type = entry.type
                  if not definition and entry.defined_in_pxd:
                      type = CPtrType(type)
                  header = type.declaration_code(entry.cname,
-                     dll_linkage = dll_linkage)
+                                                dll_linkage = dll_linkage)
 +                if entry.c_visibility == 'private':
 +                    storage_class = "static "
 +                elif entry.c_visibility == 'public':
 +                    storage_class = ""
 +                else:
 +                    storage_class = "%s " % Naming.extern_c_macro
                  if entry.func_modifiers:
-                     modifiers = '%s ' % ' '.join([
-                             modifier.upper() for modifier in entry.func_modifiers])
+                     modifiers = "%s " % ' '.join(entry.func_modifiers).upper()
                  else:
                      modifiers = ''
                  code.putln("%s%s%s; /*proto*/" % (
index f59986cf6a2cb1c23e909363ebd54794ac2e17f8,4405fefa46fc911c2d57d0aeb6096787ab1f4a4a..4113d7c8067e85813ec0fdc2948b043dd5ebf395
@@@ -945,14 -954,18 +958,17 @@@ class CVarDefNode(StatNode)
              need_property = True
          else:
              need_property = False
 -        visibility = self.visibility
  
          for declarator in self.declarators:
-             name_declarator, type = declarator.analyse(base_type, env)
+             if isinstance(declarator, CFuncDeclaratorNode):
+                 name_declarator, type = declarator.analyse(base_type, env, directive_locals=self.directive_locals)
+             else:
+                 name_declarator, type = declarator.analyse(base_type, env)
              if not type.is_complete():
 -                if not (self.visibility == 'extern' and type.is_array):
 +                if not (self.c_visibility == 'extern' and type.is_array):
                      error(declarator.pos,
                          "Variable type '%s' is incomplete" % type)
 -            if self.visibility == 'extern' and type.is_pyobject:
 +            if self.c_visibility == 'extern' and type.is_pyobject:
                  error(declarator.pos,
                      "Python object cannot be declared extern")
              name = name_declarator.name
                  error(declarator.pos, "Missing name in declaration.")
                  return
              if type.is_cfunction:
 -                entry = dest_scope.declare_cfunction(name, type, declarator.pos,
 -                    cname = cname, visibility = self.visibility, in_pxd = self.in_pxd,
 -                    api = self.api)
 +                entry = dest_scope.declare_cfunction(
 +                    name = name, cname = cname, c_visibility = self.c_visibility, visibility = self.visibility, overridable = self.overridable, api = self.api, type = type, in_pxd = self.in_pxd,
 +                    pos = declarator.pos)
                  if entry is not None:
-                     entry.directive_locals = self.directive_locals
+                     entry.directive_locals = copy.copy(self.directive_locals)
              else:
                  if self.directive_locals:
                      error(self.pos, "Decorators can only be followed by functions")
  
  
  class CStructOrUnionDefNode(StatNode):
 -    #  name          string
 -    #  cname         string or None
 +    #  name          (same as Entry.name)
 +    #  cname         (same as Entry.cname)
      #  kind          "struct" or "union"
      #  typedef_flag  boolean
 -    #  visibility    "public" or "private"
 -    #  api           boolean
 +    #  c_visibility  (same as Entry.c_visibility)
 +    #  visibility    (same as Entry.visibility)
++    #  api           (same as Entry.api)
      #  in_pxd        boolean
      #  attributes    [CVarDefNode] or None
      #  entry         Entry
          if self.attributes is not None:
              scope = StructOrUnionScope(self.name)
          self.entry = env.declare_struct_or_union(
-             name = self.name, cname = self.cname, c_visibility = self.c_visibility, visibility = self.visibility, overridable = self.overridable, kind = self.kind, scope = scope,
 -            self.name, self.kind, scope, self.typedef_flag, self.pos,
 -            self.cname, visibility = self.visibility, api = self.api,
 -            packed = self.packed)
++            name = self.name, cname = self.cname, c_visibility = self.c_visibility, visibility = self.visibility, overridable = self.overridable, api = self.api, kind = self.kind, scope = scope,
 +            typedef_flag = self.typedef_flag, packed = self.packed,
 +            pos = self.pos)
          if self.attributes is not None:
              if self.in_pxd and not env.in_cinclude:
                  self.entry.defined_in_pxd = 1
@@@ -1077,20 -1091,21 +1094,21 @@@ class CppClassNode(CStructOrUnionDefNod
                  attr.analyse_declarations(scope)
  
  class CEnumDefNode(StatNode):
 -    #  name           string or None
 -    #  cname          string or None
 +    #  name           (same as Entry.name)
 +    #  cname          (same as Entry.cname)
      #  items          [CEnumDefItemNode]
      #  typedef_flag   boolean
 -    #  visibility     "public" or "private"
 -    #  api            boolean
 +    #  c_visibility   (same as Entry.c_visibility)
 +    #  visibility     (same as Entry.visibility)
++    #  api            (same as Entry.api)
      #  in_pxd         boolean
      #  entry          Entry
  
      child_attrs = ["items"]
  
      def analyse_declarations(self, env):
 -        self.entry = env.declare_enum(self.name, self.pos,
 -            cname = self.cname, typedef_flag = self.typedef_flag,
 -            visibility = self.visibility, api = self.api)
 +        self.entry = env.declare_enum(
-             name = self.name, cname = self.cname, c_visibility = self.c_visibility, visibility = self.visibility, typedef_flag = self.typedef_flag, pos = self.pos)
++            name = self.name, cname = self.cname, c_visibility = self.c_visibility, visibility = self.visibility, api = self.api, typedef_flag = self.typedef_flag, pos = self.pos)
          if self.items is not None:
              if self.in_pxd and not env.in_cinclude:
                  self.entry.defined_in_pxd = 1
          pass
  
      def generate_execution_code(self, code):
-         if self.visibility == 'public':
+         if self.visibility == 'public' or self.api:
              temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
              for item in self.entry.enum_values:
 +                if item.visibility == 'private':
 +                    continue
                  code.putln("%s = PyInt_FromLong(%s); %s" % (
                          temp,
                          item.cname,
@@@ -1133,9 -1146,9 +1151,9 @@@ class CEnumDefItemNode(StatNode)
              if not self.value.type.is_int:
                  self.value = self.value.coerce_to(PyrexTypes.c_int_type, env)
                  self.value.analyse_const_expression(env)
 -        entry = env.declare_const(self.name, enum_entry.type,
 -            self.value, self.pos, cname = self.cname,
 -            visibility = enum_entry.visibility, api = enum_entry.api)
 +        entry = env.declare_const(
 +            name = self.name, cname = self.cname, c_visibility = self.c_visibility, visibility = self.visibility, type = enum_entry.type,
-             value = self.value, pos = self.pos)
++            api = enum_entry.api, value = self.value, pos = self.pos)
          enum_entry.enum_values.append(entry)
  
  
@@@ -1143,6 -1156,7 +1161,7 @@@ class CTypeDefNode(StatNode)
      #  base_type    CBaseTypeNode
      #  declarator   CDeclaratorNode
      #  visibility   "public" or "private"
 -    #  api          boolean
++    #  api          (same as Entry.api)
      #  in_pxd       boolean
  
      child_attrs = ["base_type", "declarator"]
      def analyse_declarations(self, env):
          base = self.base_type.analyse(env)
          name_declarator, type = self.declarator.analyse(base, env)
 -        name = name_declarator.name
 -        cname = name_declarator.cname
 -        entry = env.declare_typedef(name, type, self.pos,
 -            cname = cname, visibility = self.visibility, api = self.api)
 +        entry = env.declare_typedef(
-             name = name_declarator.name, cname = name_declarator.cname, c_visibility = self.c_visibility, visibility = self.visibility, base_type = type, pos = self.pos)
++            name = name_declarator.name, cname = name_declarator.cname, c_visibility = self.c_visibility, visibility = self.visibility, api = self.api, base_type = type, pos = self.pos)
          if self.in_pxd and not env.in_cinclude:
              entry.defined_in_pxd = 1
  
@@@ -1760,24 -1805,20 +1811,20 @@@ class CFuncDefNode(FuncDefNode)
          if cname is None:
              cname = self.entry.func_cname
          entity = type.function_header_code(cname, ', '.join(arg_decls))
-         if self.entry.c_visibility == 'public':
-             dll_linkage = "DL_EXPORT"
 -        if self.entry.visibility == 'private':
++        if self.entry.c_visibility == 'private':
+             storage_class = "static "
          else:
-             dll_linkage = None
-         header = self.return_type.declaration_code(entity,
-             dll_linkage = dll_linkage)
-         if self.entry.c_visibility == 'extern':
-             storage_class = "%s " % Naming.extern_c_macro
-         elif self.entry.c_visibility == 'public':
              storage_class = ""
-         else:
-             storage_class = "static "
+         dll_linkage = None
+         modifiers = ""
          if 'inline' in self.modifiers:
              self.modifiers[self.modifiers.index('inline')] = 'cython_inline'
-         code.putln("%s%s %s {" % (
-             storage_class,
-             ' '.join(self.modifiers).upper(), # macro forms
-             header))
+         if self.modifiers:
+             modifiers = "%s " % ' '.join(self.modifiers).upper()
+         header = self.return_type.declaration_code(entity, dll_linkage=dll_linkage)
+         #print (storage_class, modifiers, header)
+         code.putln("%s%s%s {" % (storage_class, modifiers, header))
  
      def generate_argument_declarations(self, env, code):
          for arg in self.args:
@@@ -2195,14 -2232,7 +2244,7 @@@ class DefNode(FuncDefNode)
              entry.doc = None
  
      def declare_lambda_function(self, env):
-         name = self.name
-         prefix = env.scope_prefix
-         func_cname = \
-             Naming.lambda_func_prefix + u'funcdef' + prefix + self.lambda_name
-         entry = env.declare_lambda_function(cname = func_cname, pos = self.pos)
-         entry.pymethdef_cname = \
-             Naming.lambda_func_prefix + u'methdef' + prefix + self.lambda_name
-         entry.qualified_name = env.qualify_name(self.lambda_name)
 -        entry = env.declare_lambda_function(self.lambda_name, self.pos)
++        entry = env.declare_lambda_function(cname = self.lambda_name, pos = self.pos)
          entry.doc = None
          self.entry = entry
  
      def caller_will_check_exceptions(self):
          return 1
  
 -        entry = env.declare_var(prefix + name, py_object_type, self.pos, visibility='private')
+ class GeneratorDefNode(DefNode):
+     # Generator DefNode.
+     #
+     # gbody          GeneratorBodyDefNode
+     #
+     is_generator = True
+     needs_closure = True
+     child_attrs = DefNode.child_attrs + ["gbody"]
+     def __init__(self, **kwargs):
+         # XXX: don't actually needs a body
+         kwargs['body'] = StatListNode(kwargs['pos'], stats=[])
+         super(GeneratorDefNode, self).__init__(**kwargs)
+     def analyse_declarations(self, env):
+         super(GeneratorDefNode, self).analyse_declarations(env)
+         self.gbody.local_scope = self.local_scope
+         self.gbody.analyse_declarations(env)
+     def generate_function_body(self, env, code):
+         body_cname = self.gbody.entry.func_cname
+         generator_cname = '%s->%s' % (Naming.cur_scope_cname, Naming.obj_base_cname)
+         code.putln('%s.resume_label = 0;' % generator_cname)
+         code.putln('%s.body = (__pyx_generator_body_t) %s;' % (generator_cname, body_cname))
+         code.put_giveref(Naming.cur_scope_cname)
+         code.put_finish_refcount_context()
+         code.putln("return (PyObject *) %s;" % Naming.cur_scope_cname);
+     def generate_function_definitions(self, env, code):
+         self.gbody.generate_function_header(code, proto=True)
+         super(GeneratorDefNode, self).generate_function_definitions(env, code)
+         self.gbody.generate_function_definitions(env, code)
+ class GeneratorBodyDefNode(DefNode):
+     # Generator body DefNode.
+     #
+     is_generator_body = True
+     def __init__(self, pos=None, name=None, body=None):
+         super(GeneratorBodyDefNode, self).__init__(pos=pos, body=body, name=name, doc=None,
+                                                    args=[],
+                                                    star_arg=None, starstar_arg=None)
+     def declare_generator_body(self, env):
+         prefix = env.next_id(env.scope_prefix)
+         name = env.next_id('generator')
++        entry = env.declare_var(
++            name=prefix + name, type=py_object_type, c_visibility='private',
++            visibility='public', pos=self.pos)
+         entry.func_cname = Naming.genbody_prefix + prefix + name
+         entry.qualified_name = EncodedString(self.name)
+         self.entry = entry
+     def analyse_declarations(self, env):
+         self.analyse_argument_types(env)
+         self.declare_generator_body(env)
+     def generate_function_header(self, code, proto=False):
+         header = "static PyObject *%s(%s, PyObject *%s)" % (
+             self.entry.func_cname,
+             self.local_scope.scope_class.type.declaration_code(Naming.cur_scope_cname),
+             Naming.sent_value_cname)
+         if proto:
+             code.putln('%s; /* proto */' % header)
+         else:
+             code.putln('%s /* generator body */\n{' % header);
+     def generate_function_definitions(self, env, code):
+         lenv = self.local_scope
+         # Generate closure function definitions
+         self.body.generate_function_definitions(lenv, code)
+         # Generate C code for header and body of function
+         code.enter_cfunc_scope()
+         code.return_from_error_cleanup_label = code.new_label()
+         # ----- Top-level constants used by this function
+         code.mark_pos(self.pos)
+         self.generate_cached_builtins_decls(lenv, code)
+         # ----- Function header
+         code.putln("")
+         self.generate_function_header(code)
+         # ----- Local variables
+         code.putln("PyObject *%s = NULL;" % Naming.retval_cname)
+         tempvardecl_code = code.insertion_point()
+         code.put_declare_refcount_context()
+         code.put_setup_refcount_context(self.entry.name)
+         # ----- Resume switch point.
+         code.funcstate.init_closure_temps(lenv.scope_class.type.scope)
+         resume_code = code.insertion_point()
+         first_run_label = code.new_label('first_run')
+         code.use_label(first_run_label)
+         code.put_label(first_run_label)
+         code.putln('%s' %
+                    (code.error_goto_if_null(Naming.sent_value_cname, self.pos)))
+         # ----- Function body
+         self.generate_function_body(env, code)
+         code.putln('PyErr_SetNone(PyExc_StopIteration); %s' % code.error_goto(self.pos))
+         # ----- Error cleanup
+         if code.error_label in code.labels_used:
+             code.put_goto(code.return_label)
+             code.put_label(code.error_label)
+             for cname, type in code.funcstate.all_managed_temps():
+                 code.put_xdecref(cname, type)
+             code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name)
+         # ----- Non-error return cleanup
+         code.put_label(code.return_label)
+         code.put_xdecref(Naming.retval_cname, py_object_type)
+         code.putln('%s->%s.resume_label = -1;' % (Naming.cur_scope_cname, Naming.obj_base_cname))
+         code.put_finish_refcount_context()
+         code.putln('return NULL;');
+         code.putln("}")
+         # ----- Go back and insert temp variable declarations
+         tempvardecl_code.put_temp_declarations(code.funcstate)
+         # ----- Generator resume code
+         resume_code.putln("switch (%s->%s.resume_label) {" % (Naming.cur_scope_cname, Naming.obj_base_cname));
+         resume_code.putln("case 0: goto %s;" % first_run_label)
+         from ParseTreeTransforms import YieldNodeCollector
+         collector = YieldNodeCollector()
+         collector.visitchildren(self)
+         for yield_expr in collector.yields:
+             resume_code.putln("case %d: goto %s;" % (yield_expr.label_num, yield_expr.label_name));
+         resume_code.putln("default: /* CPython raises the right error here */");
+         resume_code.put_finish_refcount_context()
+         resume_code.putln("return NULL;");
+         resume_code.putln("}");
+         code.exit_cfunc_scope()
  class OverrideCheckNode(StatNode):
      # A Node for dispatching to the def method if it
      # is overriden.
Simple merge
index 5626c4dcf25880f906a311ad06bfebeeaf9d1b20,00de70a359adb9046849b946e4e9a49ac91f7a53..a660db1337a90edea8309db24639188cebec3831
@@@ -1219,7 -1227,8 +1227,8 @@@ if VALUE is not None
      def visit_CNameDeclaratorNode(self, node):
          if node.name in self.seen_vars_stack[-1]:
              entry = self.env_stack[-1].lookup(node.name)
-             if entry is None or entry.c_visibility != 'extern':
 -            if (entry is None or entry.visibility != 'extern'
++            if (entry is None or entry.c_visibility != 'extern'
+                 and not entry.scope.is_c_class_scope):
                  warning(node.pos, "cdef variable '%s' declared after it is used" % node.name, 2)
          self.visitchildren(node)
          return node
@@@ -1446,7 -1511,57 +1515,61 @@@ class CreateClosureClasses(CythonTransf
          self.visitchildren(node)
          return node
  
-     def get_scope_use(self, node):
+     def create_generator_class(self, target_module_scope, pos):
+         if self.generator_class:
+             return self.generator_class
+         # XXX: make generator class creation cleaner
+         entry = target_module_scope.declare_c_class(name='__pyx_Generator',
+                     objstruct_cname='__pyx_Generator_object',
+                     typeobj_cname='__pyx_Generator_type',
+                     pos=pos, defining=True, implementing=True)
+         klass = entry.type.scope
+         klass.is_internal = True
+         klass.directives = {'final': True}
+         body_type = PyrexTypes.create_typedef_type('generator_body',
+                                                    PyrexTypes.c_void_ptr_type,
+                                                    '__pyx_generator_body_t')
+         klass.declare_var(pos=pos, name='body', cname='body',
 -                          type=body_type, is_cdef=True)
++                          visibility='private', type=body_type, is_cdef=True)
+         klass.declare_var(pos=pos, name='is_running', cname='is_running', type=PyrexTypes.c_int_type,
+                           is_cdef=True)
+         klass.declare_var(pos=pos, name='resume_label', cname='resume_label', type=PyrexTypes.c_int_type,
+                           is_cdef=True)
+         klass.declare_var(pos=pos, name='exc_type', cname='exc_type',
+                           type=PyrexTypes.py_object_type, is_cdef=True)
+         klass.declare_var(pos=pos, name='exc_value', cname='exc_value',
+                           type=PyrexTypes.py_object_type, is_cdef=True)
+         klass.declare_var(pos=pos, name='exc_traceback', cname='exc_traceback',
+                           type=PyrexTypes.py_object_type, is_cdef=True)
+         import TypeSlots
 -        e = klass.declare_pyfunction('send', pos)
++        e = klass.declare_pyfunction(name='send', pos=pos)
+         e.func_cname = '__Pyx_Generator_Send'
+         e.signature = TypeSlots.binaryfunc
 -        e = klass.declare_pyfunction('close', pos)
++        e = klass.declare_pyfunction(name='close', pos=pos)
+         e.func_cname = '__Pyx_Generator_Close'
+         e.signature = TypeSlots.unaryfunc
 -        e = klass.declare_pyfunction('throw', pos)
++        e = klass.declare_pyfunction(name='throw', pos=pos)
+         e.func_cname = '__Pyx_Generator_Throw'
+         e.signature = TypeSlots.pyfunction_signature
 -        e = klass.declare_var('__iter__', PyrexTypes.py_object_type, pos, visibility='public')
++        e = klass.declare_var(
++            name='__iter__', type=PyrexTypes.py_object_type,
++            c_visibility='public', pos=pos)
+         e.func_cname = 'PyObject_SelfIter'
 -        e = klass.declare_var('__next__', PyrexTypes.py_object_type, pos, visibility='public')
++        e = klass.declare_var(
++            name='__next__', type=PyrexTypes.py_object_type,
++            c_visibility='public', pos=pos)
+         e.func_cname = '__Pyx_Generator_Next'
+         self.generator_class = entry.type
+         return self.generator_class
+     def find_entries_used_in_closures(self, node):
          from_closure = []
          in_closure = []
          for name, entry in node.local_scope.entries.items():
Simple merge
index 4a822d5e89a8025801a77259116e1ff65382a9b3,4e2c55ad2c2aee350487bbac841dac8b4e0695cc..63ae5c0f16dc33029ce836ac9ee673428cdcf04d
@@@ -2436,8 -2471,8 +2488,9 @@@ def p_c_enum_definition(s, pos, ctx)
          s.expect_dedent()
      return Nodes.CEnumDefNode(
          pos, name = name, cname = cname, items = items,
 -        typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
 -        api = ctx.api, in_pxd = ctx.level == 'module_pxd')
 +        typedef_flag = ctx.typedef_flag, c_visibility = ctx.c_visibility,
-         visibility = ctx.visibility, in_pxd = ctx.level == 'module_pxd')
++        visibility = ctx.visibility, api = ctx.api,
++        in_pxd = ctx.level == 'module_pxd')
  
  def p_c_enum_line(s, ctx, items):
      if s.sy != 'pass':
@@@ -2499,38 -2530,21 +2552,39 @@@ def p_c_struct_or_union_definition(s, p
          s.expect_dedent()
      else:
          s.expect_newline("Syntax error in struct or union definition")
--    return Nodes.CStructOrUnionDefNode(pos,
 -        name = name, cname = cname, kind = kind, attributes = attributes,
 -        typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
 -        api = ctx.api, in_pxd = ctx.level == 'module_pxd', packed = packed)
++    return Nodes.CStructOrUnionDefNode(pos = pos,
 +        name = name,
 +        cname = cname,
 +        kind = kind,
 +        attributes = attributes,
 +        typedef_flag = ctx.typedef_flag,
 +        cdef_flag = ctx.cdef_flag,
 +        overridable = ctx.overridable,
 +        c_visibility = ctx.c_visibility,
 +        visibility = ctx.visibility,
++        api = ctx.api,
 +        in_pxd = ctx.level == 'module_pxd',
 +        packed = packed)
  
 -def p_visibility(s, prev_visibility):
 +def p_visibility(s, ctx):
      pos = s.position()
 -    visibility = prev_visibility
      if s.sy == 'IDENT' and s.systring in ('extern', 'public', 'readonly'):
          visibility = s.systring
 -        if prev_visibility != 'private' and visibility != prev_visibility:
 -            s.error("Conflicting visibility options '%s' and '%s'"
 -                % (prev_visibility, visibility))
 +        outer_scope = ctx.level in ('module', 'module_pxd')
 +        if visibility == 'extern':
 +            #if prev_visibility != 'private' and visibility != prev_visibility:
 +            #    s.error("Conflicting visibility options '%s' and '%s'"
 +            #            % (prev_visibility, visibility))
 +            ctx.c_visibility = 'extern'
 +            # Need to restore/set default value for Python visibility?
 +        elif outer_scope and visibility not in ('readonly',):
 +            ctx.c_visibility = visibility
 +        else:
 +            ctx.visibility = visibility
 +            if ctx.visibility != 'private':
 +                ctx.c_visibility = 'public'
          s.next()
 -    return visibility
 +    return ctx
  
  def p_c_modifiers(s):
      if s.sy == 'IDENT' and s.systring in ('inline',):
@@@ -2619,9 -2617,10 +2673,9 @@@ def p_ctypedef_statement(s, pos, ctx)
          declarator = p_c_declarator(s, ctx, is_type = 1, nonempty = 1)
          s.expect_newline("Syntax error in ctypedef statement")
          return Nodes.CTypeDefNode(
 -            pos, base_type = base_type,
 -            declarator = declarator,
 -            visibility = visibility, api = api,
 -            in_pxd = ctx.level == 'module_pxd')
 +            pos, base_type = base_type, declarator = declarator,
 +            c_visibility = ctx.c_visibility, visibility = ctx.visibility,
-             in_pxd = ctx.level == 'module_pxd')
++            api = ctx.api, in_pxd = ctx.level == 'module_pxd')
  
  def p_decorators(s):
      decorators = []
@@@ -2747,8 -2746,8 +2801,8 @@@ def p_c_class_definition(s, pos,  ctx, 
          base_class_module = ".".join(base_class_path[:-1])
          base_class_name = base_class_path[-1]
      if s.sy == '[':
-         if ctx.c_visibility not in ('extern', 'public'):
-             error(s.position(), "Name options only allowed for 'public' or 'extern' C class")
 -        if ctx.visibility not in ('public', 'extern') and not ctx.api:
++        if ctx.c_visibility not in ('public', 'extern') and not ctx.api:
+             error(s.position(), "Name options only allowed for 'public', 'api', or 'extern' C class")
          objstruct_name, typeobj_name = p_c_class_options(s)
      if s.sy == ':':
          if ctx.level == 'module_pxd':
              error(pos, "Object struct name specification required for 'public' C class")
          if not typeobj_name:
              error(pos, "Type object name specification required for 'public' C class")
 -    elif ctx.visibility == 'private':
 +    elif ctx.c_visibility == 'private':
          if ctx.api:
-             error(pos, "Only 'public' C class can be declared 'api'")
+             if not objstruct_name:
+                 error(pos, "Object struct name specification required for 'api' C class")
+             if not typeobj_name:
+                 error(pos, "Type object name specification required for 'api' C class")
      else:
 -        error(pos, "Invalid class visibility '%s'" % ctx.visibility)
 +        error(pos, "Invalid class visibility '%s'" % ctx.visibility_string())
      return Nodes.CClassDefNode(pos,
 +        c_visibility = ctx.c_visibility,
          visibility = ctx.visibility,
          typedef_flag = ctx.typedef_flag,
          api = ctx.api,
index d9093f3c4e50b7df2e322b0515464ff3cf4a3901,0870cf22d78472e2dd70081ed24619dcfb66f10f..9f9bd3d0a4c5527814f0233d4f6a352db0a72fd6
@@@ -1968,12 -1977,12 +1973,8 @@@ class StructUtilityCode(object)
          code.putln("return NULL;")
          code.putln("}")
  
--        # This is a bit of a hack, we need a forward declaration
--        # due to the way things are ordered in the module...
--        if self.forward_decl:
--            proto.putln(self.type.declaration_code('') + ';')
          proto.putln(self.header + ";")
-         
  
  class CStructOrUnionType(CType):
      #  name          string
                      self.to_py_function = None
                      self._convert_code = False
                      return False
 -            forward_decl = (self.entry.visibility != 'extern')
 +            forward_decl = (self.entry.c_visibility != 'extern')
              self._convert_code = StructUtilityCode(self, forward_decl)
-         
          env.use_utility_code(self._convert_code)
          return True
-         
      def __repr__(self):
          return "<CStructOrUnionType %s %s%s>" % (self.name, self.cname,
              ("", " typedef")[self.typedef_flag])
index 5ffcb0ca51ee16f06e9d0d171984c9eb2ac68b14,6425a26de17f6616a665c3f1de3cf82eface069a..c045de96825e8489850329a5187f19b5a0477775
@@@ -365,10 -363,10 +367,10 @@@ class Scope(object)
      def qualify_name(self, name):
          return EncodedString("%s.%s" % (self.qualified_name, name))
  
 -    def declare_const(self, name, type, value, pos, cname = None, visibility = 'private', api = 0):
 +    def declare_const(self, name, cname = None, namespace = None, c_visibility = 'private', visibility = 'public', overridable = 0, api = 0, type = None, value = None, pos = None):
          # Add an entry for a named constant.
          if not cname:
-             if self.in_cinclude or c_visibility == 'public':
 -            if self.in_cinclude or (visibility == 'public' or api):
++            if self.in_cinclude or c_visibility == 'public' or api:
                  cname = name
              else:
                  cname = self.mangle(Naming.enum_prefix, name)
          # Add an entry for a type definition.
          if not cname:
              cname = name
 -        entry = self.declare(name, cname, type, pos, visibility, shadow)
 +        entry = self.declare(name = name, cname = cname, namespace = namespace, c_visibility = c_visibility, visibility = visibility, overridable = overridable, api = api, type = type, shadow = shadow, pos = pos)
          entry.is_type = 1
+         entry.api = api
          if defining:
              self.type_entries.append(entry)
          # here we would set as_variable to an object representing this type
          return entry
  
 -    def declare_typedef(self, name, base_type, pos, cname = None,
 -                        visibility = 'private', api = 0):
 +    def declare_typedef(self, name, cname = None, namespace = None, c_visibility = 'private', visibility = 'public', overridable = 0, api = 0,
 +                            base_type = None, pos = None):
          if not cname:
-             if self.in_cinclude or c_visibility == 'public':
 -            if self.in_cinclude or (visibility == 'public' or api):
++            if self.in_cinclude or c_visibility == 'public' or api:
                  cname = name
              else:
                  cname = self.mangle(Naming.type_prefix, name)
          type.qualified_name = entry.qualified_name
          return entry
  
 -    def declare_struct_or_union(self, name, kind, scope,
 -                                typedef_flag, pos, cname = None,
 -                                visibility = 'private', api = 0,
 -                                packed = False):
 +    def declare_struct_or_union(self, name, cname = None, namespace = None, c_visibility = 'private', visibility = 'public', overridable = 0, api = 0, kind = None, scope = None, typedef_flag=False,
 +                                packed=False, pos = None):
          # Add an entry for a struct or union definition.
          if not cname:
-             if self.in_cinclude or c_visibility == 'public':
 -            if self.in_cinclude or (visibility == 'public' or api):
++            if self.in_cinclude or c_visibility == 'public' or api:
                  cname = name
              else:
                  cname = self.mangle(Naming.type_prefix, name)
      def check_previous_typedef_flag(self, entry, typedef_flag, pos):
          if typedef_flag != entry.type.typedef_flag:
              error(pos, "'%s' previously declared using '%s'" % (
 -                entry.name, ("cdef", "ctypedef")[entry.type.typedef_flag]))
 -
 -    def check_previous_visibility(self, entry, visibility, pos):
 -        if entry.visibility != visibility:
 -            error(pos, "'%s' previously declared as '%s'" % (
 -                entry.name, entry.visibility))
 -
 -    def declare_enum(self, name, pos, cname, typedef_flag,
 -            visibility = 'private', api = 0):
 +                entry.name,
 +                ("cdef", "ctypedef")[entry.type.typedef_flag]))
 +
-     def _check_previous_visibility(self, entry, c_visibility = 'private', visibility = 'public'):
++    def check_previous_visibility(self, entry, name, cname = None, namespace = None, c_visibility = 'private', visibility = 'public', overridable = 0, api = 0, type_name=None,
++                                  pos = None):
 +        # Compare the visibility of `entry` with a second
 +        # `visibility`.  If there is a difference, return a string
 +        # representing the conflicting `entry` visibility, otherwise
 +        # return an empty string.
++
++        if not type_name:
++            type_name = type(entry)
 +        if c_visibility != entry.c_visibility:
-             return entry.c_visibility
++            error(pos, "%s '%s' C visibility changed from '%s' to '%s'" % (
++                    type_name, entry.name, entry.c_visibility, c_visibility))
 +        if visibility != entry.visibility:
-             return entry.visibility
-     def check_previous_visibility(self, entry, name, cname = None, namespace = None, c_visibility = 'private', visibility = 'public', overridable = 0, api = 0, type_name=None,
-                                   pos = None):
++            error(pos, "%s '%s' Python visibility changed from '%s' to %s" % (
++                    type_name, entry.name, entry.visibility, visibility))
 +        # WTK: check api?  Previous code seems to allow you to set the
 +        # api flag anywhere.
-         vis_diff = self._check_previous_visibility(entry, c_visibility = c_visibility, visibility = visibility)
-         if vis_diff:
-             if not type_name:
-                 type_name = type(entry)
-             error(pos, "%s '%s' previously declared as '%s'" % (
-                     type_name, entry.name, vis_diff))
 +
 +    def declare_enum(self, name, cname = None, namespace = None, c_visibility = 'private', visibility = 'public', overridable = 0, api = 0, typedef_flag = None, pos = None):
          if name:
              if not cname:
-                 if self.in_cinclude or c_visibility == 'public':
 -                if self.in_cinclude or (visibility == 'public' or api):
++                if self.in_cinclude or c_visibility == 'public' or api:
                      cname = name
                  else:
                      cname = self.mangle(Naming.type_prefix, name)
              constructor = type.scope.lookup(u'<init>')
              if constructor is not None and PyrexTypes.best_match([], constructor.all_alternatives()) is None:
                  error(pos, "C++ class must have a default constructor to be stack allocated")
 -        entry = self.declare(name, cname, type, pos, visibility)
 +        entry = self.declare(name = name, cname = cname, namespace = namespace, c_visibility = c_visibility, visibility = visibility, overridable = overridable, api = api, type = type, pos = pos)
          entry.is_variable = 1
+         entry.api = api
          self.control_flow.set_state((), (name, 'initialized'), False)
          return entry
  
          entry.is_anonymous = True
          return entry
  
 -    def declare_lambda_function(self, lambda_name, pos):
 +    def declare_lambda_function(self, name = None, cname = None, namespace = None, c_visibility = 'private', visibility = 'public', overridable = 0, api = 0, pos = None):
          # Add an entry for an anonymous Python function.
 -        func_cname = self.mangle(Naming.lambda_func_prefix + u'funcdef_', lambda_name)
 -        pymethdef_cname = self.mangle(Naming.lambda_func_prefix + u'methdef_', lambda_name)
 -        qualified_name = self.qualify_name(lambda_name)
++        if not cname:
++            cname = self.mangle(Naming.lambda_func_prefix + u'funcdef_', cname)
++        pymethdef_cname = self.mangle(Naming.lambda_func_prefix + u'methdef_', cname)
++        qualified_name = self.qualify_name(cname)
 -        entry = self.declare(None, func_cname, py_object_type, pos, 'private')
 -        entry.name = lambda_name
 +        entry = self.declare_var(name = name, cname = cname, namespace = namespace, c_visibility = c_visibility, visibility = visibility, overridable = overridable, api = api, type = py_object_type, pos = pos)
++
 +        entry.name = EncodedString(cname)
+         entry.qualified_name = qualified_name
+         entry.pymethdef_cname = pymethdef_cname
 -        entry.func_cname = func_cname
 +        entry.func_cname = cname
          entry.signature = pyfunction_signature
          entry.is_anonymous = True
          return entry
                  cname = self.mangle(Naming.func_prefix, name)
          entry = self.lookup_here(name)
          if entry:
-             vis_diff = self._check_previous_visibility(entry, c_visibility = c_visibility, visibility = visibility)
-             if vis_diff:
-                 warning(pos, "Function '%s' previously declared as '%s'" % (
-                         name, vis_diff), 1)
 -            if visibility != 'private' and visibility != entry.visibility:
 -                warning(pos, "Function '%s' previously declared as '%s'" % (name, entry.visibility), 1)
++            self.check_previous_visibility(
++                entry, name = name, cname = cname, namespace = namespace,
++                c_visibility = c_visibility, visibility = visibility,
++                overridable = overridable, api = api, type_name = 'Function',
++                pos = pos)
              if not entry.type.same_as(type):
 -                if visibility == 'extern' and entry.visibility == 'extern':
 +                if c_visibility == 'extern' and entry.c_visibility == 'extern':
                      can_override = False
                      if self.is_cpp():
                          can_override = True
@@@ -772,15 -760,18 +784,18 @@@ class BuiltinScope(Scope)
                  name = 'unicode'
          return Scope.lookup(self, name)
  
 -    def declare_builtin(self, name, pos):
 +    def declare_builtin(self, name, cname = None, namespace = None, c_visibility = 'private', visibility = 'public', overridable = 0, api = 0, pos = None):
          if not hasattr(builtins, name):
              if self.outer_scope is not None:
 -                return self.outer_scope.declare_builtin(name, pos)
 +                return self.outer_scope.declare_builtin(name = name, cname = cname, namespace = namespace, c_visibility = c_visibility, visibility = visibility, overridable = overridable, api = api, pos = pos)
              else:
-                 error(pos, "undeclared name not builtin: %s" % name)
+                 if Options.error_on_unknown_names:
+                     error(pos, "undeclared name not builtin: %s" % name)
+                 else:
+                     warning(pos, "undeclared name not builtin: %s" % name, 2)
  
 -    def declare_builtin_cfunction(self, name, type, cname, python_equiv = None,
 -            utility_code = None):
 +    def declare_builtin_cfunction(self, name, cname = None, namespace = None, c_visibility = 'private', visibility = 'public', overridable = 0, api = 0, type = None, python_equiv = None,
 +                                  utility_code = None):
          # If python_equiv == "*", the Python equivalent has the same name
          # as the entry, otherwise it has the name specified by python_equiv.
          name = EncodedString(name)
@@@ -932,34 -920,40 +949,42 @@@ class ModuleScope(Scope)
              return entry
          return self.outer_scope.lookup(name, language_level = self.context.language_level)
  
 -    def declare_builtin(self, name, pos):
 +    def declare_builtin(self, name, cname = None, namespace = None, c_visibility = 'private', visibility = 'public', overridable = 0, api = 0, pos = None):
-         if (not hasattr(builtins, name)
-             and name != 'xrange'):
-             # 'xrange' is special cased in Code.py
+         if not hasattr(builtins, name) \
+                and name not in Code.non_portable_builtins_map \
+                and name not in Code.uncachable_builtins:
              if self.has_import_star:
 -                entry = self.declare_var(name, py_object_type, pos)
 +                entry = self.declare_var(name = name, cname = cname, namespace = namespace, c_visibility = c_visibility, visibility = visibility, overridable = overridable, api = api, type = py_object_type, pos = pos)
                  return entry
 +            elif self.outer_scope is not None:
 +                return self.outer_scope.declare_builtin(name = name, cname = cname, namespace = namespace, c_visibility = c_visibility, visibility = visibility, overridable = overridable, api = api, pos = pos)
              else:
-                 error(pos, "undeclared name not builtin: %s"%name)
+                 if Options.error_on_unknown_names:
+                     error(pos, "undeclared name not builtin: %s" % name)
+                 else:
+                     warning(pos, "undeclared name not builtin: %s" % name, 2)
+                 # unknown - assume it's builtin and look it up at runtime
+                 entry = self.declare(name, None, py_object_type, pos, 'private')
+                 entry.is_builtin = 1
+                 return entry
          if Options.cache_builtins:
              for entry in self.cached_builtins:
                  if entry.name == name:
                      return entry
 -        entry = self.declare(None, None, py_object_type, pos, 'private')
 +        entry = self.declare(type = py_object_type, pos = pos)
-         if Options.cache_builtins:
+         if Options.cache_builtins and name not in Code.uncachable_builtins:
              entry.is_builtin = 1
-             entry.is_const = 1
+             entry.is_const = 1 # cached
              entry.name = name
              entry.cname = Naming.builtin_prefix + name
              self.cached_builtins.append(entry)
              self.undeclared_cached_builtins.append(entry)
          else:
              entry.is_builtin = 1
+             entry.name = name
          return entry
  
 -    def find_module(self, module_name, pos):
 +    def find_module(self, module_name, pos = None):
          # Find a module in the import namespace, interpreting
          # relative imports relative to this module's parent.
          # Finds and parses the module's .pxd file if the module
          # If this is a non-extern typedef class, expose the typedef, but use
          # the non-typedef struct internally to avoid needing forward
          # declarations for anonymous structs.
 -        if typedef_flag and visibility != 'extern':
 -            if not (visibility == 'public' or api):
 +        if typedef_flag and c_visibility != 'extern':
-             if c_visibility != 'public':
-                 warning(pos, "ctypedef only valid for public and extern classes", 2)
++            if not (c_visibility == 'public' or api):
+                 warning(pos, "ctypedef only valid for 'extern' , 'public', and 'api'", 2)
              objtypedef_cname = objstruct_cname
              typedef_flag = 0
          else:
@@@ -1387,9 -1388,10 +1423,9 @@@ class GeneratorExpressionScope(Scope)
          self.genexp_prefix = "%s%d%s" % (Naming.pyrex_prefix, len(name), name)
  
      def mangle(self, prefix, name):
-         return '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(self, prefix, name))
+         return '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(prefix, name))
  
 -    def declare_var(self, name, type, pos,
 -                    cname = None, visibility = 'private', api = 0, is_cdef = True):
 +    def declare_var(self, name, cname = None, namespace = None, c_visibility = 'private', visibility = 'public', overridable = 0, api = 0, type = None, is_cdef = 0, pos = None):
          if type is unspecified_type:
              # if the outer scope defines a type for this variable, inherit it
              outer_entry = self.outer_scope.lookup(name)
          self.entries[name] = entry
          return entry
  
 -    def declare_lambda_function(self, func_cname, pos):
 -        return self.outer_scope.declare_lambda_function(func_cname, pos)
++    def declare_lambda_function(self, name = None, cname = None, namespace = None, c_visibility = 'private', visibility = 'public', overridable = 0, api = 0, pos = None):
++        return self.outer_scope.declare_lambda_function(
++            name = name, cname = cname, namespace = namespace,
++            c_visibility = c_visibility, visibility = visibility,
++            overridable = overridable, api = api, pos = pos)
+     def add_lambda_def(self, def_node):
+         return self.outer_scope.add_lambda_def(def_node)
  
  class ClosureScope(LocalScope):
  
@@@ -1497,9 -1511,9 +1542,9 @@@ class PyClassScope(ClassScope)
          if type is unspecified_type:
              type = py_object_type
          # Add an entry for a class attribute.
 -        entry = Scope.declare_var(self, name, type, pos,
 -                                  cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
 +        entry = Scope.declare_var(
 +            self, name, cname = None, namespace = None, c_visibility = 'private', visibility = 'public', overridable = 0, api = 0, type = type, is_cdef = is_cdef, pos = pos)
-         entry.is_pyglobal = 1
+         entry.is_pyglobal = 1 # FIXME: WTF?
          entry.is_pyclass_attr = 1
          return entry
  
@@@ -1595,9 -1627,8 +1654,7 @@@ class CClassScope(ClassScope)
          if name == "__new__":
              error(pos, "__new__ method of extension type will change semantics "
                  "in a future version of Pyrex and Cython. Use __cinit__ instead.")
-         if c_visibility != 'extern':
-             error(pos, "C class pyfunctions may only be extern")
 -        entry = self.declare_var(name, py_object_type, pos,
 -                                 visibility='extern')
 +        entry = self.declare_var(name = name, cname = cname, namespace = namespace, c_visibility = c_visibility, visibility = visibility, overridable = overridable, api = api, type = py_object_type, pos = pos)
          special_sig = get_special_method_signature(name)
          if special_sig:
              # Special methods get put in the method table with a particular
diff --cc runtests.py
index 3436d473a081890eeb7e658d963c483afbfd22f6,d565aed1c9497128c3df274b2fedc183b8cb3a21..b241fbc90c568c1c6d9c09b12c38d7446a7de117
@@@ -510,64 -601,70 +601,70 @@@ class CythonRunTestCase(CythonCompileTe
              self.run_doctests(self.module, result)
  
      def run_doctests(self, module_name, result):
-         if sys.version_info[0] >= 3 or not hasattr(os, 'fork') or not self.fork:
-             doctest.DocTestSuite(module_name).run(result)
-             gc.collect()
-             return
-         # fork to make sure we do not keep the tested module loaded
-         result_handle, result_file = tempfile.mkstemp()
-         os.close(result_handle)
-         child_id = os.fork()
-         if not child_id:
-             result_code = 0
-             try:
-                 try:
-                     tests = None
-                     try:
-                         partial_result = PartialTestResult(result)
-                         tests = doctest.DocTestSuite(module_name)
-                         tests.run(partial_result)
-                         gc.collect()
-                     except Exception:
-                         if tests is None:
-                             # importing failed, try to fake a test class
-                             tests = _FakeClass(
-                                 failureException=sys.exc_info()[1],
-                                 _shortDescription=self.shortDescription(),
-                                 module_name=None)
-                         partial_result.addError(tests, sys.exc_info())
-                         result_code = 1
-                     output = open(result_file, 'wb')
-                     pickle.dump(partial_result.data(), output)
-                 except:
-                     traceback.print_exc()
-             finally:
-                 try: output.close()
-                 except: pass
-                 os._exit(result_code)
+         def run_test(result):
+             tests = doctest.DocTestSuite(module_name)
+             tests.run(result)
+         run_forked_test(result, run_test, self.shortDescription(), self.fork)
  
+ def run_forked_test(result, run_func, test_name, fork=True):
+     if not fork or sys.version_info[0] >= 3 or not hasattr(os, 'fork'):
+         run_func(result)
+         gc.collect()
+         return
+     # fork to make sure we do not keep the tested module loaded
+     result_handle, result_file = tempfile.mkstemp()
+     os.close(result_handle)
+     child_id = os.fork()
+     if not child_id:
+         result_code = 0
          try:
-             cid, result_code = os.waitpid(child_id, 0)
-             # os.waitpid returns the child's result code in the
-             # upper byte of result_code, and the signal it was
-             # killed by in the lower byte
-             if result_code & 255:
-                 raise Exception("Tests in module '%s' were unexpectedly killed by signal %d"%
-                                 (module_name, result_code & 255))
-             result_code = result_code >> 8
-             if result_code in (0,1):
-                 input = open(result_file, 'rb')
+             try:
+                 tests = None
                  try:
-                     PartialTestResult.join_results(result, pickle.load(input))
-                 finally:
-                     input.close()
-             if result_code:
-                 raise Exception("Tests in module '%s' exited with status %d" %
-                                 (module_name, result_code))
+                     partial_result = PartialTestResult(result)
+                     run_func(partial_result)
+                     gc.collect()
+                 except Exception:
+                     if tests is None:
+                         # importing failed, try to fake a test class
+                         tests = _FakeClass(
+                             failureException=sys.exc_info()[1],
+                             _shortDescription=test_name,
+                             module_name=None)
+                     partial_result.addError(tests, sys.exc_info())
+                     result_code = 1
+                 output = open(result_file, 'wb')
+                 pickle.dump(partial_result.data(), output)
+             except:
+                 traceback.print_exc()
          finally:
-             try: os.unlink(result_file)
+             try: output.close()
              except: pass
 -            raise Exception("Tests in module '%s' were unexpectedly killed by signal %d"%
 -                            (module_name, result_code & 255))
+             os._exit(result_code)
+     try:
+         cid, result_code = os.waitpid(child_id, 0)
+         # os.waitpid returns the child's result code in the
+         # upper byte of result_code, and the signal it was
+         # killed by in the lower byte
+         if result_code & 255:
 -            raise Exception("Tests in module '%s' exited with status %d" %
 -                            (module_name, result_code))
++            raise Exception("Test '%s' was unexpectedly killed by signal %d"%
++                            (test_name, result_code & 255))
+         result_code = result_code >> 8
+         if result_code in (0,1):
+             input = open(result_file, 'rb')
+             try:
+                 PartialTestResult.join_results(result, pickle.load(input))
+             finally:
+                 input.close()
+         if result_code:
++            raise Exception("Test '%s' exited with status %d" %
++                            (test_name, result_code))
+     finally:
+         try: os.unlink(result_file)
+         except: pass
  
  class PureDoctestTestCase(unittest.TestCase):
      def __init__(self, module_name, module_path):
index 5db6b3e02bd7bb6be3b8e40baa1368b7620852d1,7eec85f759568d4e51c81b2560d690b1be976fd3..38654775852a4851947ccc0d5d0bd2efa087246f
@@@ -1,8 -1,6 +1,10 @@@
+ # mode: compile
  cdef class A:
 +    cdef public int i
 +    cdef readonly int j
 +    cdef void *ptr
 +
      cpdef a(self):
          ma(self)
  
index 0d11207d7b8a3b07c6c5c50915aa733f307c4f99,c7c02222dc155d2b1b8275fed8b3d639040e03bc..82f7e40c8d0799716d66f9a2c45f10028fa5152b
@@@ -11,7 -12,7 +12,7 @@@ cdef class MyStr(str): # only in Py2, b
      pass
  
  _ERRORS = """
- 4:0: inheritance from PyVarObject types like 'tuple' is not currently supported
- 7:0: inheritance from PyVarObject types like 'bytes' is not currently supported
- 10:0: inheritance from PyVarObject types like 'str' is not currently supported
 -5:5: inheritance from PyVarObject types like 'tuple' is not currently supported
 -8:5: inheritance from PyVarObject types like 'bytes' is not currently supported
 -11:5: inheritance from PyVarObject types like 'str' is not currently supported
++5:0: inheritance from PyVarObject types like 'tuple' is not currently supported
++8:0: inheritance from PyVarObject types like 'bytes' is not currently supported
++11:0: inheritance from PyVarObject types like 'str' is not currently supported
  """
index 9867aca69d70eda22dc85b44a7324baf628eca09,0b7dfe38087916f527baaad5a665ce221b698c8c..2e5d54adcfb360af677cad06e3e54dd2aa716058
@@@ -15,11 -18,12 +18,11 @@@ cdef class Bar
      pass
  
  _ERRORS = u"""
- 5:24: C attribute of type 'VoidP' cannot be accessed from Python
- 5:24: Cannot convert 'VoidP' to Python object
- 6:24: C attribute of type 'VoidP' cannot be accessed from Python
- 6:24: Cannot convert 'VoidP' to Python object
- 6:24: Cannot convert Python object to 'VoidP'
- 14:22: Cannot convert Python object to 'Foo'
+ 8:24: C attribute of type 'VoidP' cannot be accessed from Python
+ 8:24: Cannot convert 'VoidP' to Python object
+ 9:24: C attribute of type 'VoidP' cannot be accessed from Python
+ 9:24: Cannot convert 'VoidP' to Python object
+ 9:24: Cannot convert Python object to 'VoidP'
 -17:22: C attribute of type 'Foo' cannot be accessed from Python
+ 17:22: Cannot convert Python object to 'Foo'
  """
  
index ff3664ae0980c21054870d9ac0453472acba15ff,0000000000000000000000000000000000000000..c7f49fb398002e80da96397329e1501a0d7ac00c
mode 100644,000000..100644
--- /dev/null
@@@ -1,38 -1,0 +1,40 @@@
- 3:17: Syntax error in C variable declaration
++# mode: error
++
 +# TODO: a way to keep going after parsing errors?
 +
 +cdef private int priv_global_variable
 +
 +cdef private priv_global_function(x):
 +    return x*2
 +
 +
 +cdef class bare_global_class:
 +    cdef private int priv_attribute
 +
 +    def __cinit__(self):
 +        self.priv_attribute = 1
 +
 +
 +cdef class public pub_global_class:
 +    cpdef cp_method(self, x):
 +        return x*2
 +
 +
 +cdef class private priv_global_class:
 +    cpdef cp_method(self, x):
 +        return x*2
 +
 +
 +cdef class readonly ro_global_class:
 +    cpdef cp_method(self, x):
 +        return x*2
 +
 +
 +cpdef class cp_global_class:
 +    cpdef cp_method(self, x):
 +        return x*2
 +
 +
 +_ERRORS = u"""
++5:17: Syntax error in C variable declaration
 +"""
index f942006c5ace63ba03023a983384130979418ba3,0998856aaf36a266fd9a29d76f7325b2277de259..f0243b11740c9fd6dc028e3e1c3faddd6fc8008d
@@@ -7,6 -8,6 +8,6 @@@ cdef class Test
          pass
  
  _ERRORS = u"""
- 3:4: Special methods must be declared with 'def', not 'cdef'
- 6:4: Special methods must be declared with 'def', not 'cdef'
 -4:9: Special methods must be declared with 'def', not 'cdef'
 -7:9: Special methods must be declared with 'def', not 'cdef'
++4:4: Special methods must be declared with 'def', not 'cdef'
++7:4: Special methods must be declared with 'def', not 'cdef'
  """
index fbbafe2dc1741fad74cfdff9a9b323cea711f4aa,9e309f16f47e966559aeff969dd675c270943165..c9be278258712b8b7ce573a506736aa9ccef6688
@@@ -7,6 -9,6 +9,6 @@@ cdef class D(C)
          pass
  
  _ERRORS = u"""
- 6: 4: Signature not compatible with previous declaration
- 2: 4: Previous declaration is here
 -8: 9: Signature not compatible with previous declaration
 -4: 9: Previous declaration is here
++8: 4: Signature not compatible with previous declaration
++4: 4: Previous declaration is here
  """
index 569750d3d06e45c26459efb6ca1b8a7a173157e2,7c60881359a0436cfe865f0a4651f5c1b48b29c4..c4e140bbcd9d6693d201d4fd2e974941e991354e
@@@ -3,7 -4,7 +4,7 @@@ cpdef nogil: pas
  cpdef nogil class test: pass
  
  _ERRORS = u"""
-  2: 0: cdef blocks cannot be declared cpdef
-  3: 0: cdef blocks cannot be declared cpdef
-  3:12: Expected ':', found 'class'
 -3: 6: cdef blocks cannot be declared cpdef
 -4: 6: cdef blocks cannot be declared cpdef
++3: 0: cdef blocks cannot be declared cpdef
++4: 0: cdef blocks cannot be declared cpdef
+ 4:12: Expected ':', found 'class'
  """
index 5ed134979da0717ffb5124a8559cf5b8742eb213,f71370f4a1e41c54ca3a374375ba380e69d430c3..22ec012a625e6726d47b43b84f4064952e8d9818
@@@ -7,7 -9,7 +9,7 @@@ ctypedef union eggs
  cdef enum ham:
        pass
  _ERRORS = u"""
- 1:0: Empty struct or union definition not allowed outside a 'cdef extern from' block
- 4:0: Empty struct or union definition not allowed outside a 'cdef extern from' block
- 7:0: Empty enum definition not allowed outside a 'cdef extern from' block
 -3:5: Empty struct or union definition not allowed outside a 'cdef extern from' block
++3:0: Empty struct or union definition not allowed outside a 'cdef extern from' block
+ 6:0: Empty struct or union definition not allowed outside a 'cdef extern from' block
 -9:5: Empty enum definition not allowed outside a 'cdef extern from' block
++9:0: Empty enum definition not allowed outside a 'cdef extern from' block
  """
index 271421dc247a3d4d1c394302c65a3b099791f13c,45651f90644fbc4f2139791d7059bf5c1145bedf..24afed5c3012778d773e9f5e814bcd5ea06d0be0
@@@ -6,6 -8,6 +8,6 @@@ cdef class D(C)
        cdef void f(self, int x):
                pass
  _ERRORS = u"""
- 6:1: Signature not compatible with previous declaration
- 2:1: Previous declaration is here
 -8:6: Signature not compatible with previous declaration
 -4:6: Previous declaration is here
++8:1: Signature not compatible with previous declaration
++4:1: Previous declaration is here
  """
index 1d8396b4cb64bc838adfa8a5b153905eaf0dec6a,67563099fe052e0d4af7ced07b966864364f624a..bfe17cd53cd5635afc81254e896d15595f607de4
@@@ -12,6 -14,6 +14,6 @@@ cdef Foo 
  cdef Blarg b
  
  _ERRORS = u"""
- 3:0: 'Foo' previously declared using 'cdef'
- 9:0: 'Blarg' previously declared using 'ctypedef'
+ 5:0: 'Foo' previously declared using 'cdef'
 -11:5: 'Blarg' previously declared using 'ctypedef'
++11:0: 'Blarg' previously declared using 'ctypedef'
  """
Simple merge
index 6f4cb6ee7bb876c3dd361aa0b748230c5117003a,02ab59b4b8a1f4835cf2f54eefd80cab02477d3f..5708bc6560c59d81a8ca96202d1b5ed00433aafd
@@@ -3,6 -5,6 +5,6 @@@ cdef class C
                pass
  
  _ERRORS = u"""
- 2:1: Signature not compatible with previous declaration
  2:12: Previous declaration is here
 -4: 6: Signature not compatible with previous declaration
++4: 1: Signature not compatible with previous declaration
  """
index 8a3ef5e6f11963511172440e8a0b8d6ceadfec59,cf2df11fd54e0aa496ab882133a0a5001628fab9..078f606642664b01ee514ff4de3e8b7d3076d1a9
@@@ -3,5 -6,5 +6,5 @@@ cdef extern
          char a
  
  _ERRORS = u"""
- 2:4: Cannot declare extern struct as 'packed'
 -5:9: Cannot declare extern struct as 'packed'
++5:4: Cannot declare extern struct as 'packed'
  """
index 0a9f6a9bdc964d192d0150eede5c8ca02d465de1,3a68f8b3cc94668847d4cbb84339a4e934055264..9f732a09afdd81f55ac9f71d883b2df87f4f1583
@@@ -1,6 -3,6 +3,6 @@@
  cdef class Spam
  cdef extern class external.Eggs
  _ERRORS = u"""
- 1:0: C class 'Spam' is declared but not defined
- 2:0: C class 'Eggs' is declared but not defined
 -3:5: C class 'Spam' is declared but not defined
 -4:5: C class 'Eggs' is declared but not defined
++3:0: C class 'Spam' is declared but not defined
++4:0: C class 'Eggs' is declared but not defined
  """
index 3fbb7f6d039f33247c56fb40e38024f06caa03eb,21241a2210f986afda2206ff392fbf8fb39158fb..3b621b35458e7924195ade4849ad050aba6a2bb0
@@@ -4,5 -6,5 +6,5 @@@ cdef class B
          pass
  
  _ERRORS = u"""
- 3:4: C method has no self argument
 -5:10: C method has no self argument
++5:4: C method has no self argument
  """
index 89fc19475651f0266aa058b12b24e5385bef85b4,6a95922d53232982c9d07baa1316babaaf553310..3a0223e929dbeff3f18c00308b8182e969e7f809
@@@ -4,5 -6,5 +6,5 @@@ cdef class A
          pass
  
  _ERRORS = u"""
- 3:4: Self argument (int) of C method 'a' does not match parent type (A)
 -5:10: Self argument (int) of C method 'a' does not match parent type (A)
++5:4: Self argument (int) of C method 'a' does not match parent type (A)
  """
index 1e85d08d6283bef38455a6d5ae5ed5dc7c3a83f1,512e1b67d164ca589dea13b15058516c3fd02877..e7bb672be4383783aee8ab222d98272295f5749b
@@@ -90,71 -92,71 +92,72 @@@ def bare_pyvar_name(object x)
  # except these: 29, 34, 44, 56, 58, 60, 62-64
  
  _ERRORS = u"""
- 1:0: Function with Python return type cannot be declared nogil
- 4:0: Function declared nogil has Python locals or temporaries
- 6:6: Assignment of Python object not allowed without gil
- 9:5: Discarding owned Python object not allowed without gil
- 11:0: Function with Python return type cannot be declared nogil
- 15:5: Calling gil-requiring function not allowed without gil
- 24:9: Calling gil-requiring function not allowed without gil
- 26:12: Assignment of Python object not allowed without gil
- 28:8: Discarding owned Python object not allowed without gil
- 28:16: Constructing complex number not allowed without gil
- 30:8: Backquote expression not allowed without gil
 -3:5: Function with Python return type cannot be declared nogil
 -6:5: Function declared nogil has Python locals or temporaries
++<<<<<<< HEAD
++3:0: Function with Python return type cannot be declared nogil
++6:0: Function declared nogil has Python locals or temporaries
+ 8:6: Assignment of Python object not allowed without gil
+ 11:5: Discarding owned Python object not allowed without gil
 -13:5: Function with Python return type cannot be declared nogil
++13:0: Function with Python return type cannot be declared nogil
+ 17:5: Calling gil-requiring function not allowed without gil
+ 26:9: Calling gil-requiring function not allowed without gil
+ 28:12: Assignment of Python object not allowed without gil
  30:8: Discarding owned Python object not allowed without gil
- 30:9: Operation not allowed without gil
- 31:15: Assignment of Python object not allowed without gil
- 31:15: Operation not allowed without gil
- 31:15: Python import not allowed without gil
- 32:8: Operation not allowed without gil
- 32:13: Python import not allowed without gil
- 32:25: Constructing Python list not allowed without gil
- 32:25: Operation not allowed without gil
- 33:17: Iterating over Python object not allowed without gil
- 35:11: Discarding owned Python object not allowed without gil
- 35:11: Indexing Python object not allowed without gil
- 36:11: Discarding owned Python object not allowed without gil
- 36:11: Slicing Python object not allowed without gil
- 37:11: Constructing Python slice object not allowed without gil
+ 30:16: Constructing complex number not allowed without gil
+ 32:8: Backquote expression not allowed without gil
+ 32:8: Discarding owned Python object not allowed without gil
+ 32:9: Operation not allowed without gil
+ 33:15: Assignment of Python object not allowed without gil
+ 33:15: Operation not allowed without gil
+ 33:15: Python import not allowed without gil
+ 34:8: Operation not allowed without gil
+ 34:13: Python import not allowed without gil
+ 34:25: Constructing Python list not allowed without gil
+ 34:25: Operation not allowed without gil
+ 35:17: Iterating over Python object not allowed without gil
  37:11: Discarding owned Python object not allowed without gil
  37:11: Indexing Python object not allowed without gil
- 37:13: Converting to Python object not allowed without gil
- 37:15: Converting to Python object not allowed without gil
- 37:17: Converting to Python object not allowed without gil
- 38:11: Accessing Python attribute not allowed without gil
  38:11: Discarding owned Python object not allowed without gil
- 39:9: Constructing Python tuple not allowed without gil
- 39:9: Discarding owned Python object not allowed without gil
- 40:8: Constructing Python list not allowed without gil
- 40:8: Discarding owned Python object not allowed without gil
- 41:8: Constructing Python dict not allowed without gil
- 41:8: Discarding owned Python object not allowed without gil
- 42:12: Discarding owned Python object not allowed without gil
- 42:12: Truth-testing Python object not allowed without gil
- 43:13: Python type test not allowed without gil
- 45:10: Discarding owned Python object not allowed without gil
- 45:10: Operation not allowed without gil
- 46:8: Discarding owned Python object not allowed without gil
- 46:8: Operation not allowed without gil
- 47:10: Assignment of Python object not allowed without gil
- 47:14: Assignment of Python object not allowed without gil
- 48:9: Assignment of Python object not allowed without gil
- 48:13: Assignment of Python object not allowed without gil
- 48:16: Creating temporary Python reference not allowed without gil
- 48:19: Creating temporary Python reference not allowed without gil
- 49:11: Assignment of Python object not allowed without gil
- 49:11: Indexing Python object not allowed without gil
- 50:11: Accessing Python attribute not allowed without gil
- 50:11: Assignment of Python object not allowed without gil
- 51:8: Constructing Python tuple not allowed without gil
- 51:8: Python print statement not allowed without gil
- 52:8: Deleting Python object not allowed without gil
- 53:8: Returning Python object not allowed without gil
- 54:8: Raising exception not allowed without gil
- 55:14: Truth-testing Python object not allowed without gil
- 57:17: Truth-testing Python object not allowed without gil
- 59:8: For-loop using object bounds or target not allowed without gil
- 61:8: Try-except statement not allowed without gil
- 65:8: Try-finally statement not allowed without gil
- 82:8: For-loop using object bounds or target not allowed without gil
+ 38:11: Slicing Python object not allowed without gil
+ 39:11: Constructing Python slice object not allowed without gil
+ 39:11: Discarding owned Python object not allowed without gil
+ 39:11: Indexing Python object not allowed without gil
+ 39:13: Converting to Python object not allowed without gil
+ 39:15: Converting to Python object not allowed without gil
+ 39:17: Converting to Python object not allowed without gil
+ 40:11: Accessing Python attribute not allowed without gil
+ 40:11: Discarding owned Python object not allowed without gil
+ 41:9: Constructing Python tuple not allowed without gil
+ 41:9: Discarding owned Python object not allowed without gil
+ 42:8: Constructing Python list not allowed without gil
+ 42:8: Discarding owned Python object not allowed without gil
+ 43:8: Constructing Python dict not allowed without gil
+ 43:8: Discarding owned Python object not allowed without gil
+ 44:12: Discarding owned Python object not allowed without gil
+ 44:12: Truth-testing Python object not allowed without gil
+ 45:13: Python type test not allowed without gil
+ 47:10: Discarding owned Python object not allowed without gil
+ 47:10: Operation not allowed without gil
+ 48:8: Discarding owned Python object not allowed without gil
+ 48:8: Operation not allowed without gil
+ 49:10: Assignment of Python object not allowed without gil
+ 49:14: Assignment of Python object not allowed without gil
+ 50:9: Assignment of Python object not allowed without gil
+ 50:13: Assignment of Python object not allowed without gil
+ 50:16: Creating temporary Python reference not allowed without gil
+ 50:19: Creating temporary Python reference not allowed without gil
+ 51:11: Assignment of Python object not allowed without gil
+ 51:11: Indexing Python object not allowed without gil
+ 52:11: Accessing Python attribute not allowed without gil
+ 52:11: Assignment of Python object not allowed without gil
+ 53:8: Constructing Python tuple not allowed without gil
+ 53:8: Python print statement not allowed without gil
+ 54:8: Deleting Python object not allowed without gil
+ 55:8: Returning Python object not allowed without gil
+ 56:8: Raising exception not allowed without gil
+ 57:14: Truth-testing Python object not allowed without gil
+ 59:17: Truth-testing Python object not allowed without gil
+ 61:8: For-loop using object bounds or target not allowed without gil
+ 63:8: Try-except statement not allowed without gil
+ 67:8: Try-finally statement not allowed without gil
+ 84:8: For-loop using object bounds or target not allowed without gil
  """
index 77327b23552861ae973af7cd5cf64d6d359d24e9,c2c2cc3c9538e1a11c29b2dc81eb60db39365239..4eb36f9b7a4518b32deff83f3b9f9b102abb3880
@@@ -3,6 -5,6 +5,6 @@@ cdef class C
          pass
  
  _ERRORS = u"""
- 2:4: Signature not compatible with previous declaration
  2:15: Previous declaration is here
 -4:9: Signature not compatible with previous declaration
++4:4: Signature not compatible with previous declaration
  """
index ac16fbe8f08fc1b0a14c4f2d4473a7a4197d9c8d,05c5a9e9ed1b58f63933615564b2bf5d2bc57835..434de1b19d36e242c762fd0974746d1c6fcc45e8
@@@ -9,5 -10,5 +10,5 @@@ cdef class SubType(FinalClass)
      pass
  
  _ERRORS = """
- 8:0: Base class 'FinalClass' of type 'SubType' is final
 -9:5: Base class 'FinalClass' of type 'SubType' is final
++9:0: Base class 'FinalClass' of type 'SubType' is final
  """
Simple merge