1#
2#   Parse tree nodes
3#
4
5from __future__ import absolute_import
6
7import cython
8cython.declare(sys=object, os=object, copy=object,
9               Builtin=object, error=object, warning=object, Naming=object, PyrexTypes=object,
10               py_object_type=object, ModuleScope=object, LocalScope=object, ClosureScope=object,
11               StructOrUnionScope=object, PyClassScope=object,
12               CppClassScope=object, UtilityCode=object, EncodedString=object,
13               error_type=object, _py_int_types=object)
14
15import sys, os, copy
16from itertools import chain
17
18from . import Builtin
19from .Errors import error, warning, InternalError, CompileError
20from . import Naming
21from . import PyrexTypes
22from . import TypeSlots
23from .PyrexTypes import py_object_type, error_type
24from .Symtab import (ModuleScope, LocalScope, ClosureScope,
25                     StructOrUnionScope, PyClassScope, CppClassScope, TemplateScope)
26from .Code import UtilityCode
27from .StringEncoding import EncodedString
28from . import Future
29from . import Options
30from . import DebugFlags
31from .Pythran import has_np_pythran, pythran_type, is_pythran_buffer
32from ..Utils import add_metaclass
33
34
35if sys.version_info[0] >= 3:
36    _py_int_types = int
37else:
38    _py_int_types = (int, long)
39
40
41def relative_position(pos):
42    return (pos[0].get_filenametable_entry(), pos[1])
43
44
45def embed_position(pos, docstring):
46    if not Options.embed_pos_in_docstring:
47        return docstring
48    pos_line = u'File: %s (starting at line %s)' % relative_position(pos)
49    if docstring is None:
50        # unicode string
51        return EncodedString(pos_line)
52
53    # make sure we can encode the filename in the docstring encoding
54    # otherwise make the docstring a unicode string
55    encoding = docstring.encoding
56    if encoding is not None:
57        try:
58            pos_line.encode(encoding)
59        except UnicodeEncodeError:
60            encoding = None
61
62    if not docstring:
63        # reuse the string encoding of the original docstring
64        doc = EncodedString(pos_line)
65    else:
66        doc = EncodedString(pos_line + u'\n' + docstring)
67    doc.encoding = encoding
68    return doc
69
70
71def analyse_type_annotation(annotation, env, assigned_value=None):
72    base_type = None
73    is_ambiguous = False
74    explicit_pytype = explicit_ctype = False
75    if annotation.is_dict_literal:
76        warning(annotation.pos,
77                "Dicts should no longer be used as type annotations. Use 'cython.int' etc. directly.")
78        for name, value in annotation.key_value_pairs:
79            if not name.is_string_literal:
80                continue
81            if name.value in ('type', b'type'):
82                explicit_pytype = True
83                if not explicit_ctype:
84                    annotation = value
85            elif name.value in ('ctype', b'ctype'):
86                explicit_ctype = True
87                annotation = value
88        if explicit_pytype and explicit_ctype:
89            warning(annotation.pos, "Duplicate type declarations found in signature annotation")
90    arg_type = annotation.analyse_as_type(env)
91    if annotation.is_name and not annotation.cython_attribute and annotation.name in ('int', 'long', 'float'):
92        # Map builtin numeric Python types to C types in safe cases.
93        if assigned_value is not None and arg_type is not None and not arg_type.is_pyobject:
94            assigned_type = assigned_value.infer_type(env)
95            if assigned_type and assigned_type.is_pyobject:
96                # C type seems unsafe, e.g. due to 'None' default value  => ignore annotation type
97                is_ambiguous = True
98                arg_type = None
99        # ignore 'int' and require 'cython.int' to avoid unsafe integer declarations
100        if arg_type in (PyrexTypes.c_long_type, PyrexTypes.c_int_type, PyrexTypes.c_float_type):
101            arg_type = PyrexTypes.c_double_type if annotation.name == 'float' else py_object_type
102    elif arg_type is not None and annotation.is_string_literal:
103        warning(annotation.pos,
104                "Strings should no longer be used for type declarations. Use 'cython.int' etc. directly.")
105    if arg_type is not None:
106        if explicit_pytype and not explicit_ctype and not arg_type.is_pyobject:
107            warning(annotation.pos,
108                    "Python type declaration in signature annotation does not refer to a Python type")
109        base_type = CAnalysedBaseTypeNode(
110            annotation.pos, type=arg_type, is_arg=True)
111    elif is_ambiguous:
112        warning(annotation.pos, "Ambiguous types in annotation, ignoring")
113    else:
114        warning(annotation.pos, "Unknown type declaration in annotation, ignoring")
115    return base_type, arg_type
116
117
118def write_func_call(func, codewriter_class):
119    def f(*args, **kwds):
120        if len(args) > 1 and isinstance(args[1], codewriter_class):
121            # here we annotate the code with this function call
122            # but only if new code is generated
123            node, code = args[:2]
124            marker = '                    /* %s -> %s.%s %s */' % (
125                ' ' * code.call_level,
126                node.__class__.__name__,
127                func.__name__,
128                node.pos[1:])
129            pristine = code.buffer.stream.tell()
130            code.putln(marker)
131            start = code.buffer.stream.tell()
132            code.call_level += 4
133            res = func(*args, **kwds)
134            code.call_level -= 4
135            if start == code.buffer.stream.tell():
136                # no code written => undo writing marker
137                code.buffer.stream.truncate(pristine)
138            else:
139                marker = marker.replace('->', '<-', 1)
140                code.putln(marker)
141            return res
142        else:
143            return func(*args, **kwds)
144    return f
145
146
147class VerboseCodeWriter(type):
148    # Set this as a metaclass to trace function calls in code.
149    # This slows down code generation and makes much larger files.
150    def __new__(cls, name, bases, attrs):
151        from types import FunctionType
152        from .Code import CCodeWriter
153        attrs = dict(attrs)
154        for mname, m in attrs.items():
155            if isinstance(m, FunctionType):
156                attrs[mname] = write_func_call(m, CCodeWriter)
157        return super(VerboseCodeWriter, cls).__new__(cls, name, bases, attrs)
158
159
160class CheckAnalysers(type):
161    """Metaclass to check that type analysis functions return a node.
162    """
163    methods = set(['analyse_types',
164                   'analyse_expressions',
165                   'analyse_target_types'])
166
167    def __new__(cls, name, bases, attrs):
168        from types import FunctionType
169        def check(name, func):
170            def call(*args, **kwargs):
171                retval = func(*args, **kwargs)
172                if retval is None:
173                    print('%s %s %s' % (name, args, kwargs))
174                return retval
175            return call
176
177        attrs = dict(attrs)
178        for mname, m in attrs.items():
179            if isinstance(m, FunctionType) and mname in cls.methods:
180                attrs[mname] = check(mname, m)
181        return super(CheckAnalysers, cls).__new__(cls, name, bases, attrs)
182
183
184def _with_metaclass(cls):
185    if DebugFlags.debug_trace_code_generation:
186        return add_metaclass(VerboseCodeWriter)(cls)
187    #return add_metaclass(CheckAnalysers)(cls)
188    return cls
189
190
191@_with_metaclass
192class Node(object):
193    #  pos         (string, int, int)   Source file position
194    #  is_name     boolean              Is a NameNode
195    #  is_literal  boolean              Is a ConstNode
196
197    is_name = 0
198    is_none = 0
199    is_nonecheck = 0
200    is_literal = 0
201    is_terminator = 0
202    is_wrapper = False  # is a DefNode wrapper for a C function
203    temps = None
204
205    # All descendants should set child_attrs to a list of the attributes
206    # containing nodes considered "children" in the tree. Each such attribute
207    # can either contain a single node or a list of nodes. See Visitor.py.
208    child_attrs = None
209
210    # Subset of attributes that are evaluated in the outer scope (e.g. function default arguments).
211    outer_attrs = None
212
213    cf_state = None
214
215    # This may be an additional (or 'actual') type that will be checked when
216    # this node is coerced to another type. This could be useful to set when
217    # the actual type to which it can coerce is known, but you want to leave
218    # the type a py_object_type
219    coercion_type = None
220
221    def __init__(self, pos, **kw):
222        self.pos = pos
223        self.__dict__.update(kw)
224
225    gil_message = "Operation"
226
227    nogil_check = None
228    in_nogil_context = False  # For use only during code generation.
229
230    def gil_error(self, env=None):
231        error(self.pos, "%s not allowed without gil" % self.gil_message)
232
233    cpp_message = "Operation"
234
235    def cpp_check(self, env):
236        if not env.is_cpp():
237            self.cpp_error()
238
239    def cpp_error(self):
240        error(self.pos, "%s only allowed in c++" % self.cpp_message)
241
242    def clone_node(self):
243        """Clone the node. This is defined as a shallow copy, except for member lists
244           amongst the child attributes (from get_child_accessors) which are also
245           copied. Lists containing child nodes are thus seen as a way for the node
246           to hold multiple children directly; the list is not treated as a separate
247           level in the tree."""
248        result = copy.copy(self)
249        for attrname in result.child_attrs:
250            value = getattr(result, attrname)
251            if isinstance(value, list):
252                setattr(result, attrname, [x for x in value])
253        return result
254
255
256    #
257    #  There are 3 phases of parse tree processing, applied in order to
258    #  all the statements in a given scope-block:
259    #
260    #  (0) analyse_declarations
261    #        Make symbol table entries for all declarations at the current
262    #        level, both explicit (def, cdef, etc.) and implicit (assignment
263    #        to an otherwise undeclared name).
264    #
265    #  (1) analyse_expressions
266    #         Determine the result types of expressions and fill in the
267    #         'type' attribute of each ExprNode. Insert coercion nodes into the
268    #         tree where needed to convert to and from Python objects.
269    #         Allocate temporary locals for intermediate results. Fill
270    #         in the 'result_code' attribute of each ExprNode with a C code
271    #         fragment.
272    #
273    #  (2) generate_code
274    #         Emit C code for all declarations, statements and expressions.
275    #         Recursively applies the 3 processing phases to the bodies of
276    #         functions.
277    #
278
279    def analyse_declarations(self, env):
280        pass
281
282    def analyse_expressions(self, env):
283        raise InternalError("analyse_expressions not implemented for %s" % \
284            self.__class__.__name__)
285
286    def generate_code(self, code):
287        raise InternalError("generate_code not implemented for %s" % \
288            self.__class__.__name__)
289
290    def annotate(self, code):
291        # mro does the wrong thing
292        if isinstance(self, BlockNode):
293            self.body.annotate(code)
294
295    def end_pos(self):
296        try:
297            return self._end_pos
298        except AttributeError:
299            pos = self.pos
300            if not self.child_attrs:
301                self._end_pos = pos
302                return pos
303            for attr in self.child_attrs:
304                child = getattr(self, attr)
305                # Sometimes lists, sometimes nodes
306                if child is None:
307                    pass
308                elif isinstance(child, list):
309                    for c in child:
310                        pos = max(pos, c.end_pos())
311                else:
312                    pos = max(pos, child.end_pos())
313            self._end_pos = pos
314            return pos
315
316    def dump(self, level=0, filter_out=("pos",), cutoff=100, encountered=None):
317        """Debug helper method that returns a recursive string representation of this node.
318        """
319        if cutoff == 0:
320            return "<...nesting level cutoff...>"
321        if encountered is None:
322            encountered = set()
323        if id(self) in encountered:
324            return "<%s (0x%x) -- already output>" % (self.__class__.__name__, id(self))
325        encountered.add(id(self))
326
327        def dump_child(x, level):
328            if isinstance(x, Node):
329                return x.dump(level, filter_out, cutoff-1, encountered)
330            elif isinstance(x, list):
331                return "[%s]" % ", ".join([dump_child(item, level) for item in x])
332            else:
333                return repr(x)
334
335        attrs = [(key, value) for key, value in self.__dict__.items() if key not in filter_out]
336        if len(attrs) == 0:
337            return "<%s (0x%x)>" % (self.__class__.__name__, id(self))
338        else:
339            indent = "  " * level
340            res = "<%s (0x%x)\n" % (self.__class__.__name__, id(self))
341            for key, value in attrs:
342                res += "%s  %s: %s\n" % (indent, key, dump_child(value, level + 1))
343            res += "%s>" % indent
344            return res
345
346    def dump_pos(self, mark_column=False, marker='(#)'):
347        """Debug helper method that returns the source code context of this node as a string.
348        """
349        if not self.pos:
350            return u''
351        source_desc, line, col = self.pos
352        contents = source_desc.get_lines(encoding='ASCII', error_handling='ignore')
353        # line numbers start at 1
354        lines = contents[max(0, line-3):line]
355        current = lines[-1]
356        if mark_column:
357            current = current[:col] + marker + current[col:]
358        lines[-1] = current.rstrip() + u'             # <<<<<<<<<<<<<<\n'
359        lines += contents[line:line+2]
360        return u'"%s":%d:%d\n%s\n' % (
361            source_desc.get_escaped_description(), line, col, u''.join(lines))
362
363class CompilerDirectivesNode(Node):
364    """
365    Sets compiler directives for the children nodes
366    """
367    #  directives     {string:value}  A dictionary holding the right value for
368    #                                 *all* possible directives.
369    #  body           Node
370    child_attrs = ["body"]
371
372    def analyse_declarations(self, env):
373        old = env.directives
374        env.directives = self.directives
375        self.body.analyse_declarations(env)
376        env.directives = old
377
378    def analyse_expressions(self, env):
379        old = env.directives
380        env.directives = self.directives
381        self.body = self.body.analyse_expressions(env)
382        env.directives = old
383        return self
384
385    def generate_function_definitions(self, env, code):
386        env_old = env.directives
387        code_old = code.globalstate.directives
388        code.globalstate.directives = self.directives
389        self.body.generate_function_definitions(env, code)
390        env.directives = env_old
391        code.globalstate.directives = code_old
392
393    def generate_execution_code(self, code):
394        old = code.globalstate.directives
395        code.globalstate.directives = self.directives
396        self.body.generate_execution_code(code)
397        code.globalstate.directives = old
398
399    def annotate(self, code):
400        old = code.globalstate.directives
401        code.globalstate.directives = self.directives
402        self.body.annotate(code)
403        code.globalstate.directives = old
404
405class BlockNode(object):
406    #  Mixin class for nodes representing a declaration block.
407
408    def generate_cached_builtins_decls(self, env, code):
409        entries = env.global_scope().undeclared_cached_builtins
410        for entry in entries:
411            code.globalstate.add_cached_builtin_decl(entry)
412        del entries[:]
413
414    def generate_lambda_definitions(self, env, code):
415        for node in env.lambda_defs:
416            node.generate_function_definitions(env, code)
417
418class StatListNode(Node):
419    # stats     a list of StatNode
420
421    child_attrs = ["stats"]
422
423    @staticmethod
424    def create_analysed(pos, env, *args, **kw):
425        node = StatListNode(pos, *args, **kw)
426        return node  # No node-specific analysis needed
427
428    def analyse_declarations(self, env):
429        #print "StatListNode.analyse_declarations" ###
430        for stat in self.stats:
431            stat.analyse_declarations(env)
432
433    def analyse_expressions(self, env):
434        #print "StatListNode.analyse_expressions" ###
435        self.stats = [stat.analyse_expressions(env)
436                      for stat in self.stats]
437        return self
438
439    def generate_function_definitions(self, env, code):
440        #print "StatListNode.generate_function_definitions" ###
441        for stat in self.stats:
442            stat.generate_function_definitions(env, code)
443
444    def generate_execution_code(self, code):
445        #print "StatListNode.generate_execution_code" ###
446        for stat in self.stats:
447            code.mark_pos(stat.pos)
448            stat.generate_execution_code(code)
449
450    def annotate(self, code):
451        for stat in self.stats:
452            stat.annotate(code)
453
454
455class StatNode(Node):
456    #
457    #  Code generation for statements is split into the following subphases:
458    #
459    #  (1) generate_function_definitions
460    #        Emit C code for the definitions of any structs,
461    #        unions, enums and functions defined in the current
462    #        scope-block.
463    #
464    #  (2) generate_execution_code
465    #        Emit C code for executable statements.
466    #
467
468    def generate_function_definitions(self, env, code):
469        pass
470
471    def generate_execution_code(self, code):
472        raise InternalError("generate_execution_code not implemented for %s" % \
473            self.__class__.__name__)
474
475
476class CDefExternNode(StatNode):
477    #  include_file       string or None
478    #  verbatim_include   string or None
479    #  body               StatListNode
480
481    child_attrs = ["body"]
482
483    def analyse_declarations(self, env):
484        old_cinclude_flag = env.in_cinclude
485        env.in_cinclude = 1
486        self.body.analyse_declarations(env)
487        env.in_cinclude = old_cinclude_flag
488
489        if self.include_file or self.verbatim_include:
490            # Determine whether include should be late
491            stats = self.body.stats
492            if not env.directives['preliminary_late_includes_cy28']:
493                late = False
494            elif not stats:
495                # Special case: empty 'cdef extern' blocks are early
496                late = False
497            else:
498                late = all(isinstance(node, CVarDefNode) for node in stats)
499            env.add_include_file(self.include_file, self.verbatim_include, late)
500
501    def analyse_expressions(self, env):
502        return self
503
504    def generate_execution_code(self, code):
505        pass
506
507    def annotate(self, code):
508        self.body.annotate(code)
509
510
511class CDeclaratorNode(Node):
512    # Part of a C declaration.
513    #
514    # Processing during analyse_declarations phase:
515    #
516    #   analyse
517    #      Returns (name, type) pair where name is the
518    #      CNameDeclaratorNode of the name being declared
519    #      and type is the type it is being declared as.
520    #
521    #  calling_convention  string   Calling convention of CFuncDeclaratorNode
522    #                               for which this is a base
523
524    child_attrs = []
525
526    calling_convention = ""
527
528    def analyse_templates(self):
529        # Only C++ functions have templates.
530        return None
531
532
533class CNameDeclaratorNode(CDeclaratorNode):
534    #  name    string             The Cython name being declared
535    #  cname   string or None     C name, if specified
536    #  default ExprNode or None   the value assigned on declaration
537
538    child_attrs = ['default']
539
540    default = None
541
542    def analyse(self, base_type, env, nonempty=0, visibility=None, in_pxd=False):
543        if nonempty and self.name == '':
544            # May have mistaken the name for the type.
545            if base_type.is_ptr or base_type.is_array or base_type.is_buffer:
546                error(self.pos, "Missing argument name")
547            elif base_type.is_void:
548                error(self.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
549            else:
550                self.name = base_type.declaration_code("", for_display=1, pyrex=1)
551                base_type = py_object_type
552
553        if base_type.is_fused and env.fused_to_specific:
554            base_type = base_type.specialize(env.fused_to_specific)
555
556        self.type = base_type
557        return self, base_type
558
559
560class CPtrDeclaratorNode(CDeclaratorNode):
561    # base     CDeclaratorNode
562
563    child_attrs = ["base"]
564
565    def analyse_templates(self):
566        return self.base.analyse_templates()
567
568    def analyse(self, base_type, env, nonempty=0, visibility=None, in_pxd=False):
569        if base_type.is_pyobject:
570            error(self.pos, "Pointer base type cannot be a Python object")
571        ptr_type = PyrexTypes.c_ptr_type(base_type)
572        return self.base.analyse(ptr_type, env, nonempty=nonempty, visibility=visibility, in_pxd=in_pxd)
573
574
575class CReferenceDeclaratorNode(CDeclaratorNode):
576    # base     CDeclaratorNode
577
578    child_attrs = ["base"]
579
580    def analyse_templates(self):
581        return self.base.analyse_templates()
582
583    def analyse(self, base_type, env, nonempty=0, visibility=None, in_pxd=False):
584        if base_type.is_pyobject:
585            error(self.pos, "Reference base type cannot be a Python object")
586        ref_type = PyrexTypes.c_ref_type(base_type)
587        return self.base.analyse(ref_type, env, nonempty=nonempty, visibility=visibility, in_pxd=in_pxd)
588
589
590class CArrayDeclaratorNode(CDeclaratorNode):
591    # base        CDeclaratorNode
592    # dimension   ExprNode
593
594    child_attrs = ["base", "dimension"]
595
596    def analyse(self, base_type, env, nonempty=0, visibility=None, in_pxd=False):
597        if (base_type.is_cpp_class and base_type.is_template_type()) or base_type.is_cfunction:
598            from .ExprNodes import TupleNode
599            if isinstance(self.dimension, TupleNode):
600                args = self.dimension.args
601            else:
602                args = self.dimension,
603            values = [v.analyse_as_type(env) for v in args]
604            if None in values:
605                ix = values.index(None)
606                error(args[ix].pos, "Template parameter not a type")
607                base_type = error_type
608            else:
609                base_type = base_type.specialize_here(self.pos, values)
610            return self.base.analyse(base_type, env, nonempty=nonempty, visibility=visibility, in_pxd=in_pxd)
611        if self.dimension:
612            self.dimension = self.dimension.analyse_const_expression(env)
613            if not self.dimension.type.is_int:
614                error(self.dimension.pos, "Array dimension not integer")
615            size = self.dimension.get_constant_c_result_code()
616            if size is not None:
617                try:
618                    size = int(size)
619                except ValueError:
620                    # runtime constant?
621                    pass
622        else:
623            size = None
624        if not base_type.is_complete():
625            error(self.pos, "Array element type '%s' is incomplete" % base_type)
626        if base_type.is_pyobject:
627            error(self.pos, "Array element cannot be a Python object")
628        if base_type.is_cfunction:
629            error(self.pos, "Array element cannot be a function")
630        array_type = PyrexTypes.c_array_type(base_type, size)
631        return self.base.analyse(array_type, env, nonempty=nonempty, visibility=visibility, in_pxd=in_pxd)
632
633
634class CFuncDeclaratorNode(CDeclaratorNode):
635    # base             CDeclaratorNode
636    # args             [CArgDeclNode]
637    # templates        [TemplatePlaceholderType]
638    # has_varargs      boolean
639    # exception_value  ConstNode
640    # exception_check  boolean    True if PyErr_Occurred check needed
641    # nogil            boolean    Can be called without gil
642    # with_gil         boolean    Acquire gil around function body
643    # is_const_method  boolean    Whether this is a const method
644
645    child_attrs = ["base", "args", "exception_value"]
646
647    overridable = 0
648    optional_arg_count = 0
649    is_const_method = 0
650    templates = None
651
652    def analyse_templates(self):
653        if isinstance(self.base, CArrayDeclaratorNode):
654            from .ExprNodes import TupleNode, NameNode
655            template_node = self.base.dimension
656            if isinstance(template_node, TupleNode):
657                template_nodes = template_node.args
658            elif isinstance(template_node, NameNode):
659                template_nodes = [template_node]
660            else:
661                error(template_node.pos, "Template arguments must be a list of names")
662                return None
663            self.templates = []
664            for template in template_nodes:
665                if isinstance(template, NameNode):
666                    self.templates.append(PyrexTypes.TemplatePlaceholderType(template.name))
667                else:
668                    error(template.pos, "Template arguments must be a list of names")
669            self.base = self.base.base
670            return self.templates
671        else:
672            return None
673
674    def analyse(self, return_type, env, nonempty=0, directive_locals=None, visibility=None, in_pxd=False):
675        if directive_locals is None:
676            directive_locals = {}
677        if nonempty:
678            nonempty -= 1
679        func_type_args = []
680        for i, arg_node in enumerate(self.args):
681            name_declarator, type = arg_node.analyse(
682                env, nonempty=nonempty,
683                is_self_arg=(i == 0 and env.is_c_class_scope and 'staticmethod' not in env.directives))
684            name = name_declarator.name
685            if name in directive_locals:
686                type_node = directive_locals[name]
687                other_type = type_node.analyse_as_type(env)
688                if other_type is None:
689                    error(type_node.pos, "Not a type")
690                elif (type is not PyrexTypes.py_object_type
691                      and not type.same_as(other_type)):
692                    error(self.base.pos, "Signature does not agree with previous declaration")
693                    error(type_node.pos, "Previous declaration here")
694                else:
695                    type = other_type
696            if name_declarator.cname:
697                error(self.pos, "Function argument cannot have C name specification")
698            if i == 0 and env.is_c_class_scope and type.is_unspecified:
699                # fix the type of self
700                type = env.parent_type
701            # Turn *[] argument into **
702            if type.is_array:
703                type = PyrexTypes.c_ptr_type(type.base_type)
704            # Catch attempted C-style func(void) decl
705            if type.is_void:
706                error(arg_node.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
707            func_type_args.append(
708                PyrexTypes.CFuncTypeArg(name, type, arg_node.pos))
709            if arg_node.default:
710                self.optional_arg_count += 1
711            elif self.optional_arg_count:
712                error(self.pos, "Non-default argument follows default argument")
713
714        exc_val = None
715        exc_check = 0
716        if self.exception_check == '+':
717            env.add_include_file('ios')         # for std::ios_base::failure
718            env.add_include_file('new')         # for std::bad_alloc
719            env.add_include_file('stdexcept')
720            env.add_include_file('typeinfo')    # for std::bad_cast
721        if (return_type.is_pyobject
722                and (self.exception_value or self.exception_check)
723                and self.exception_check != '+'):
724            error(self.pos, "Exception clause not allowed for function returning Python object")
725        else:
726            if self.exception_value is None and self.exception_check and self.exception_check != '+':
727                # Use an explicit exception return value to speed up exception checks.
728                # Even if it is not declared, we can use the default exception value of the return type,
729                # unless the function is some kind of external function that we do not control.
730                if return_type.exception_value is not None and (visibility != 'extern' and not in_pxd):
731                    # Extension types are more difficult because the signature must match the base type signature.
732                    if not env.is_c_class_scope:
733                        from .ExprNodes import ConstNode
734                        self.exception_value = ConstNode(
735                            self.pos, value=return_type.exception_value, type=return_type)
736            if self.exception_value:
737                self.exception_value = self.exception_value.analyse_const_expression(env)
738                if self.exception_check == '+':
739                    exc_val_type = self.exception_value.type
740                    if (not exc_val_type.is_error
741                            and not exc_val_type.is_pyobject
742                            and not (exc_val_type.is_cfunction
743                                     and not exc_val_type.return_type.is_pyobject
744                                     and not exc_val_type.args)
745                            and not (exc_val_type == PyrexTypes.c_char_type
746                                     and self.exception_value.value == '*')):
747                        error(self.exception_value.pos,
748                              "Exception value must be a Python exception or cdef function with no arguments or *.")
749                    exc_val = self.exception_value
750                else:
751                    self.exception_value = self.exception_value.coerce_to(
752                        return_type, env).analyse_const_expression(env)
753                    exc_val = self.exception_value.get_constant_c_result_code()
754                    if exc_val is None:
755                        raise InternalError(
756                            "get_constant_c_result_code not implemented for %s" %
757                            self.exception_value.__class__.__name__)
758                    if not return_type.assignable_from(self.exception_value.type):
759                        error(self.exception_value.pos,
760                              "Exception value incompatible with function return type")
761            exc_check = self.exception_check
762        if return_type.is_cfunction:
763            error(self.pos, "Function cannot return a function")
764        func_type = PyrexTypes.CFuncType(
765            return_type, func_type_args, self.has_varargs,
766            optional_arg_count=self.optional_arg_count,
767            exception_value=exc_val, exception_check=exc_check,
768            calling_convention=self.base.calling_convention,
769            nogil=self.nogil, with_gil=self.with_gil, is_overridable=self.overridable,
770            is_const_method=self.is_const_method,
771            templates=self.templates)
772
773        if self.optional_arg_count:
774            if func_type.is_fused:
775                # This is a bit of a hack... When we need to create specialized CFuncTypes
776                # on the fly because the cdef is defined in a pxd, we need to declare the specialized optional arg
777                # struct
778                def declare_opt_arg_struct(func_type, fused_cname):
779                    self.declare_optional_arg_struct(func_type, env, fused_cname)
780
781                func_type.declare_opt_arg_struct = declare_opt_arg_struct
782            else:
783                self.declare_optional_arg_struct(func_type, env)
784
785        callspec = env.directives['callspec']
786        if callspec:
787            current = func_type.calling_convention
788            if current and current != callspec:
789                error(self.pos, "cannot have both '%s' and '%s' "
790                      "calling conventions" % (current, callspec))
791            func_type.calling_convention = callspec
792        return self.base.analyse(func_type, env, visibility=visibility, in_pxd=in_pxd)
793
794    def declare_optional_arg_struct(self, func_type, env, fused_cname=None):
795        """
796        Declares the optional argument struct (the struct used to hold the
797        values for optional arguments). For fused cdef functions, this is
798        deferred as analyse_declarations is called only once (on the fused
799        cdef function).
800        """
801        scope = StructOrUnionScope()
802        arg_count_member = '%sn' % Naming.pyrex_prefix
803        scope.declare_var(arg_count_member, PyrexTypes.c_int_type, self.pos)
804
805        for arg in func_type.args[len(func_type.args) - self.optional_arg_count:]:
806            scope.declare_var(arg.name, arg.type, arg.pos, allow_pyobject=True, allow_memoryview=True)
807
808        struct_cname = env.mangle(Naming.opt_arg_prefix, self.base.name)
809
810        if fused_cname is not None:
811            struct_cname = PyrexTypes.get_fused_cname(fused_cname, struct_cname)
812
813        op_args_struct = env.global_scope().declare_struct_or_union(
814            name=struct_cname,
815            kind='struct',
816            scope=scope,
817            typedef_flag=0,
818            pos=self.pos,
819            cname=struct_cname)
820
821        op_args_struct.defined_in_pxd = 1
822        op_args_struct.used = 1
823
824        func_type.op_arg_struct = PyrexTypes.c_ptr_type(op_args_struct.type)
825
826
827class CConstDeclaratorNode(CDeclaratorNode):
828    # base     CDeclaratorNode
829
830    child_attrs = ["base"]
831
832    def analyse(self, base_type, env, nonempty=0, visibility=None, in_pxd=False):
833        if base_type.is_pyobject:
834            error(self.pos,
835                  "Const base type cannot be a Python object")
836        const = PyrexTypes.c_const_type(base_type)
837        return self.base.analyse(const, env, nonempty=nonempty, visibility=visibility, in_pxd=in_pxd)
838
839
840class CArgDeclNode(Node):
841    # Item in a function declaration argument list.
842    #
843    # base_type      CBaseTypeNode
844    # declarator     CDeclaratorNode
845    # not_none       boolean            Tagged with 'not None'
846    # or_none        boolean            Tagged with 'or None'
847    # accept_none    boolean            Resolved boolean for not_none/or_none
848    # default        ExprNode or None
849    # default_value  PyObjectConst      constant for default value
850    # annotation     ExprNode or None   Py3 function arg annotation
851    # is_self_arg    boolean            Is the "self" arg of an extension type method
852    # is_type_arg    boolean            Is the "class" arg of an extension type classmethod
853    # is_kw_only     boolean            Is a keyword-only argument
854    # is_dynamic     boolean            Non-literal arg stored inside CyFunction
855
856    child_attrs = ["base_type", "declarator", "default", "annotation"]
857    outer_attrs = ["default", "annotation"]
858
859    is_self_arg = 0
860    is_type_arg = 0
861    is_generic = 1
862    kw_only = 0
863    not_none = 0
864    or_none = 0
865    type = None
866    name_declarator = None
867    default_value = None
868    annotation = None
869    is_dynamic = 0
870
871    def analyse(self, env, nonempty=0, is_self_arg=False):
872        if is_self_arg:
873            self.base_type.is_self_arg = self.is_self_arg = True
874        if self.type is None:
875            # The parser may misinterpret names as types. We fix that here.
876            if isinstance(self.declarator, CNameDeclaratorNode) and self.declarator.name == '':
877                if nonempty:
878                    if self.base_type.is_basic_c_type:
879                        # char, short, long called "int"
880                        type = self.base_type.analyse(env, could_be_name=True)
881                        arg_name = type.empty_declaration_code()
882                    else:
883                        arg_name = self.base_type.name
884                    self.declarator.name = EncodedString(arg_name)
885                    self.base_type.name = None
886                    self.base_type.is_basic_c_type = False
887                could_be_name = True
888            else:
889                could_be_name = False
890            self.base_type.is_arg = True
891            base_type = self.base_type.analyse(env, could_be_name=could_be_name)
892            if hasattr(self.base_type, 'arg_name') and self.base_type.arg_name:
893                self.declarator.name = self.base_type.arg_name
894
895            # The parser is unable to resolve the ambiguity of [] as part of the
896            # type (e.g. in buffers) or empty declarator (as with arrays).
897            # This is only arises for empty multi-dimensional arrays.
898            if (base_type.is_array
899                    and isinstance(self.base_type, TemplatedTypeNode)
900                    and isinstance(self.declarator, CArrayDeclaratorNode)):
901                declarator = self.declarator
902                while isinstance(declarator.base, CArrayDeclaratorNode):
903                    declarator = declarator.base
904                declarator.base = self.base_type.array_declarator
905                base_type = base_type.base_type
906
907            # inject type declaration from annotations
908            # this is called without 'env' by AdjustDefByDirectives transform before declaration analysis
909            if self.annotation and env and env.directives['annotation_typing'] and self.base_type.name is None:
910                arg_type = self.inject_type_from_annotations(env)
911                if arg_type is not None:
912                    base_type = arg_type
913            return self.declarator.analyse(base_type, env, nonempty=nonempty)
914        else:
915            return self.name_declarator, self.type
916
917    def inject_type_from_annotations(self, env):
918        annotation = self.annotation
919        if not annotation:
920            return None
921        base_type, arg_type = analyse_type_annotation(annotation, env, assigned_value=self.default)
922        if base_type is not None:
923            self.base_type = base_type
924        return arg_type
925
926    def calculate_default_value_code(self, code):
927        if self.default_value is None:
928            if self.default:
929                if self.default.is_literal:
930                    # will not output any code, just assign the result_code
931                    self.default.generate_evaluation_code(code)
932                    return self.type.cast_code(self.default.result())
933                self.default_value = code.get_argument_default_const(self.type)
934        return self.default_value
935
936    def annotate(self, code):
937        if self.default:
938            self.default.annotate(code)
939
940    def generate_assignment_code(self, code, target=None, overloaded_assignment=False):
941        default = self.default
942        if default is None or default.is_literal:
943            return
944        if target is None:
945            target = self.calculate_default_value_code(code)
946        default.generate_evaluation_code(code)
947        default.make_owned_reference(code)
948        result = default.result() if overloaded_assignment else default.result_as(self.type)
949        code.putln("%s = %s;" % (target, result))
950        if self.type.is_pyobject:
951            code.put_giveref(default.result())
952        default.generate_post_assignment_code(code)
953        default.free_temps(code)
954
955
956class CBaseTypeNode(Node):
957    # Abstract base class for C base type nodes.
958    #
959    # Processing during analyse_declarations phase:
960    #
961    #   analyse
962    #     Returns the type.
963
964    def analyse_as_type(self, env):
965        return self.analyse(env)
966
967
968class CAnalysedBaseTypeNode(Node):
969    # type            type
970
971    child_attrs = []
972
973    def analyse(self, env, could_be_name=False):
974        return self.type
975
976
977class CSimpleBaseTypeNode(CBaseTypeNode):
978    # name             string
979    # module_path      [string]     Qualifying name components
980    # is_basic_c_type  boolean
981    # signed           boolean
982    # longness         integer
983    # complex          boolean
984    # is_self_arg      boolean      Is self argument of C method
985    # ##is_type_arg      boolean      Is type argument of class method
986
987    child_attrs = []
988    arg_name = None   # in case the argument name was interpreted as a type
989    module_path = []
990    is_basic_c_type = False
991    complex = False
992
993    def analyse(self, env, could_be_name=False):
994        # Return type descriptor.
995        #print "CSimpleBaseTypeNode.analyse: is_self_arg =", self.is_self_arg ###
996        type = None
997        if self.is_basic_c_type:
998            type = PyrexTypes.simple_c_type(self.signed, self.longness, self.name)
999            if not type:
1000                error(self.pos, "Unrecognised type modifier combination")
1001        elif self.name == "object" and not self.module_path:
1002            type = py_object_type
1003        elif self.name is None:
1004            if self.is_self_arg and env.is_c_class_scope:
1005                #print "CSimpleBaseTypeNode.analyse: defaulting to parent type" ###
1006                type = env.parent_type
1007            ## elif self.is_type_arg and env.is_c_class_scope:
1008            ##     type = Builtin.type_type
1009            else:
1010                type = py_object_type
1011        else:
1012            if self.module_path:
1013                # Maybe it's a nested C++ class.
1014                scope = env
1015                for item in self.module_path:
1016                    entry = scope.lookup(item)
1017                    if entry is not None and entry.is_cpp_class:
1018                        scope = entry.type.scope
1019                    else:
1020                        scope = None
1021                        break
1022
1023                if scope is None:
1024                    # Maybe it's a cimport.
1025                    scope = env.find_imported_module(self.module_path, self.pos)
1026            else:
1027                scope = env
1028
1029            if scope:
1030                if scope.is_c_class_scope:
1031                    scope = scope.global_scope()
1032
1033                type = scope.lookup_type(self.name)
1034                if type is not None:
1035                    pass
1036                elif could_be_name:
1037                    if self.is_self_arg and env.is_c_class_scope:
1038                        type = env.parent_type
1039                    ## elif self.is_type_arg and env.is_c_class_scope:
1040                    ##     type = Builtin.type_type
1041                    else:
1042                        type = py_object_type
1043                    self.arg_name = EncodedString(self.name)
1044                else:
1045                    if self.templates:
1046                        if not self.name in self.templates:
1047                            error(self.pos, "'%s' is not a type identifier" % self.name)
1048                        type = PyrexTypes.TemplatePlaceholderType(self.name)
1049                    else:
1050                        error(self.pos, "'%s' is not a type identifier" % self.name)
1051        if type and type.is_fused and env.fused_to_specific:
1052            type = type.specialize(env.fused_to_specific)
1053        if self.complex:
1054            if not type.is_numeric or type.is_complex:
1055                error(self.pos, "can only complexify c numeric types")
1056            type = PyrexTypes.CComplexType(type)
1057            type.create_declaration_utility_code(env)
1058        elif type is Builtin.complex_type:
1059            # Special case: optimise builtin complex type into C's
1060            # double complex.  The parser cannot do this (as for the
1061            # normal scalar types) as the user may have redeclared the
1062            # 'complex' type.  Testing for the exact type here works.
1063            type = PyrexTypes.c_double_complex_type
1064            type.create_declaration_utility_code(env)
1065            self.complex = True
1066        if type:
1067            return type
1068        else:
1069            return PyrexTypes.error_type
1070
1071class MemoryViewSliceTypeNode(CBaseTypeNode):
1072
1073    name = 'memoryview'
1074    child_attrs = ['base_type_node', 'axes']
1075
1076    def analyse(self, env, could_be_name=False):
1077
1078        base_type = self.base_type_node.analyse(env)
1079        if base_type.is_error: return base_type
1080
1081        from . import MemoryView
1082
1083        try:
1084            axes_specs = MemoryView.get_axes_specs(env, self.axes)
1085        except CompileError as e:
1086            error(e.position, e.message_only)
1087            self.type = PyrexTypes.ErrorType()
1088            return self.type
1089
1090        if not MemoryView.validate_axes(self.pos, axes_specs):
1091            self.type = error_type
1092        else:
1093            self.type = PyrexTypes.MemoryViewSliceType(base_type, axes_specs)
1094            self.type.validate_memslice_dtype(self.pos)
1095            self.use_memview_utilities(env)
1096
1097        return self.type
1098
1099    def use_memview_utilities(self, env):
1100        from . import MemoryView
1101        env.use_utility_code(MemoryView.view_utility_code)
1102
1103
1104class CNestedBaseTypeNode(CBaseTypeNode):
1105    # For C++ classes that live inside other C++ classes.
1106
1107    # name             string
1108    # base_type        CBaseTypeNode
1109
1110    child_attrs = ['base_type']
1111
1112    def analyse(self, env, could_be_name=None):
1113        base_type = self.base_type.analyse(env)
1114        if base_type is PyrexTypes.error_type:
1115            return PyrexTypes.error_type
1116        if not base_type.is_cpp_class:
1117            error(self.pos, "'%s' is not a valid type scope" % base_type)
1118            return PyrexTypes.error_type
1119        type_entry = base_type.scope.lookup_here(self.name)
1120        if not type_entry or not type_entry.is_type:
1121            error(self.pos, "'%s.%s' is not a type identifier" % (base_type, self.name))
1122            return PyrexTypes.error_type
1123        return type_entry.type
1124
1125
1126class TemplatedTypeNode(CBaseTypeNode):
1127    #  After parsing:
1128    #  positional_args  [ExprNode]        List of positional arguments
1129    #  keyword_args     DictNode          Keyword arguments
1130    #  base_type_node   CBaseTypeNode
1131
1132    #  After analysis:
1133    #  type             PyrexTypes.BufferType or PyrexTypes.CppClassType  ...containing the right options
1134
1135    child_attrs = ["base_type_node", "positional_args",
1136                   "keyword_args", "dtype_node"]
1137
1138    dtype_node = None
1139
1140    name = None
1141
1142    def analyse(self, env, could_be_name=False, base_type=None):
1143        if base_type is None:
1144            base_type = self.base_type_node.analyse(env)
1145        if base_type.is_error: return base_type
1146
1147        if base_type.is_cpp_class and base_type.is_template_type():
1148            # Templated class
1149            if self.keyword_args and self.keyword_args.key_value_pairs:
1150                error(self.pos, "c++ templates cannot take keyword arguments")
1151                self.type = PyrexTypes.error_type
1152            else:
1153                template_types = []
1154                for template_node in self.positional_args:
1155                    type = template_node.analyse_as_type(env)
1156                    if type is None:
1157                        error(template_node.pos, "unknown type in template argument")
1158                        type = error_type
1159                    template_types.append(type)
1160                self.type = base_type.specialize_here(self.pos, template_types)
1161
1162        elif base_type.is_pyobject:
1163            # Buffer
1164            from . import Buffer
1165
1166            options = Buffer.analyse_buffer_options(
1167                self.pos,
1168                env,
1169                self.positional_args,
1170                self.keyword_args,
1171                base_type.buffer_defaults)
1172
1173            if sys.version_info[0] < 3:
1174                # Py 2.x enforces byte strings as keyword arguments ...
1175                options = dict([(name.encode('ASCII'), value)
1176                                for name, value in options.items()])
1177
1178            self.type = PyrexTypes.BufferType(base_type, **options)
1179            if has_np_pythran(env) and is_pythran_buffer(self.type):
1180                self.type = PyrexTypes.PythranExpr(pythran_type(self.type), self.type)
1181
1182        else:
1183            # Array
1184            empty_declarator = CNameDeclaratorNode(self.pos, name="", cname=None)
1185            if len(self.positional_args) > 1 or self.keyword_args.key_value_pairs:
1186                error(self.pos, "invalid array declaration")
1187                self.type = PyrexTypes.error_type
1188            else:
1189                # It would be nice to merge this class with CArrayDeclaratorNode,
1190                # but arrays are part of the declaration, not the type...
1191                if not self.positional_args:
1192                    dimension = None
1193                else:
1194                    dimension = self.positional_args[0]
1195                self.array_declarator = CArrayDeclaratorNode(
1196                    self.pos,
1197                    base=empty_declarator,
1198                    dimension=dimension)
1199                self.type = self.array_declarator.analyse(base_type, env)[1]
1200
1201        if self.type.is_fused and env.fused_to_specific:
1202            self.type = self.type.specialize(env.fused_to_specific)
1203
1204        return self.type
1205
1206
1207class CComplexBaseTypeNode(CBaseTypeNode):
1208    # base_type   CBaseTypeNode
1209    # declarator  CDeclaratorNode
1210
1211    child_attrs = ["base_type", "declarator"]
1212
1213    def analyse(self, env, could_be_name=False):
1214        base = self.base_type.analyse(env, could_be_name)
1215        _, type = self.declarator.analyse(base, env)
1216        return type
1217
1218
1219class CTupleBaseTypeNode(CBaseTypeNode):
1220    # components [CBaseTypeNode]
1221
1222    child_attrs = ["components"]
1223
1224    def analyse(self, env, could_be_name=False):
1225        component_types = []
1226        for c in self.components:
1227            type = c.analyse(env)
1228            if type.is_pyobject:
1229                error(c.pos, "Tuple types can't (yet) contain Python objects.")
1230                return error_type
1231            component_types.append(type)
1232        entry = env.declare_tuple_type(self.pos, component_types)
1233        entry.used = True
1234        return entry.type
1235
1236
1237class FusedTypeNode(CBaseTypeNode):
1238    """
1239    Represents a fused type in a ctypedef statement:
1240
1241        ctypedef cython.fused_type(int, long, long long) integral
1242
1243    name            str                     name of this fused type
1244    types           [CSimpleBaseTypeNode]   is the list of types to be fused
1245    """
1246
1247    child_attrs = []
1248
1249    def analyse_declarations(self, env):
1250        type = self.analyse(env)
1251        entry = env.declare_typedef(self.name, type, self.pos)
1252
1253        # Omit the typedef declaration that self.declarator would produce
1254        entry.in_cinclude = True
1255
1256    def analyse(self, env, could_be_name=False):
1257        types = []
1258        for type_node in self.types:
1259            type = type_node.analyse_as_type(env)
1260
1261            if not type:
1262                error(type_node.pos, "Not a type")
1263                continue
1264
1265            if type in types:
1266                error(type_node.pos, "Type specified multiple times")
1267            else:
1268                types.append(type)
1269
1270        # if len(self.types) == 1:
1271        #     return types[0]
1272
1273        return PyrexTypes.FusedType(types, name=self.name)
1274
1275
1276class CConstTypeNode(CBaseTypeNode):
1277    # base_type     CBaseTypeNode
1278
1279    child_attrs = ["base_type"]
1280
1281    def analyse(self, env, could_be_name=False):
1282        base = self.base_type.analyse(env, could_be_name)
1283        if base.is_pyobject:
1284            error(self.pos,
1285                  "Const base type cannot be a Python object")
1286        return PyrexTypes.c_const_type(base)
1287
1288
1289class CVarDefNode(StatNode):
1290    #  C variable definition or forward/extern function declaration.
1291    #
1292    #  visibility    'private' or 'public' or 'extern'
1293    #  base_type     CBaseTypeNode
1294    #  declarators   [CDeclaratorNode]
1295    #  in_pxd        boolean
1296    #  api           boolean
1297    #  overridable   boolean        whether it is a cpdef
1298    #  modifiers     ['inline']
1299
1300    #  decorators    [cython.locals(...)] or None
1301    #  directive_locals { string : NameNode } locals defined by cython.locals(...)
1302
1303    child_attrs = ["base_type", "declarators"]
1304
1305    decorators = None
1306    directive_locals = None
1307
1308    def analyse_declarations(self, env, dest_scope=None):
1309        if self.directive_locals is None:
1310            self.directive_locals = {}
1311        if not dest_scope:
1312            dest_scope = env
1313        self.dest_scope = dest_scope
1314
1315        if self.declarators:
1316            templates = self.declarators[0].analyse_templates()
1317        else:
1318            templates = None
1319        if templates is not None:
1320            if self.visibility != 'extern':
1321                error(self.pos, "Only extern functions allowed")
1322            if len(self.declarators) > 1:
1323                error(self.declarators[1].pos, "Can't multiply declare template types")
1324            env = TemplateScope('func_template', env)
1325            env.directives = env.outer_scope.directives
1326            for template_param in templates:
1327                env.declare_type(template_param.name, template_param, self.pos)
1328
1329        base_type = self.base_type.analyse(env)
1330
1331        if base_type.is_fused and not self.in_pxd and (env.is_c_class_scope or
1332                                                       env.is_module_scope):
1333            error(self.pos, "Fused types not allowed here")
1334            return error_type
1335
1336        self.entry = None
1337        visibility = self.visibility
1338
1339        for declarator in self.declarators:
1340
1341            if (len(self.declarators) > 1
1342                    and not isinstance(declarator, CNameDeclaratorNode)
1343                    and env.directives['warn.multiple_declarators']):
1344                warning(
1345                    declarator.pos,
1346                    "Non-trivial type declarators in shared declaration (e.g. mix of pointers and values). "
1347                    "Each pointer declaration should be on its own line.", 1)
1348
1349            create_extern_wrapper = (self.overridable
1350                                     and self.visibility == 'extern'
1351                                     and env.is_module_scope)
1352            if create_extern_wrapper:
1353                declarator.overridable = False
1354            if isinstance(declarator, CFuncDeclaratorNode):
1355                name_declarator, type = declarator.analyse(
1356                    base_type, env, directive_locals=self.directive_locals, visibility=visibility, in_pxd=self.in_pxd)
1357            else:
1358                name_declarator, type = declarator.analyse(
1359                    base_type, env, visibility=visibility, in_pxd=self.in_pxd)
1360            if not type.is_complete():
1361                if not (self.visibility == 'extern' and type.is_array or type.is_memoryviewslice):
1362                    error(declarator.pos, "Variable type '%s' is incomplete" % type)
1363            if self.visibility == 'extern' and type.is_pyobject:
1364                error(declarator.pos, "Python object cannot be declared extern")
1365            name = name_declarator.name
1366            cname = name_declarator.cname
1367            if name == '':
1368                error(declarator.pos, "Missing name in declaration.")
1369                return
1370            if type.is_reference and self.visibility != 'extern':
1371                error(declarator.pos, "C++ references cannot be declared; use a pointer instead")
1372            if type.is_cfunction:
1373                if 'staticmethod' in env.directives:
1374                    type.is_static_method = True
1375                self.entry = dest_scope.declare_cfunction(
1376                    name, type, declarator.pos,
1377                    cname=cname, visibility=self.visibility, in_pxd=self.in_pxd,
1378                    api=self.api, modifiers=self.modifiers, overridable=self.overridable)
1379                if self.entry is not None:
1380                    self.entry.directive_locals = copy.copy(self.directive_locals)
1381                if create_extern_wrapper:
1382                    self.entry.type.create_to_py_utility_code(env)
1383                    self.entry.create_wrapper = True
1384            else:
1385                if self.overridable:
1386                    warning(self.pos, "cpdef variables will not be supported in Cython 3; "
1387                            "currently they are no different from cdef variables", 2)
1388                if self.directive_locals:
1389                    error(self.pos, "Decorators can only be followed by functions")
1390                self.entry = dest_scope.declare_var(
1391                    name, type, declarator.pos,
1392                    cname=cname, visibility=visibility, in_pxd=self.in_pxd,
1393                    api=self.api, is_cdef=1)
1394                if Options.docstrings:
1395                    self.entry.doc = embed_position(self.pos, self.doc)
1396
1397
1398class CStructOrUnionDefNode(StatNode):
1399    #  name          string
1400    #  cname         string or None
1401    #  kind          "struct" or "union"
1402    #  typedef_flag  boolean
1403    #  visibility    "public" or "private"
1404    #  api           boolean
1405    #  in_pxd        boolean
1406    #  attributes    [CVarDefNode] or None
1407    #  entry         Entry
1408    #  packed        boolean
1409
1410    child_attrs = ["attributes"]
1411
1412    def declare(self, env, scope=None):
1413        self.entry = env.declare_struct_or_union(
1414            self.name, self.kind, scope, self.typedef_flag, self.pos,
1415            self.cname, visibility=self.visibility, api=self.api,
1416            packed=self.packed)
1417
1418    def analyse_declarations(self, env):
1419        scope = None
1420        if self.attributes is not None:
1421            scope = StructOrUnionScope(self.name)
1422        self.declare(env, scope)
1423        if self.attributes is not None:
1424            if self.in_pxd and not env.in_cinclude:
1425                self.entry.defined_in_pxd = 1
1426            for attr in self.attributes:
1427                attr.analyse_declarations(env, scope)
1428            if self.visibility != 'extern':
1429                for attr in scope.var_entries:
1430                    type = attr.type
1431                    while type.is_array:
1432                        type = type.base_type
1433                    if type == self.entry.type:
1434                        error(attr.pos, "Struct cannot contain itself as a member.")
1435
1436    def analyse_expressions(self, env):
1437        return self
1438
1439    def generate_execution_code(self, code):
1440        pass
1441
1442
1443class CppClassNode(CStructOrUnionDefNode, BlockNode):
1444
1445    #  name          string
1446    #  cname         string or None
1447    #  visibility    "extern"
1448    #  in_pxd        boolean
1449    #  attributes    [CVarDefNode] or None
1450    #  entry         Entry
1451    #  base_classes  [CBaseTypeNode]
1452    #  templates     [(string, bool)] or None
1453    #  decorators    [DecoratorNode] or None
1454
1455    decorators = None
1456
1457    def declare(self, env):
1458        if self.templates is None:
1459            template_types = None
1460        else:
1461            template_types = [PyrexTypes.TemplatePlaceholderType(template_name, not required)
1462                              for template_name, required in self.templates]
1463            num_optional_templates = sum(not required for _, required in self.templates)
1464            if num_optional_templates and not all(required for _, required in self.templates[:-num_optional_templates]):
1465                error(self.pos, "Required template parameters must precede optional template parameters.")
1466        self.entry = env.declare_cpp_class(
1467            self.name, None, self.pos, self.cname,
1468            base_classes=[], visibility=self.visibility, templates=template_types)
1469
1470    def analyse_declarations(self, env):
1471        if self.templates is None:
1472            template_types = template_names = None
1473        else:
1474            template_names = [template_name for template_name, _ in self.templates]
1475            template_types = [PyrexTypes.TemplatePlaceholderType(template_name, not required)
1476                              for template_name, required in self.templates]
1477        scope = None
1478        if self.attributes is not None:
1479            scope = CppClassScope(self.name, env, templates=template_names)
1480        def base_ok(base_class):
1481            if base_class.is_cpp_class or base_class.is_struct:
1482                return True
1483            else:
1484                error(self.pos, "Base class '%s' not a struct or class." % base_class)
1485        base_class_types = filter(base_ok, [b.analyse(scope or env) for b in self.base_classes])
1486        self.entry = env.declare_cpp_class(
1487            self.name, scope, self.pos,
1488            self.cname, base_class_types, visibility=self.visibility, templates=template_types)
1489        if self.entry is None:
1490            return
1491        self.entry.is_cpp_class = 1
1492        if scope is not None:
1493            scope.type = self.entry.type
1494        defined_funcs = []
1495        def func_attributes(attributes):
1496            for attr in attributes:
1497                if isinstance(attr, CFuncDefNode):
1498                    yield attr
1499                elif isinstance(attr, CompilerDirectivesNode):
1500                    for sub_attr in func_attributes(attr.body.stats):
1501                        yield sub_attr
1502        if self.attributes is not None:
1503            if self.in_pxd and not env.in_cinclude:
1504                self.entry.defined_in_pxd = 1
1505            for attr in self.attributes:
1506                declare = getattr(attr, 'declare', None)
1507                if declare:
1508                    attr.declare(scope)
1509                attr.analyse_declarations(scope)
1510            for func in func_attributes(self.attributes):
1511                defined_funcs.append(func)
1512                if self.templates is not None:
1513                    func.template_declaration = "template <typename %s>" % ", typename ".join(template_names)
1514        self.body = StatListNode(self.pos, stats=defined_funcs)
1515        self.scope = scope
1516
1517    def analyse_expressions(self, env):
1518        self.body = self.body.analyse_expressions(self.entry.type.scope)
1519        return self
1520
1521    def generate_function_definitions(self, env, code):
1522        self.body.generate_function_definitions(self.entry.type.scope, code)
1523
1524    def generate_execution_code(self, code):
1525        self.body.generate_execution_code(code)
1526
1527    def annotate(self, code):
1528        self.body.annotate(code)
1529
1530
1531class CEnumDefNode(StatNode):
1532    #  name           string or None
1533    #  cname          string or None
1534    #  items          [CEnumDefItemNode]
1535    #  typedef_flag   boolean
1536    #  visibility     "public" or "private" or "extern"
1537    #  api            boolean
1538    #  in_pxd         boolean
1539    #  create_wrapper boolean
1540    #  entry          Entry
1541
1542    child_attrs = ["items"]
1543
1544    def declare(self, env):
1545         self.entry = env.declare_enum(
1546             self.name, self.pos,
1547             cname=self.cname, typedef_flag=self.typedef_flag,
1548             visibility=self.visibility, api=self.api,
1549             create_wrapper=self.create_wrapper)
1550
1551    def analyse_declarations(self, env):
1552        if self.items is not None:
1553            if self.in_pxd and not env.in_cinclude:
1554                self.entry.defined_in_pxd = 1
1555            for item in self.items:
1556                item.analyse_declarations(env, self.entry)
1557
1558    def analyse_expressions(self, env):
1559        return self
1560
1561    def generate_execution_code(self, code):
1562        if self.visibility == 'public' or self.api:
1563            code.mark_pos(self.pos)
1564            temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
1565            for item in self.entry.enum_values:
1566                code.putln("%s = PyInt_FromLong(%s); %s" % (
1567                    temp,
1568                    item.cname,
1569                    code.error_goto_if_null(temp, item.pos)))
1570                code.put_gotref(temp)
1571                code.putln('if (PyDict_SetItemString(%s, "%s", %s) < 0) %s' % (
1572                    Naming.moddict_cname,
1573                    item.name,
1574                    temp,
1575                    code.error_goto(item.pos)))
1576                code.put_decref_clear(temp, PyrexTypes.py_object_type)
1577            code.funcstate.release_temp(temp)
1578
1579
1580class CEnumDefItemNode(StatNode):
1581    #  name     string
1582    #  cname    string or None
1583    #  value    ExprNode or None
1584
1585    child_attrs = ["value"]
1586
1587    def analyse_declarations(self, env, enum_entry):
1588        if self.value:
1589            self.value = self.value.analyse_const_expression(env)
1590            if not self.value.type.is_int:
1591                self.value = self.value.coerce_to(PyrexTypes.c_int_type, env)
1592                self.value = self.value.analyse_const_expression(env)
1593        entry = env.declare_const(
1594            self.name, enum_entry.type,
1595            self.value, self.pos, cname=self.cname,
1596            visibility=enum_entry.visibility, api=enum_entry.api,
1597            create_wrapper=enum_entry.create_wrapper and enum_entry.name is None)
1598        enum_entry.enum_values.append(entry)
1599        if enum_entry.name:
1600            enum_entry.type.values.append(entry.name)
1601
1602
1603class CTypeDefNode(StatNode):
1604    #  base_type    CBaseTypeNode
1605    #  declarator   CDeclaratorNode
1606    #  visibility   "public" or "private"
1607    #  api          boolean
1608    #  in_pxd       boolean
1609
1610    child_attrs = ["base_type", "declarator"]
1611
1612    def analyse_declarations(self, env):
1613        base = self.base_type.analyse(env)
1614        name_declarator, type = self.declarator.analyse(
1615            base, env, visibility=self.visibility, in_pxd=self.in_pxd)
1616        name = name_declarator.name
1617        cname = name_declarator.cname
1618
1619        entry = env.declare_typedef(
1620            name, type, self.pos,
1621            cname=cname, visibility=self.visibility, api=self.api)
1622
1623        if type.is_fused:
1624            entry.in_cinclude = True
1625
1626        if self.in_pxd and not env.in_cinclude:
1627            entry.defined_in_pxd = 1
1628
1629    def analyse_expressions(self, env):
1630        return self
1631
1632    def generate_execution_code(self, code):
1633        pass
1634
1635
1636class FuncDefNode(StatNode, BlockNode):
1637    #  Base class for function definition nodes.
1638    #
1639    #  return_type     PyrexType
1640    #  #filename        string        C name of filename string const
1641    #  entry           Symtab.Entry
1642    #  needs_closure   boolean        Whether or not this function has inner functions/classes/yield
1643    #  needs_outer_scope boolean      Whether or not this function requires outer scope
1644    #  pymethdef_required boolean     Force Python method struct generation
1645    #  directive_locals { string : ExprNode } locals defined by cython.locals(...)
1646    #  directive_returns [ExprNode] type defined by cython.returns(...)
1647    #  star_arg      PyArgDeclNode or None  * argument
1648    #  starstar_arg  PyArgDeclNode or None  ** argument
1649    #
1650    #  is_async_def  boolean          is a Coroutine function
1651    #
1652    #  has_fused_arguments  boolean
1653    #       Whether this cdef function has fused parameters. This is needed
1654    #       by AnalyseDeclarationsTransform, so it can replace CFuncDefNodes
1655    #       with fused argument types with a FusedCFuncDefNode
1656
1657    py_func = None
1658    needs_closure = False
1659    needs_outer_scope = False
1660    pymethdef_required = False
1661    is_generator = False
1662    is_generator_body = False
1663    is_async_def = False
1664    modifiers = []
1665    has_fused_arguments = False
1666    star_arg = None
1667    starstar_arg = None
1668    is_cyfunction = False
1669    code_object = None
1670
1671    def analyse_default_values(self, env):
1672        default_seen = 0
1673        for arg in self.args:
1674            if arg.default:
1675                default_seen = 1
1676                if arg.is_generic:
1677                    arg.default = arg.default.analyse_types(env)
1678                    arg.default = arg.default.coerce_to(arg.type, env)
1679                else:
1680                    error(arg.pos, "This argument cannot have a default value")
1681                    arg.default = None
1682            elif arg.kw_only:
1683                default_seen = 1
1684            elif default_seen:
1685                error(arg.pos, "Non-default argument following default argument")
1686
1687    def analyse_annotation(self, env, annotation):
1688        # Annotations can not only contain valid Python expressions but arbitrary type references.
1689        if annotation is None:
1690            return None
1691        if not env.directives['annotation_typing'] or annotation.analyse_as_type(env) is None:
1692            annotation = annotation.analyse_types(env)
1693        return annotation
1694
1695    def analyse_annotations(self, env):
1696        for arg in self.args:
1697            if arg.annotation:
1698                arg.annotation = self.analyse_annotation(env, arg.annotation)
1699
1700    def align_argument_type(self, env, arg):
1701        # @cython.locals()
1702        directive_locals = self.directive_locals
1703        orig_type = arg.type
1704        if arg.name in directive_locals:
1705            type_node = directive_locals[arg.name]
1706            other_type = type_node.analyse_as_type(env)
1707        elif isinstance(arg, CArgDeclNode) and arg.annotation and env.directives['annotation_typing']:
1708            type_node = arg.annotation
1709            other_type = arg.inject_type_from_annotations(env)
1710            if other_type is None:
1711                return arg
1712        else:
1713            return arg
1714        if other_type is None:
1715            error(type_node.pos, "Not a type")
1716        elif orig_type is not py_object_type and not orig_type.same_as(other_type):
1717            error(arg.base_type.pos, "Signature does not agree with previous declaration")
1718            error(type_node.pos, "Previous declaration here")
1719        else:
1720            arg.type = other_type
1721        return arg
1722
1723    def need_gil_acquisition(self, lenv):
1724        return 0
1725
1726    def create_local_scope(self, env):
1727        genv = env
1728        while genv.is_py_class_scope or genv.is_c_class_scope:
1729            genv = genv.outer_scope
1730        if self.needs_closure:
1731            lenv = ClosureScope(name=self.entry.name,
1732                                outer_scope=genv,
1733                                parent_scope=env,
1734                                scope_name=self.entry.cname)
1735        else:
1736            lenv = LocalScope(name=self.entry.name,
1737                              outer_scope=genv,
1738                              parent_scope=env)
1739        lenv.return_type = self.return_type
1740        type = self.entry.type
1741        if type.is_cfunction:
1742            lenv.nogil = type.nogil and not type.with_gil
1743        self.local_scope = lenv
1744        lenv.directives = env.directives
1745        return lenv
1746
1747    def generate_function_body(self, env, code):
1748        self.body.generate_execution_code(code)
1749
1750    def generate_function_definitions(self, env, code):
1751        from . import Buffer
1752        if self.return_type.is_memoryviewslice:
1753            from . import MemoryView
1754
1755        lenv = self.local_scope
1756        if lenv.is_closure_scope and not lenv.is_passthrough:
1757            outer_scope_cname = "%s->%s" % (Naming.cur_scope_cname,
1758                                            Naming.outer_scope_cname)
1759        else:
1760            outer_scope_cname = Naming.outer_scope_cname
1761        lenv.mangle_closure_cnames(outer_scope_cname)
1762        # Generate closure function definitions
1763        self.body.generate_function_definitions(lenv, code)
1764        # generate lambda function definitions
1765        self.generate_lambda_definitions(lenv, code)
1766
1767        is_getbuffer_slot = (self.entry.name == "__getbuffer__" and
1768                             self.entry.scope.is_c_class_scope)
1769        is_releasebuffer_slot = (self.entry.name == "__releasebuffer__" and
1770                                 self.entry.scope.is_c_class_scope)
1771        is_buffer_slot = is_getbuffer_slot or is_releasebuffer_slot
1772        if is_buffer_slot:
1773            if 'cython_unused' not in self.modifiers:
1774                self.modifiers = self.modifiers + ['cython_unused']
1775
1776        preprocessor_guard = self.get_preprocessor_guard()
1777
1778        profile = code.globalstate.directives['profile']
1779        linetrace = code.globalstate.directives['linetrace']
1780        if profile or linetrace:
1781            code.globalstate.use_utility_code(
1782                UtilityCode.load_cached("Profile", "Profile.c"))
1783
1784        # Generate C code for header and body of function
1785        code.enter_cfunc_scope(lenv)
1786        code.return_from_error_cleanup_label = code.new_label()
1787        code.funcstate.gil_owned = not lenv.nogil
1788
1789        # ----- Top-level constants used by this function
1790        code.mark_pos(self.pos)
1791        self.generate_cached_builtins_decls(lenv, code)
1792        # ----- Function header
1793        code.putln("")
1794
1795        if preprocessor_guard:
1796            code.putln(preprocessor_guard)
1797
1798        with_pymethdef = (self.needs_assignment_synthesis(env, code) or
1799                          self.pymethdef_required)
1800        if self.py_func:
1801            self.py_func.generate_function_header(
1802                code, with_pymethdef=with_pymethdef, proto_only=True)
1803        self.generate_function_header(code, with_pymethdef=with_pymethdef)
1804        # ----- Local variable declarations
1805        # Find function scope
1806        cenv = env
1807        while cenv.is_py_class_scope or cenv.is_c_class_scope:
1808            cenv = cenv.outer_scope
1809        if self.needs_closure:
1810            code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
1811            code.putln(";")
1812        elif self.needs_outer_scope:
1813            if lenv.is_passthrough:
1814                code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
1815                code.putln(";")
1816            code.put(cenv.scope_class.type.declaration_code(Naming.outer_scope_cname))
1817            code.putln(";")
1818        self.generate_argument_declarations(lenv, code)
1819
1820        for entry in lenv.var_entries:
1821            if not (entry.in_closure or entry.is_arg):
1822                code.put_var_declaration(entry)
1823
1824        # Initialize the return variable __pyx_r
1825        init = ""
1826        if not self.return_type.is_void:
1827            if self.return_type.is_pyobject:
1828                init = " = NULL"
1829            elif self.return_type.is_memoryviewslice:
1830                init = ' = ' + MemoryView.memslice_entry_init
1831
1832            code.putln("%s%s;" % (
1833                self.return_type.declaration_code(Naming.retval_cname),
1834                init))
1835
1836        tempvardecl_code = code.insertion_point()
1837        self.generate_keyword_list(code)
1838
1839        # ----- GIL acquisition
1840        acquire_gil = self.acquire_gil
1841
1842        # See if we need to acquire the GIL for variable declarations, or for
1843        # refnanny only
1844
1845        # Closures are not currently possible for cdef nogil functions,
1846        # but check them anyway
1847        have_object_args = self.needs_closure or self.needs_outer_scope
1848        for arg in lenv.arg_entries:
1849            if arg.type.is_pyobject:
1850                have_object_args = True
1851                break
1852
1853        used_buffer_entries = [entry for entry in lenv.buffer_entries if entry.used]
1854
1855        acquire_gil_for_var_decls_only = (
1856            lenv.nogil and lenv.has_with_gil_block and
1857            (have_object_args or used_buffer_entries))
1858
1859        acquire_gil_for_refnanny_only = (
1860            lenv.nogil and lenv.has_with_gil_block and not
1861            acquire_gil_for_var_decls_only)
1862
1863        use_refnanny = not lenv.nogil or lenv.has_with_gil_block
1864
1865        if acquire_gil or acquire_gil_for_var_decls_only:
1866            code.put_ensure_gil()
1867            code.funcstate.gil_owned = True
1868        elif lenv.nogil and lenv.has_with_gil_block:
1869            code.declare_gilstate()
1870
1871        if profile or linetrace:
1872            if not self.is_generator:
1873                # generators are traced when iterated, not at creation
1874                tempvardecl_code.put_trace_declarations()
1875                code_object = self.code_object.calculate_result_code(code) if self.code_object else None
1876                code.put_trace_frame_init(code_object)
1877
1878        # ----- Special check for getbuffer
1879        if is_getbuffer_slot:
1880            self.getbuffer_check(code)
1881
1882        # ----- set up refnanny
1883        if use_refnanny:
1884            tempvardecl_code.put_declare_refcount_context()
1885            code.put_setup_refcount_context(
1886                self.entry.name, acquire_gil=acquire_gil_for_refnanny_only)
1887
1888        # ----- Automatic lead-ins for certain special functions
1889        if is_getbuffer_slot:
1890            self.getbuffer_init(code)
1891        # ----- Create closure scope object
1892        if self.needs_closure:
1893            tp_slot = TypeSlots.ConstructorSlot("tp_new", '__new__')
1894            slot_func_cname = TypeSlots.get_slot_function(lenv.scope_class.type.scope, tp_slot)
1895            if not slot_func_cname:
1896                slot_func_cname = '%s->tp_new' % lenv.scope_class.type.typeptr_cname
1897            code.putln("%s = (%s)%s(%s, %s, NULL);" % (
1898                Naming.cur_scope_cname,
1899                lenv.scope_class.type.empty_declaration_code(),
1900                slot_func_cname,
1901                lenv.scope_class.type.typeptr_cname,
1902                Naming.empty_tuple))
1903            code.putln("if (unlikely(!%s)) {" % Naming.cur_scope_cname)
1904            # Scope unconditionally DECREFed on return.
1905            code.putln("%s = %s;" % (
1906                Naming.cur_scope_cname,
1907                lenv.scope_class.type.cast_code("Py_None")))
1908            code.put_incref("Py_None", py_object_type)
1909            code.putln(code.error_goto(self.pos))
1910            code.putln("} else {")
1911            code.put_gotref(Naming.cur_scope_cname)
1912            code.putln("}")
1913            # Note that it is unsafe to decref the scope at this point.
1914        if self.needs_outer_scope:
1915            if self.is_cyfunction:
1916                code.putln("%s = (%s) __Pyx_CyFunction_GetClosure(%s);" % (
1917                    outer_scope_cname,
1918                    cenv.scope_class.type.empty_declaration_code(),
1919                    Naming.self_cname))
1920            else:
1921                code.putln("%s = (%s) %s;" % (
1922                    outer_scope_cname,
1923                    cenv.scope_class.type.empty_declaration_code(),
1924                    Naming.self_cname))
1925            if lenv.is_passthrough:
1926                code.putln("%s = %s;" % (Naming.cur_scope_cname, outer_scope_cname))
1927            elif self.needs_closure:
1928                # inner closures own a reference to their outer parent
1929                code.put_incref(outer_scope_cname, cenv.scope_class.type)
1930                code.put_giveref(outer_scope_cname)
1931        # ----- Trace function call
1932        if profile or linetrace:
1933            # this looks a bit late, but if we don't get here due to a
1934            # fatal error before hand, it's not really worth tracing
1935            if not self.is_generator:
1936                # generators are traced when iterated, not at creation
1937                if self.is_wrapper:
1938                    trace_name = self.entry.name + " (wrapper)"
1939                else:
1940                    trace_name = self.entry.name
1941                code.put_trace_call(
1942                    trace_name, self.pos, nogil=not code.funcstate.gil_owned)
1943            code.funcstate.can_trace = True
1944        # ----- Fetch arguments
1945        self.generate_argument_parsing_code(env, code)
1946        # If an argument is assigned to in the body, we must
1947        # incref it to properly keep track of refcounts.
1948        is_cdef = isinstance(self, CFuncDefNode)
1949        for entry in lenv.arg_entries:
1950            if entry.type.is_pyobject:
1951                if (acquire_gil or len(entry.cf_assignments) > 1) and not entry.in_closure:
1952                    code.put_var_incref(entry)
1953
1954            # Note: defaults are always incref-ed. For def functions, we
1955            #       we acquire arguments from object conversion, so we have
1956            #       new references. If we are a cdef function, we need to
1957            #       incref our arguments
1958            elif is_cdef and entry.type.is_memoryviewslice and len(entry.cf_assignments) > 1:
1959                code.put_incref_memoryviewslice(entry.cname, have_gil=code.funcstate.gil_owned)
1960        for entry in lenv.var_entries:
1961            if entry.is_arg and len(entry.cf_assignments) > 1 and not entry.in_closure:
1962                if entry.xdecref_cleanup:
1963                    code.put_var_xincref(entry)
1964                else:
1965                    code.put_var_incref(entry)
1966
1967        # ----- Initialise local buffer auxiliary variables
1968        for entry in lenv.var_entries + lenv.arg_entries:
1969            if entry.type.is_buffer and entry.buffer_aux.buflocal_nd_var.used:
1970                Buffer.put_init_vars(entry, code)
1971
1972        # ----- Check and convert arguments
1973        self.generate_argument_type_tests(code)
1974        # ----- Acquire buffer arguments
1975        for entry in lenv.arg_entries:
1976            if entry.type.is_buffer:
1977                Buffer.put_acquire_arg_buffer(entry, code, self.pos)
1978
1979        if acquire_gil_for_var_decls_only:
1980            code.put_release_ensured_gil()
1981            code.funcstate.gil_owned = False
1982
1983        # -------------------------
1984        # ----- Function body -----
1985        # -------------------------
1986        self.generate_function_body(env, code)
1987
1988        code.mark_pos(self.pos, trace=False)
1989        code.putln("")
1990        code.putln("/* function exit code */")
1991
1992        # ----- Default return value
1993        if not self.body.is_terminator:
1994            if self.return_type.is_pyobject:
1995                #if self.return_type.is_extension_type:
1996                #    lhs = "(PyObject *)%s" % Naming.retval_cname
1997                #else:
1998                lhs = Naming.retval_cname
1999                code.put_init_to_py_none(lhs, self.return_type)
2000            else:
2001                val = self.return_type.default_value
2002                if val:
2003                    code.putln("%s = %s;" % (Naming.retval_cname, val))
2004                elif not self.return_type.is_void:
2005                    code.putln("__Pyx_pretend_to_initialize(&%s);" % Naming.retval_cname)
2006        # ----- Error cleanup
2007        if code.error_label in code.labels_used:
2008            if not self.body.is_terminator:
2009                code.put_goto(code.return_label)
2010            code.put_label(code.error_label)
2011            for cname, type in code.funcstate.all_managed_temps():
2012                code.put_xdecref(cname, type, have_gil=not lenv.nogil)
2013
2014            # Clean up buffers -- this calls a Python function
2015            # so need to save and restore error state
2016            buffers_present = len(used_buffer_entries) > 0
2017            #memslice_entries = [e for e in lenv.entries.values() if e.type.is_memoryviewslice]
2018            if buffers_present:
2019                code.globalstate.use_utility_code(restore_exception_utility_code)
2020                code.putln("{ PyObject *__pyx_type, *__pyx_value, *__pyx_tb;")
2021                code.putln("__Pyx_PyThreadState_declare")
2022                code.putln("__Pyx_PyThreadState_assign")
2023                code.putln("__Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);")
2024                for entry in used_buffer_entries:
2025                    Buffer.put_release_buffer_code(code, entry)
2026                    #code.putln("%s = 0;" % entry.cname)
2027                code.putln("__Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}")
2028
2029            if self.return_type.is_memoryviewslice:
2030                MemoryView.put_init_entry(Naming.retval_cname, code)
2031                err_val = Naming.retval_cname
2032            else:
2033                err_val = self.error_value()
2034
2035            exc_check = self.caller_will_check_exceptions()
2036            if err_val is not None or exc_check:
2037                # TODO: Fix exception tracing (though currently unused by cProfile).
2038                # code.globalstate.use_utility_code(get_exception_tuple_utility_code)
2039                # code.put_trace_exception()
2040
2041                if lenv.nogil and not lenv.has_with_gil_block:
2042                    code.putln("{")
2043                    code.put_ensure_gil()
2044
2045                code.put_add_traceback(self.entry.qualified_name)
2046
2047                if lenv.nogil and not lenv.has_with_gil_block:
2048                    code.put_release_ensured_gil()
2049                    code.putln("}")
2050            else:
2051                warning(self.entry.pos,
2052                        "Unraisable exception in function '%s'." %
2053                        self.entry.qualified_name, 0)
2054                code.put_unraisable(self.entry.qualified_name, lenv.nogil)
2055            default_retval = self.return_type.default_value
2056            if err_val is None and default_retval:
2057                err_val = default_retval
2058            if err_val is not None:
2059                if err_val != Naming.retval_cname:
2060                    code.putln("%s = %s;" % (Naming.retval_cname, err_val))
2061            elif not self.return_type.is_void:
2062                code.putln("__Pyx_pretend_to_initialize(&%s);" % Naming.retval_cname)
2063
2064            if is_getbuffer_slot:
2065                self.getbuffer_error_cleanup(code)
2066
2067            # If we are using the non-error cleanup section we should
2068            # jump past it if we have an error. The if-test below determine
2069            # whether this section is used.
2070            if buffers_present or is_getbuffer_slot or self.return_type.is_memoryviewslice:
2071                code.put_goto(code.return_from_error_cleanup_label)
2072
2073        # ----- Non-error return cleanup
2074        code.put_label(code.return_label)
2075        for entry in used_buffer_entries:
2076            Buffer.put_release_buffer_code(code, entry)
2077        if is_getbuffer_slot:
2078            self.getbuffer_normal_cleanup(code)
2079
2080        if self.return_type.is_memoryviewslice:
2081            # See if our return value is uninitialized on non-error return
2082            # from . import MemoryView
2083            # MemoryView.err_if_nogil_initialized_check(self.pos, env)
2084            cond = code.unlikely(self.return_type.error_condition(Naming.retval_cname))
2085            code.putln(
2086                'if (%s) {' % cond)
2087            if env.nogil:
2088                code.put_ensure_gil()
2089            code.putln(
2090                'PyErr_SetString(PyExc_TypeError, "Memoryview return value is not initialized");')
2091            if env.nogil:
2092                code.put_release_ensured_gil()
2093            code.putln(
2094                '}')
2095
2096        # ----- Return cleanup for both error and no-error return
2097        code.put_label(code.return_from_error_cleanup_label)
2098
2099        for entry in lenv.var_entries:
2100            if not entry.used or entry.in_closure:
2101                continue
2102
2103            if entry.type.is_memoryviewslice:
2104                code.put_xdecref_memoryviewslice(entry.cname, have_gil=not lenv.nogil)
2105            elif entry.type.is_pyobject:
2106                if not entry.is_arg or len(entry.cf_assignments) > 1:
2107                    if entry.xdecref_cleanup:
2108                        code.put_var_xdecref(entry)
2109                    else:
2110                        code.put_var_decref(entry)
2111
2112        # Decref any increfed args
2113        for entry in lenv.arg_entries:
2114            if entry.type.is_pyobject:
2115                if (acquire_gil or len(entry.cf_assignments) > 1) and not entry.in_closure:
2116                    code.put_var_decref(entry)
2117            elif (entry.type.is_memoryviewslice and
2118                  (not is_cdef or len(entry.cf_assignments) > 1)):
2119                # decref slices of def functions and acquired slices from cdef
2120                # functions, but not borrowed slices from cdef functions.
2121                code.put_xdecref_memoryviewslice(entry.cname,
2122                                                 have_gil=not lenv.nogil)
2123        if self.needs_closure:
2124            code.put_decref(Naming.cur_scope_cname, lenv.scope_class.type)
2125
2126        # ----- Return
2127        # This code is duplicated in ModuleNode.generate_module_init_func
2128        if not lenv.nogil:
2129            default_retval = self.return_type.default_value
2130            err_val = self.error_value()
2131            if err_val is None and default_retval:
2132                err_val = default_retval  # FIXME: why is err_val not used?
2133            if self.return_type.is_pyobject:
2134                code.put_xgiveref(self.return_type.as_pyobject(Naming.retval_cname))
2135
2136        if self.entry.is_special and self.entry.name == "__hash__":
2137            # Returning -1 for __hash__ is supposed to signal an error
2138            # We do as Python instances and coerce -1 into -2.
2139            code.putln("if (unlikely(%s == -1) && !PyErr_Occurred()) %s = -2;" % (
2140                Naming.retval_cname, Naming.retval_cname))
2141
2142        if profile or linetrace:
2143            code.funcstate.can_trace = False
2144            if not self.is_generator:
2145                # generators are traced when iterated, not at creation
2146                if self.return_type.is_pyobject:
2147                    code.put_trace_return(
2148                        Naming.retval_cname, nogil=not code.funcstate.gil_owned)
2149                else:
2150                    code.put_trace_return(
2151                        "Py_None", nogil=not code.funcstate.gil_owned)
2152
2153        if not lenv.nogil:
2154            # GIL holding function
2155            code.put_finish_refcount_context()
2156
2157        if acquire_gil or (lenv.nogil and lenv.has_with_gil_block):
2158            # release the GIL (note that with-gil blocks acquire it on exit in their EnsureGILNode)
2159            code.put_release_ensured_gil()
2160            code.funcstate.gil_owned = False
2161
2162        if not self.return_type.is_void:
2163            code.putln("return %s;" % Naming.retval_cname)
2164
2165        code.putln("}")
2166
2167        if preprocessor_guard:
2168            code.putln("#endif /*!(%s)*/" % preprocessor_guard)
2169
2170        # ----- Go back and insert temp variable declarations
2171        tempvardecl_code.put_temp_declarations(code.funcstate)
2172
2173        # ----- Python version
2174        code.exit_cfunc_scope()
2175        if self.py_func:
2176            self.py_func.generate_function_definitions(env, code)
2177        self.generate_wrapper_functions(code)
2178
2179    def declare_argument(self, env, arg):
2180        if arg.type.is_void:
2181            error(arg.pos, "Invalid use of 'void'")
2182        elif not arg.type.is_complete() and not (arg.type.is_array or arg.type.is_memoryviewslice):
2183            error(arg.pos, "Argument type '%s' is incomplete" % arg.type)
2184        entry = env.declare_arg(arg.name, arg.type, arg.pos)
2185        if arg.annotation:
2186            entry.annotation = arg.annotation
2187        return entry
2188
2189    def generate_arg_type_test(self, arg, code):
2190        # Generate type test for one argument.
2191        if arg.type.typeobj_is_available():
2192            code.globalstate.use_utility_code(
2193                UtilityCode.load_cached("ArgTypeTest", "FunctionArguments.c"))
2194            typeptr_cname = arg.type.typeptr_cname
2195            arg_code = "((PyObject *)%s)" % arg.entry.cname
2196            code.putln(
2197                'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % (
2198                    arg_code,
2199                    typeptr_cname,
2200                    arg.accept_none,
2201                    arg.name,
2202                    arg.type.is_builtin_type and arg.type.require_exact,
2203                    code.error_goto(arg.pos)))
2204        else:
2205            error(arg.pos, "Cannot test type of extern C class without type object name specification")
2206
2207    def generate_arg_none_check(self, arg, code):
2208        # Generate None check for one argument.
2209        if arg.type.is_memoryviewslice:
2210            cname = "%s.memview" % arg.entry.cname
2211        else:
2212            cname = arg.entry.cname
2213
2214        code.putln('if (unlikely(((PyObject *)%s) == Py_None)) {' % cname)
2215        code.putln('''PyErr_Format(PyExc_TypeError, "Argument '%%.%ds' must not be None", "%s"); %s''' % (
2216            max(200, len(arg.name)), arg.name,
2217            code.error_goto(arg.pos)))
2218        code.putln('}')
2219
2220    def generate_wrapper_functions(self, code):
2221        pass
2222
2223    def generate_execution_code(self, code):
2224        code.mark_pos(self.pos)
2225        # Evaluate and store argument default values
2226        for arg in self.args:
2227            if not arg.is_dynamic:
2228                arg.generate_assignment_code(code)
2229
2230    #
2231    # Special code for the __getbuffer__ function
2232    #
2233    def _get_py_buffer_info(self):
2234        py_buffer = self.local_scope.arg_entries[1]
2235        try:
2236            # Check builtin definition of struct Py_buffer
2237            obj_type = py_buffer.type.base_type.scope.entries['obj'].type
2238        except (AttributeError, KeyError):
2239            # User code redeclared struct Py_buffer
2240            obj_type = None
2241        return py_buffer, obj_type
2242
2243    # Old Python 3 used to support write-locks on buffer-like objects by
2244    # calling PyObject_GetBuffer() with a view==NULL parameter. This obscure
2245    # feature is obsolete, it was almost never used (only one instance in
2246    # `Modules/posixmodule.c` in Python 3.1) and it is now officially removed
2247    # (see bpo-14203). We add an extra check here to prevent legacy code from
2248    # from trying to use the feature and prevent segmentation faults.
2249    def getbuffer_check(self, code):
2250        py_buffer, _ = self._get_py_buffer_info()
2251        view = py_buffer.cname
2252        code.putln("if (%s == NULL) {" % view)
2253        code.putln("PyErr_SetString(PyExc_BufferError, "
2254                   "\"PyObject_GetBuffer: view==NULL argument is obsolete\");")
2255        code.putln("return -1;")
2256        code.putln("}")
2257
2258    def getbuffer_init(self, code):
2259        py_buffer, obj_type = self._get_py_buffer_info()
2260        view = py_buffer.cname
2261        if obj_type and obj_type.is_pyobject:
2262            code.put_init_to_py_none("%s->obj" % view, obj_type)
2263            code.put_giveref("%s->obj" % view) # Do not refnanny object within structs
2264        else:
2265            code.putln("%s->obj = NULL;" % view)
2266
2267    def getbuffer_error_cleanup(self, code):
2268        py_buffer, obj_type = self._get_py_buffer_info()
2269        view = py_buffer.cname
2270        if obj_type and obj_type.is_pyobject:
2271            code.putln("if (%s->obj != NULL) {" % view)
2272            code.put_gotref("%s->obj" % view)
2273            code.put_decref_clear("%s->obj" % view, obj_type)
2274            code.putln("}")
2275        else:
2276            code.putln("Py_CLEAR(%s->obj);" % view)
2277
2278    def getbuffer_normal_cleanup(self, code):
2279        py_buffer, obj_type = self._get_py_buffer_info()
2280        view = py_buffer.cname
2281        if obj_type and obj_type.is_pyobject:
2282            code.putln("if (%s->obj == Py_None) {" % view)
2283            code.put_gotref("%s->obj" % view)
2284            code.put_decref_clear("%s->obj" % view, obj_type)
2285            code.putln("}")
2286
2287    def get_preprocessor_guard(self):
2288        if not self.entry.is_special:
2289            return None
2290        name = self.entry.name
2291        slot = TypeSlots.method_name_to_slot.get(name)
2292        if not slot:
2293            return None
2294        if name == '__long__' and not self.entry.scope.lookup_here('__int__'):
2295            return None
2296        if name in ("__getbuffer__", "__releasebuffer__") and self.entry.scope.is_c_class_scope:
2297            return None
2298        return slot.preprocessor_guard_code()
2299
2300
2301class CFuncDefNode(FuncDefNode):
2302    #  C function definition.
2303    #
2304    #  modifiers     ['inline']
2305    #  visibility    'private' or 'public' or 'extern'
2306    #  base_type     CBaseTypeNode
2307    #  declarator    CDeclaratorNode
2308    #  cfunc_declarator  the CFuncDeclarator of this function
2309    #                    (this is also available through declarator or a
2310    #                     base thereof)
2311    #  body          StatListNode
2312    #  api           boolean
2313    #  decorators    [DecoratorNode]        list of decorators
2314    #
2315    #  with_gil      boolean    Acquire GIL around body
2316    #  type          CFuncType
2317    #  py_func       wrapper for calling from Python
2318    #  overridable   whether or not this is a cpdef function
2319    #  inline_in_pxd whether this is an inline function in a pxd file
2320    #  template_declaration  String or None   Used for c++ class methods
2321    #  is_const_method whether this is a const method
2322    #  is_static_method whether this is a static method
2323    #  is_c_class_method whether this is a cclass method
2324
2325    child_attrs = ["base_type", "declarator", "body", "py_func_stat"]
2326
2327    inline_in_pxd = False
2328    decorators = None
2329    directive_locals = None
2330    directive_returns = None
2331    override = None
2332    template_declaration = None
2333    is_const_method = False
2334    py_func_stat = None
2335
2336    def unqualified_name(self):
2337        return self.entry.name
2338
2339    @property
2340    def code_object(self):
2341        # share the CodeObject with the cpdef wrapper (if available)
2342        return self.py_func.code_object if self.py_func else None
2343
2344    def analyse_declarations(self, env):
2345        self.is_c_class_method = env.is_c_class_scope
2346        if self.directive_locals is None:
2347            self.directive_locals = {}
2348        self.directive_locals.update(env.directives.get('locals', {}))
2349        if self.directive_returns is not None:
2350            base_type = self.directive_returns.analyse_as_type(env)
2351            if base_type is None:
2352                error(self.directive_returns.pos, "Not a type")
2353                base_type = PyrexTypes.error_type
2354        else:
2355            base_type = self.base_type.analyse(env)
2356        self.is_static_method = 'staticmethod' in env.directives and not env.lookup_here('staticmethod')
2357        # The 2 here is because we need both function and argument names.
2358        if isinstance(self.declarator, CFuncDeclaratorNode):
2359            name_declarator, type = self.declarator.analyse(
2360                base_type, env, nonempty=2 * (self.body is not None),
2361                directive_locals=self.directive_locals, visibility=self.visibility)
2362        else:
2363            name_declarator, type = self.declarator.analyse(
2364                base_type, env, nonempty=2 * (self.body is not None), visibility=self.visibility)
2365        if not type.is_cfunction:
2366            error(self.pos, "Suite attached to non-function declaration")
2367        # Remember the actual type according to the function header
2368        # written here, because the type in the symbol table entry
2369        # may be different if we're overriding a C method inherited
2370        # from the base type of an extension type.
2371        self.type = type
2372        type.is_overridable = self.overridable
2373        declarator = self.declarator
2374        while not hasattr(declarator, 'args'):
2375            declarator = declarator.base
2376
2377        self.cfunc_declarator = declarator
2378        self.args = declarator.args
2379
2380        opt_arg_count = self.cfunc_declarator.optional_arg_count
2381        if (self.visibility == 'public' or self.api) and opt_arg_count:
2382            error(self.cfunc_declarator.pos,
2383                  "Function with optional arguments may not be declared public or api")
2384
2385        if type.exception_check == '+' and self.visibility != 'extern':
2386            warning(self.cfunc_declarator.pos,
2387                    "Only extern functions can throw C++ exceptions.")
2388
2389        for formal_arg, type_arg in zip(self.args, type.args):
2390            self.align_argument_type(env, type_arg)
2391            formal_arg.type = type_arg.type
2392            formal_arg.name = type_arg.name
2393            formal_arg.cname = type_arg.cname
2394
2395            self._validate_type_visibility(type_arg.type, type_arg.pos, env)
2396
2397            if type_arg.type.is_fused:
2398                self.has_fused_arguments = True
2399
2400            if type_arg.type.is_buffer and 'inline' in self.modifiers:
2401                warning(formal_arg.pos, "Buffer unpacking not optimized away.", 1)
2402
2403            if type_arg.type.is_buffer or type_arg.type.is_pythran_expr:
2404                if self.type.nogil:
2405                    error(formal_arg.pos,
2406                          "Buffer may not be acquired without the GIL. Consider using memoryview slices instead.")
2407                elif 'inline' in self.modifiers:
2408                    warning(formal_arg.pos, "Buffer unpacking not optimized away.", 1)
2409
2410        self._validate_type_visibility(type.return_type, self.pos, env)
2411
2412        name = name_declarator.name
2413        cname = name_declarator.cname
2414
2415        type.is_const_method = self.is_const_method
2416        type.is_static_method = self.is_static_method
2417        self.entry = env.declare_cfunction(
2418            name, type, self.pos,
2419            cname=cname, visibility=self.visibility, api=self.api,
2420            defining=self.body is not None, modifiers=self.modifiers,
2421            overridable=self.overridable)
2422        self.entry.inline_func_in_pxd = self.inline_in_pxd
2423        self.return_type = type.return_type
2424        if self.return_type.is_array and self.visibility != 'extern':
2425            error(self.pos, "Function cannot return an array")
2426        if self.return_type.is_cpp_class:
2427            self.return_type.check_nullary_constructor(self.pos, "used as a return value")
2428
2429        if self.overridable and not env.is_module_scope and not self.is_static_method:
2430            if len(self.args) < 1 or not self.args[0].type.is_pyobject:
2431                # An error will be produced in the cdef function
2432                self.overridable = False
2433
2434        self.declare_cpdef_wrapper(env)
2435        self.create_local_scope(env)
2436
2437    def declare_cpdef_wrapper(self, env):
2438        if self.overridable:
2439            if self.is_static_method:
2440                # TODO(robertwb): Finish this up, perhaps via more function refactoring.
2441                error(self.pos, "static cpdef methods not yet supported")
2442            name = self.entry.name
2443            py_func_body = self.call_self_node(is_module_scope=env.is_module_scope)
2444            if self.is_static_method:
2445                from .ExprNodes import NameNode
2446                decorators = [DecoratorNode(self.pos, decorator=NameNode(self.pos, name='staticmethod'))]
2447                decorators[0].decorator.analyse_types(env)
2448            else:
2449                decorators = []
2450            self.py_func = DefNode(pos=self.pos,
2451                                   name=self.entry.name,
2452                                   args=self.args,
2453                                   star_arg=None,
2454                                   starstar_arg=None,
2455                                   doc=self.doc,
2456                                   body=py_func_body,
2457                                   decorators=decorators,
2458                                   is_wrapper=1)
2459            self.py_func.is_module_scope = env.is_module_scope
2460            self.py_func.analyse_declarations(env)
2461            self.py_func.entry.is_overridable = True
2462            self.py_func_stat = StatListNode(self.pos, stats=[self.py_func])
2463            self.py_func.type = PyrexTypes.py_object_type
2464            self.entry.as_variable = self.py_func.entry
2465            self.entry.used = self.entry.as_variable.used = True
2466            # Reset scope entry the above cfunction
2467            env.entries[name] = self.entry
2468            if (not self.entry.is_final_cmethod and
2469                    (not env.is_module_scope or Options.lookup_module_cpdef)):
2470                self.override = OverrideCheckNode(self.pos, py_func=self.py_func)
2471                self.body = StatListNode(self.pos, stats=[self.override, self.body])
2472
2473    def _validate_type_visibility(self, type, pos, env):
2474        """
2475        Ensure that types used in cdef functions are public or api, or
2476        defined in a C header.
2477        """
2478        public_or_api = (self.visibility == 'public' or self.api)
2479        entry = getattr(type, 'entry', None)
2480        if public_or_api and entry and env.is_module_scope:
2481            if not (entry.visibility in ('public', 'extern') or
2482                    entry.api or entry.in_cinclude):
2483                error(pos, "Function declared public or api may not have private types")
2484
2485    def call_self_node(self, omit_optional_args=0, is_module_scope=0):
2486        from . import ExprNodes
2487        args = self.type.args
2488        if omit_optional_args:
2489            args = args[:len(args) - self.type.optional_arg_count]
2490        arg_names = [arg.name for arg in args]
2491        if is_module_scope:
2492            cfunc = ExprNodes.NameNode(self.pos, name=self.entry.name)
2493            call_arg_names = arg_names
2494            skip_dispatch = Options.lookup_module_cpdef
2495        elif self.type.is_static_method:
2496            class_entry = self.entry.scope.parent_type.entry
2497            class_node = ExprNodes.NameNode(self.pos, name=class_entry.name)
2498            class_node.entry = class_entry
2499            cfunc = ExprNodes.AttributeNode(self.pos, obj=class_node, attribute=self.entry.name)
2500            # Calling static c(p)def methods on an instance disallowed.
2501            # TODO(robertwb): Support by passing self to check for override?
2502            skip_dispatch = True
2503        else:
2504            type_entry = self.type.args[0].type.entry
2505            type_arg = ExprNodes.NameNode(self.pos, name=type_entry.name)
2506            type_arg.entry = type_entry
2507            cfunc = ExprNodes.AttributeNode(self.pos, obj=type_arg, attribute=self.entry.name)
2508        skip_dispatch = not is_module_scope or Options.lookup_module_cpdef
2509        c_call = ExprNodes.SimpleCallNode(
2510            self.pos,
2511            function=cfunc,
2512            args=[ExprNodes.NameNode(self.pos, name=n) for n in arg_names],
2513            wrapper_call=skip_dispatch)
2514        return ReturnStatNode(pos=self.pos, return_type=PyrexTypes.py_object_type, value=c_call)
2515
2516    def declare_arguments(self, env):
2517        for arg in self.type.args:
2518            if not arg.name:
2519                error(arg.pos, "Missing argument name")
2520            self.declare_argument(env, arg)
2521
2522    def need_gil_acquisition(self, lenv):
2523        return self.type.with_gil
2524
2525    def nogil_check(self, env):
2526        type = self.type
2527        with_gil = type.with_gil
2528        if type.nogil and not with_gil:
2529            if type.return_type.is_pyobject:
2530                error(self.pos,
2531                      "Function with Python return type cannot be declared nogil")
2532            for entry in self.local_scope.var_entries:
2533                if entry.type.is_pyobject and not entry.in_with_gil_block:
2534                    error(self.pos, "Function declared nogil has Python locals or temporaries")
2535
2536    def analyse_expressions(self, env):
2537        self.local_scope.directives = env.directives
2538        if self.py_func_stat is not None:
2539            # this will also analyse the default values and the function name assignment
2540            self.py_func_stat = self.py_func_stat.analyse_expressions(env)
2541        elif self.py_func is not None:
2542            # this will also analyse the default values
2543            self.py_func = self.py_func.analyse_expressions(env)
2544        else:
2545            self.analyse_default_values(env)
2546            self.analyse_annotations(env)
2547        self.acquire_gil = self.need_gil_acquisition(self.local_scope)
2548        return self
2549
2550    def needs_assignment_synthesis(self, env, code=None):
2551        return False
2552
2553    def generate_function_header(self, code, with_pymethdef, with_opt_args=1, with_dispatch=1, cname=None):
2554        scope = self.local_scope
2555        arg_decls = []
2556        type = self.type
2557        for arg in type.args[:len(type.args)-type.optional_arg_count]:
2558            arg_decl = arg.declaration_code()
2559            entry = scope.lookup(arg.name)
2560            if not entry.cf_used:
2561                arg_decl = 'CYTHON_UNUSED %s' % arg_decl
2562            arg_decls.append(arg_decl)
2563        if with_dispatch and self.overridable:
2564            dispatch_arg = PyrexTypes.c_int_type.declaration_code(
2565                Naming.skip_dispatch_cname)
2566            if self.override:
2567                arg_decls.append(dispatch_arg)
2568            else:
2569                arg_decls.append('CYTHON_UNUSED %s' % dispatch_arg)
2570        if type.optional_arg_count and with_opt_args:
2571            arg_decls.append(type.op_arg_struct.declaration_code(Naming.optional_args_cname))
2572        if type.has_varargs:
2573            arg_decls.append("...")
2574        if not arg_decls:
2575            arg_decls = ["void"]
2576        if cname is None:
2577            cname = self.entry.func_cname
2578        entity = type.function_header_code(cname, ', '.join(arg_decls))
2579        if self.entry.visibility == 'private' and '::' not in cname:
2580            storage_class = "static "
2581        else:
2582            storage_class = ""
2583        dll_linkage = None
2584        modifiers = code.build_function_modifiers(self.entry.func_modifiers)
2585
2586        header = self.return_type.declaration_code(entity, dll_linkage=dll_linkage)
2587        #print (storage_class, modifiers, header)
2588        needs_proto = self.is_c_class_method
2589        if self.template_declaration:
2590            if needs_proto:
2591                code.globalstate.parts['module_declarations'].putln(self.template_declaration)
2592            code.putln(self.template_declaration)
2593        if needs_proto:
2594            code.globalstate.parts['module_declarations'].putln(
2595                "%s%s%s; /* proto*/" % (storage_class, modifiers, header))
2596        code.putln("%s%s%s {" % (storage_class, modifiers, header))
2597
2598    def generate_argument_declarations(self, env, code):
2599        scope = self.local_scope
2600        for arg in self.args:
2601            if arg.default:
2602                entry = scope.lookup(arg.name)
2603                if self.override or entry.cf_used:
2604                    result = arg.calculate_default_value_code(code)
2605                    code.putln('%s = %s;' % (
2606                        arg.type.declaration_code(arg.cname), result))
2607
2608    def generate_keyword_list(self, code):
2609        pass
2610
2611    def generate_argument_parsing_code(self, env, code):
2612        i = 0
2613        used = 0
2614        scope = self.local_scope
2615        if self.type.optional_arg_count:
2616            code.putln('if (%s) {' % Naming.optional_args_cname)
2617            for arg in self.args:
2618                if arg.default:
2619                    entry = scope.lookup(arg.name)
2620                    if self.override or entry.cf_used:
2621                        code.putln('if (%s->%sn > %s) {' %
2622                                   (Naming.optional_args_cname,
2623                                    Naming.pyrex_prefix, i))
2624                        declarator = arg.declarator
2625                        while not hasattr(declarator, 'name'):
2626                            declarator = declarator.base
2627                        code.putln('%s = %s->%s;' %
2628                                   (arg.cname, Naming.optional_args_cname,
2629                                    self.type.opt_arg_cname(declarator.name)))
2630                        used += 1
2631                    i += 1
2632            for _ in range(used):
2633                code.putln('}')
2634            code.putln('}')
2635
2636        # Move arguments into closure if required
2637        def put_into_closure(entry):
2638            if entry.in_closure and not arg.default:
2639                code.putln('%s = %s;' % (entry.cname, entry.original_cname))
2640                code.put_var_incref(entry)
2641                code.put_var_giveref(entry)
2642        for arg in self.args:
2643            put_into_closure(scope.lookup_here(arg.name))
2644
2645
2646    def generate_argument_conversion_code(self, code):
2647        pass
2648
2649    def generate_argument_type_tests(self, code):
2650        # Generate type tests for args whose type in a parent
2651        # class is a supertype of the declared type.
2652        for arg in self.type.args:
2653            if arg.needs_type_test:
2654                self.generate_arg_type_test(arg, code)
2655            elif arg.type.is_pyobject and not arg.accept_none:
2656                self.generate_arg_none_check(arg, code)
2657
2658    def generate_execution_code(self, code):
2659        if code.globalstate.directives['linetrace']:
2660            code.mark_pos(self.pos)
2661            code.putln("")  # generate line tracing code
2662        super(CFuncDefNode, self).generate_execution_code(code)
2663        if self.py_func_stat:
2664            self.py_func_stat.generate_execution_code(code)
2665
2666    def error_value(self):
2667        if self.return_type.is_pyobject:
2668            return "0"
2669        else:
2670            #return None
2671            return self.entry.type.exception_value
2672
2673    def caller_will_check_exceptions(self):
2674        return self.entry.type.exception_check
2675
2676    def generate_wrapper_functions(self, code):
2677        # If the C signature of a function has changed, we need to generate
2678        # wrappers to put in the slots here.
2679        k = 0
2680        entry = self.entry
2681        func_type = entry.type
2682        while entry.prev_entry is not None:
2683            k += 1
2684            entry = entry.prev_entry
2685            entry.func_cname = "%s%swrap_%s" % (self.entry.func_cname, Naming.pyrex_prefix, k)
2686            code.putln()
2687            self.generate_function_header(
2688                code, 0,
2689                with_dispatch=entry.type.is_overridable,
2690                with_opt_args=entry.type.optional_arg_count,
2691                cname=entry.func_cname)
2692            if not self.return_type.is_void:
2693                code.put('return ')
2694            args = self.type.args
2695            arglist = [arg.cname for arg in args[:len(args)-self.type.optional_arg_count]]
2696            if entry.type.is_overridable:
2697                arglist.append(Naming.skip_dispatch_cname)
2698            elif func_type.is_overridable:
2699                arglist.append('0')
2700            if entry.type.optional_arg_count:
2701                arglist.append(Naming.optional_args_cname)
2702            elif func_type.optional_arg_count:
2703                arglist.append('NULL')
2704            code.putln('%s(%s);' % (self.entry.func_cname, ', '.join(arglist)))
2705            code.putln('}')
2706
2707
2708class PyArgDeclNode(Node):
2709    # Argument which must be a Python object (used
2710    # for * and ** arguments).
2711    #
2712    # name        string
2713    # entry       Symtab.Entry
2714    # annotation  ExprNode or None   Py3 argument annotation
2715    child_attrs = []
2716    is_self_arg = False
2717    is_type_arg = False
2718
2719    def generate_function_definitions(self, env, code):
2720        self.entry.generate_function_definitions(env, code)
2721
2722
2723class DecoratorNode(Node):
2724    # A decorator
2725    #
2726    # decorator    NameNode or CallNode or AttributeNode
2727    child_attrs = ['decorator']
2728
2729
2730class DefNode(FuncDefNode):
2731    # A Python function definition.
2732    #
2733    # name          string                 the Python name of the function
2734    # lambda_name   string                 the internal name of a lambda 'function'
2735    # decorators    [DecoratorNode]        list of decorators
2736    # args          [CArgDeclNode]         formal arguments
2737    # doc           EncodedString or None
2738    # body          StatListNode
2739    # return_type_annotation
2740    #               ExprNode or None       the Py3 return type annotation
2741    #
2742    #  The following subnode is constructed internally
2743    #  when the def statement is inside a Python class definition.
2744    #
2745    #  fused_py_func        DefNode     The original fused cpdef DefNode
2746    #                                   (in case this is a specialization)
2747    #  specialized_cpdefs   [DefNode]   list of specialized cpdef DefNodes
2748    #  py_cfunc_node  PyCFunctionNode/InnerFunctionNode   The PyCFunction to create and assign
2749    #
2750    # decorator_indirection IndirectionNode Used to remove __Pyx_Method_ClassMethod for fused functions
2751
2752    child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators", "return_type_annotation"]
2753    outer_attrs = ["decorators", "return_type_annotation"]
2754
2755    is_staticmethod = False
2756    is_classmethod = False
2757
2758    lambda_name = None
2759    reqd_kw_flags_cname = "0"
2760    is_wrapper = 0
2761    no_assignment_synthesis = 0
2762    decorators = None
2763    return_type_annotation = None
2764    entry = None
2765    acquire_gil = 0
2766    self_in_stararg = 0
2767    py_cfunc_node = None
2768    requires_classobj = False
2769    defaults_struct = None # Dynamic kwrds structure name
2770    doc = None
2771
2772    fused_py_func = False
2773    specialized_cpdefs = None
2774    py_wrapper = None
2775    py_wrapper_required = True
2776    func_cname = None
2777
2778    defaults_getter = None
2779
2780    def __init__(self, pos, **kwds):
2781        FuncDefNode.__init__(self, pos, **kwds)
2782        k = rk = r = 0
2783        for arg in self.args:
2784            if arg.kw_only:
2785                k += 1
2786                if not arg.default:
2787                    rk += 1
2788            if not arg.default:
2789                r += 1
2790        self.num_kwonly_args = k
2791        self.num_required_kw_args = rk
2792        self.num_required_args = r
2793
2794    def as_cfunction(self, cfunc=None, scope=None, overridable=True, returns=None, except_val=None, modifiers=None,
2795                     nogil=False, with_gil=False):
2796        if self.star_arg:
2797            error(self.star_arg.pos, "cdef function cannot have star argument")
2798        if self.starstar_arg:
2799            error(self.starstar_arg.pos, "cdef function cannot have starstar argument")
2800        exception_value, exception_check = except_val or (None, False)
2801
2802        if cfunc is None:
2803            cfunc_args = []
2804            for formal_arg in self.args:
2805                name_declarator, type = formal_arg.analyse(scope, nonempty=1)
2806                cfunc_args.append(PyrexTypes.CFuncTypeArg(name=name_declarator.name,
2807                                                          cname=None,
2808                                                          annotation=formal_arg.annotation,
2809                                                          type=py_object_type,
2810                                                          pos=formal_arg.pos))
2811            cfunc_type = PyrexTypes.CFuncType(return_type=py_object_type,
2812                                              args=cfunc_args,
2813                                              has_varargs=False,
2814                                              exception_value=None,
2815                                              exception_check=exception_check,
2816                                              nogil=nogil,
2817                                              with_gil=with_gil,
2818                                              is_overridable=overridable)
2819            cfunc = CVarDefNode(self.pos, type=cfunc_type)
2820        else:
2821            if scope is None:
2822                scope = cfunc.scope
2823            cfunc_type = cfunc.type
2824            if len(self.args) != len(cfunc_type.args) or cfunc_type.has_varargs:
2825                error(self.pos, "wrong number of arguments")
2826                error(cfunc.pos, "previous declaration here")
2827            for i, (formal_arg, type_arg) in enumerate(zip(self.args, cfunc_type.args)):
2828                name_declarator, type = formal_arg.analyse(scope, nonempty=1,
2829                                                           is_self_arg=(i == 0 and scope.is_c_class_scope))
2830                if type is None or type is PyrexTypes.py_object_type:
2831                    formal_arg.type = type_arg.type
2832                    formal_arg.name_declarator = name_declarator
2833
2834        if exception_value is None and cfunc_type.exception_value is not None:
2835            from .ExprNodes import ConstNode
2836            exception_value = ConstNode(
2837                self.pos, value=cfunc_type.exception_value, type=cfunc_type.return_type)
2838        declarator = CFuncDeclaratorNode(self.pos,
2839                                         base=CNameDeclaratorNode(self.pos, name=self.name, cname=None),
2840                                         args=self.args,
2841                                         has_varargs=False,
2842                                         exception_check=cfunc_type.exception_check,
2843                                         exception_value=exception_value,
2844                                         with_gil=cfunc_type.with_gil,
2845                                         nogil=cfunc_type.nogil)
2846        return CFuncDefNode(self.pos,
2847                            modifiers=modifiers or [],
2848                            base_type=CAnalysedBaseTypeNode(self.pos, type=cfunc_type.return_type),
2849                            declarator=declarator,
2850                            body=self.body,
2851                            doc=self.doc,
2852                            overridable=cfunc_type.is_overridable,
2853                            type=cfunc_type,
2854                            with_gil=cfunc_type.with_gil,
2855                            nogil=cfunc_type.nogil,
2856                            visibility='private',
2857                            api=False,
2858                            directive_locals=getattr(cfunc, 'directive_locals', {}),
2859                            directive_returns=returns)
2860
2861    def is_cdef_func_compatible(self):
2862        """Determines if the function's signature is compatible with a
2863        cdef function.  This can be used before calling
2864        .as_cfunction() to see if that will be successful.
2865        """
2866        if self.needs_closure:
2867            return False
2868        if self.star_arg or self.starstar_arg:
2869            return False
2870        return True
2871
2872    def analyse_declarations(self, env):
2873        if self.decorators:
2874            for decorator in self.decorators:
2875                func = decorator.decorator
2876                if func.is_name:
2877                    self.is_classmethod |= func.name == 'classmethod'
2878                    self.is_staticmethod |= func.name == 'staticmethod'
2879
2880        if self.is_classmethod and env.lookup_here('classmethod'):
2881            # classmethod() was overridden - not much we can do here ...
2882            self.is_classmethod = False
2883        if self.is_staticmethod and env.lookup_here('staticmethod'):
2884            # staticmethod() was overridden - not much we can do here ...
2885            self.is_staticmethod = False
2886
2887        if self.name == '__new__' and env.is_py_class_scope:
2888            self.is_staticmethod = 1
2889
2890        self.analyse_argument_types(env)
2891        if self.name == '<lambda>':
2892            self.declare_lambda_function(env)
2893        else:
2894            self.declare_pyfunction(env)
2895
2896        self.analyse_signature(env)
2897        self.return_type = self.entry.signature.return_type()
2898        # if a signature annotation provides a more specific return object type, use it
2899        if self.return_type is py_object_type and self.return_type_annotation:
2900            if env.directives['annotation_typing'] and not self.entry.is_special:
2901                _, return_type = analyse_type_annotation(self.return_type_annotation, env)
2902                if return_type and return_type.is_pyobject:
2903                    self.return_type = return_type
2904
2905        self.create_local_scope(env)
2906
2907        self.py_wrapper = DefNodeWrapper(
2908            self.pos,
2909            target=self,
2910            name=self.entry.name,
2911            args=self.args,
2912            star_arg=self.star_arg,
2913            starstar_arg=self.starstar_arg,
2914            return_type=self.return_type)
2915        self.py_wrapper.analyse_declarations(env)
2916
2917    def analyse_argument_types(self, env):
2918        self.directive_locals = env.directives.get('locals', {})
2919        allow_none_for_extension_args = env.directives['allow_none_for_extension_args']
2920
2921        f2s = env.fused_to_specific
2922        env.fused_to_specific = None
2923
2924        for arg in self.args:
2925            if hasattr(arg, 'name'):
2926                name_declarator = None
2927            else:
2928                base_type = arg.base_type.analyse(env)
2929                # If we hare in pythran mode and we got a buffer supported by
2930                # Pythran, we change this node to a fused type
2931                if has_np_pythran(env) and base_type.is_pythran_expr:
2932                    base_type = PyrexTypes.FusedType([
2933                        base_type,
2934                        #PyrexTypes.PythranExpr(pythran_type(self.type, "numpy_texpr")),
2935                        base_type.org_buffer])
2936                name_declarator, type = \
2937                    arg.declarator.analyse(base_type, env)
2938                arg.name = name_declarator.name
2939                arg.type = type
2940
2941                if type.is_fused:
2942                    self.has_fused_arguments = True
2943
2944            self.align_argument_type(env, arg)
2945            if name_declarator and name_declarator.cname:
2946                error(self.pos, "Python function argument cannot have C name specification")
2947            arg.type = arg.type.as_argument_type()
2948            arg.hdr_type = None
2949            arg.needs_conversion = 0
2950            arg.needs_type_test = 0
2951            arg.is_generic = 1
2952            if arg.type.is_pyobject or arg.type.is_buffer or arg.type.is_memoryviewslice:
2953                if arg.or_none:
2954                    arg.accept_none = True
2955                elif arg.not_none:
2956                    arg.accept_none = False
2957                elif (arg.type.is_extension_type or arg.type.is_builtin_type
2958                        or arg.type.is_buffer or arg.type.is_memoryviewslice):
2959                    if arg.default and arg.default.constant_result is None:
2960                        # special case: def func(MyType obj = None)
2961                        arg.accept_none = True
2962                    else:
2963                        # default depends on compiler directive
2964                        arg.accept_none = allow_none_for_extension_args
2965                else:
2966                    # probably just a plain 'object'
2967                    arg.accept_none = True
2968            else:
2969                arg.accept_none = True # won't be used, but must be there
2970                if arg.not_none:
2971                    error(arg.pos, "Only Python type arguments can have 'not None'")
2972                if arg.or_none:
2973                    error(arg.pos, "Only Python type arguments can have 'or None'")
2974        env.fused_to_specific = f2s
2975
2976        if has_np_pythran(env):
2977            self.np_args_idx = [i for i,a in enumerate(self.args) if a.type.is_numpy_buffer]
2978        else:
2979            self.np_args_idx = []
2980
2981    def analyse_signature(self, env):
2982        if self.entry.is_special:
2983            if self.decorators:
2984                error(self.pos, "special functions of cdef classes cannot have decorators")
2985            self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg)
2986        elif not env.directives['always_allow_keywords'] and not (self.star_arg or self.starstar_arg):
2987            # Use the simpler calling signature for zero- and one-argument functions.
2988            if self.entry.signature is TypeSlots.pyfunction_signature:
2989                if len(self.args) == 0:
2990                    self.entry.signature = TypeSlots.pyfunction_noargs
2991                elif len(self.args) == 1:
2992                    if self.args[0].default is None and not self.args[0].kw_only:
2993                        self.entry.signature = TypeSlots.pyfunction_onearg
2994            elif self.entry.signature is TypeSlots.pymethod_signature:
2995                if len(self.args) == 1:
2996                    self.entry.signature = TypeSlots.unaryfunc
2997                elif len(self.args) == 2:
2998                    if self.args[1].default is None and not self.args[1].kw_only:
2999                        self.entry.signature = TypeSlots.ibinaryfunc
3000
3001        sig = self.entry.signature
3002        nfixed = sig.num_fixed_args()
3003        if (sig is TypeSlots.pymethod_signature and nfixed == 1
3004               and len(self.args) == 0 and self.star_arg):
3005            # this is the only case where a diverging number of
3006            # arguments is not an error - when we have no explicit
3007            # 'self' parameter as in method(*args)
3008            sig = self.entry.signature = TypeSlots.pyfunction_signature # self is not 'really' used
3009            self.self_in_stararg = 1
3010            nfixed = 0
3011
3012        if self.is_staticmethod and env.is_c_class_scope:
3013            nfixed = 0
3014            self.self_in_stararg = True  # FIXME: why for staticmethods?
3015
3016            self.entry.signature = sig = copy.copy(sig)
3017            sig.fixed_arg_format = "*"
3018            sig.is_staticmethod = True
3019            sig.has_generic_args = True
3020
3021        if ((self.is_classmethod or self.is_staticmethod) and
3022                self.has_fused_arguments and env.is_c_class_scope):
3023            del self.decorator_indirection.stats[:]
3024
3025        for i in range(min(nfixed, len(self.args))):
3026            arg = self.args[i]
3027            arg.is_generic = 0
3028            if sig.is_self_arg(i) and not self.is_staticmethod:
3029                if self.is_classmethod:
3030                    arg.is_type_arg = 1
3031                    arg.hdr_type = arg.type = Builtin.type_type
3032                else:
3033                    arg.is_self_arg = 1
3034                    arg.hdr_type = arg.type = env.parent_type
3035                arg.needs_conversion = 0
3036            else:
3037                arg.hdr_type = sig.fixed_arg_type(i)
3038                if not arg.type.same_as(arg.hdr_type):
3039                    if arg.hdr_type.is_pyobject and arg.type.is_pyobject:
3040                        arg.needs_type_test = 1
3041                    else:
3042                        arg.needs_conversion = 1
3043            if arg.needs_conversion:
3044                arg.hdr_cname = Naming.arg_prefix + arg.name
3045            else:
3046                arg.hdr_cname = Naming.var_prefix + arg.name
3047
3048        if nfixed > len(self.args):
3049            self.bad_signature()
3050            return
3051        elif nfixed < len(self.args):
3052            if not sig.has_generic_args:
3053                self.bad_signature()
3054            for arg in self.args:
3055                if arg.is_generic and (arg.type.is_extension_type or arg.type.is_builtin_type):
3056                    arg.needs_type_test = 1
3057
3058    def bad_signature(self):
3059        sig = self.entry.signature
3060        expected_str = "%d" % sig.num_fixed_args()
3061        if sig.has_generic_args:
3062            expected_str += " or more"
3063        name = self.name
3064        if name.startswith("__") and name.endswith("__"):
3065            desc = "Special method"
3066        else:
3067            desc = "Method"
3068        error(self.pos, "%s %s has wrong number of arguments (%d declared, %s expected)" % (
3069            desc, self.name, len(self.args), expected_str))
3070
3071    def declare_pyfunction(self, env):
3072        #print "DefNode.declare_pyfunction:", self.name, "in", env ###
3073        name = self.name
3074        entry = env.lookup_here(name)
3075        if entry:
3076            if entry.is_final_cmethod and not env.parent_type.is_final_type:
3077                error(self.pos, "Only final types can have final Python (def/cpdef) methods")
3078            if entry.type.is_cfunction and not entry.is_builtin_cmethod and not self.is_wrapper:
3079                warning(self.pos, "Overriding cdef method with def method.", 5)
3080        entry = env.declare_pyfunction(name, self.pos, allow_redefine=not self.is_wrapper)
3081        self.entry = entry
3082        prefix = env.next_id(env.scope_prefix)
3083        self.entry.pyfunc_cname = Naming.pyfunc_prefix + prefix + name
3084        if Options.docstrings:
3085            entry.doc = embed_position(self.pos, self.doc)
3086            entry.doc_cname = Naming.funcdoc_prefix + prefix + name
3087            if entry.is_special:
3088                if entry.name in TypeSlots.invisible or not entry.doc or (
3089                        entry.name in '__getattr__' and env.directives['fast_getattr']):
3090                    entry.wrapperbase_cname = None
3091                else:
3092                    entry.wrapperbase_cname = Naming.wrapperbase_prefix + prefix + name
3093        else:
3094            entry.doc = None
3095
3096    def declare_lambda_function(self, env):
3097        entry = env.declare_lambda_function(self.lambda_name, self.pos)
3098        entry.doc = None
3099        self.entry = entry
3100        self.entry.pyfunc_cname = entry.cname
3101
3102    def declare_arguments(self, env):
3103        for arg in self.args:
3104            if not arg.name:
3105                error(arg.pos, "Missing argument name")
3106            if arg.needs_conversion:
3107                arg.entry = env.declare_var(arg.name, arg.type, arg.pos)
3108                if arg.type.is_pyobject:
3109                    arg.entry.init = "0"
3110            else:
3111                arg.entry = self.declare_argument(env, arg)
3112            arg.entry.is_arg = 1
3113            arg.entry.used = 1
3114            arg.entry.is_self_arg = arg.is_self_arg
3115        self.declare_python_arg(env, self.star_arg)
3116        self.declare_python_arg(env, self.starstar_arg)
3117
3118    def declare_python_arg(self, env, arg):
3119        if arg:
3120            if env.directives['infer_types'] != False:
3121                type = PyrexTypes.unspecified_type
3122            else:
3123                type = py_object_type
3124            entry = env.declare_var(arg.name, type, arg.pos)
3125            entry.is_arg = 1
3126            entry.used = 1
3127            entry.init = "0"
3128            entry.xdecref_cleanup = 1
3129            arg.entry = entry
3130
3131    def analyse_expressions(self, env):
3132        self.local_scope.directives = env.directives
3133        self.analyse_default_values(env)
3134        self.analyse_annotations(env)
3135        if self.return_type_annotation:
3136            self.return_type_annotation = self.analyse_annotation(env, self.return_type_annotation)
3137
3138        if not self.needs_assignment_synthesis(env) and self.decorators:
3139            for decorator in self.decorators[::-1]:
3140                decorator.decorator = decorator.decorator.analyse_expressions(env)
3141
3142        self.py_wrapper.prepare_argument_coercion(env)
3143        return self
3144
3145    def needs_assignment_synthesis(self, env, code=None):
3146        if self.is_staticmethod:
3147            return True
3148        if self.specialized_cpdefs or self.entry.is_fused_specialized:
3149            return False
3150        if self.no_assignment_synthesis:
3151            return False
3152        if self.entry.is_special:
3153            return False
3154        if self.entry.is_anonymous:
3155            return True
3156        if env.is_module_scope or env.is_c_class_scope:
3157            if code is None:
3158                return self.local_scope.directives['binding']
3159            else:
3160                return code.globalstate.directives['binding']
3161        return env.is_py_class_scope or env.is_closure_scope
3162
3163    def error_value(self):
3164        return self.entry.signature.error_value
3165
3166    def caller_will_check_exceptions(self):
3167        return self.entry.signature.exception_check
3168
3169    def generate_function_definitions(self, env, code):
3170        if self.defaults_getter:
3171            # defaults getter must never live in class scopes, it's always a module function
3172            self.defaults_getter.generate_function_definitions(env.global_scope(), code)
3173
3174        # Before closure cnames are mangled
3175        if self.py_wrapper_required:
3176            # func_cname might be modified by @cname
3177            self.py_wrapper.func_cname = self.entry.func_cname
3178            self.py_wrapper.generate_function_definitions(env, code)
3179        FuncDefNode.generate_function_definitions(self, env, code)
3180
3181    def generate_function_header(self, code, with_pymethdef, proto_only=0):
3182        if proto_only:
3183            if self.py_wrapper_required:
3184                self.py_wrapper.generate_function_header(
3185                    code, with_pymethdef, True)
3186            return
3187        arg_code_list = []
3188        if self.entry.signature.has_dummy_arg:
3189            self_arg = 'PyObject *%s' % Naming.self_cname
3190            if not self.needs_outer_scope:
3191                self_arg = 'CYTHON_UNUSED ' + self_arg
3192            arg_code_list.append(self_arg)
3193
3194        def arg_decl_code(arg):
3195            entry = arg.entry
3196            if entry.in_closure:
3197                cname = entry.original_cname
3198            else:
3199                cname = entry.cname
3200            decl = entry.type.declaration_code(cname)
3201            if not entry.cf_used:
3202                decl = 'CYTHON_UNUSED ' + decl
3203            return decl
3204
3205        for arg in self.args:
3206            arg_code_list.append(arg_decl_code(arg))
3207        if self.star_arg:
3208            arg_code_list.append(arg_decl_code(self.star_arg))
3209        if self.starstar_arg:
3210            arg_code_list.append(arg_decl_code(self.starstar_arg))
3211        if arg_code_list:
3212            arg_code = ', '.join(arg_code_list)
3213        else:
3214            arg_code = 'void'  # No arguments
3215        dc = self.return_type.declaration_code(self.entry.pyfunc_cname)
3216
3217        decls_code = code.globalstate['decls']
3218        preprocessor_guard = self.get_preprocessor_guard()
3219        if preprocessor_guard:
3220            decls_code.putln(preprocessor_guard)
3221        decls_code.putln(
3222            "static %s(%s); /* proto */" % (dc, arg_code))
3223        if preprocessor_guard:
3224            decls_code.putln("#endif")
3225        code.putln("static %s(%s) {" % (dc, arg_code))
3226
3227    def generate_argument_declarations(self, env, code):
3228        pass
3229
3230    def generate_keyword_list(self, code):
3231        pass
3232
3233    def generate_argument_parsing_code(self, env, code):
3234        # Move arguments into closure if required
3235        def put_into_closure(entry):
3236            if entry.in_closure:
3237                code.putln('%s = %s;' % (entry.cname, entry.original_cname))
3238                if entry.xdecref_cleanup:
3239                    # mostly applies to the starstar arg - this can sometimes be NULL
3240                    # so must be xincrefed instead
3241                    code.put_var_xincref(entry)
3242                    code.put_var_xgiveref(entry)
3243                else:
3244                    code.put_var_incref(entry)
3245                    code.put_var_giveref(entry)
3246        for arg in self.args:
3247            put_into_closure(arg.entry)
3248        for arg in self.star_arg, self.starstar_arg:
3249            if arg:
3250                put_into_closure(arg.entry)
3251
3252    def generate_argument_type_tests(self, code):
3253        pass
3254
3255
3256class DefNodeWrapper(FuncDefNode):
3257    # DefNode python wrapper code generator
3258
3259    defnode = None
3260    target = None # Target DefNode
3261
3262    def __init__(self, *args, **kwargs):
3263        FuncDefNode.__init__(self, *args, **kwargs)
3264        self.num_kwonly_args = self.target.num_kwonly_args
3265        self.num_required_kw_args = self.target.num_required_kw_args
3266        self.num_required_args = self.target.num_required_args
3267        self.self_in_stararg = self.target.self_in_stararg
3268        self.signature = None
3269
3270    def analyse_declarations(self, env):
3271        target_entry = self.target.entry
3272        name = self.name
3273        prefix = env.next_id(env.scope_prefix)
3274        target_entry.func_cname = Naming.pywrap_prefix + prefix + name
3275        target_entry.pymethdef_cname = Naming.pymethdef_prefix + prefix + name
3276
3277        self.signature = target_entry.signature
3278
3279        self.np_args_idx = self.target.np_args_idx
3280
3281    def prepare_argument_coercion(self, env):
3282        # This is only really required for Cython utility code at this time,
3283        # everything else can be done during code generation.  But we expand
3284        # all utility code here, simply because we cannot easily distinguish
3285        # different code types.
3286        for arg in self.args:
3287            if not arg.type.is_pyobject:
3288                if not arg.type.create_from_py_utility_code(env):
3289                    pass # will fail later
3290            elif arg.hdr_type and not arg.hdr_type.is_pyobject:
3291                if not arg.hdr_type.create_to_py_utility_code(env):
3292                    pass # will fail later
3293
3294        if self.starstar_arg and not self.starstar_arg.entry.cf_used:
3295            # we will set the kwargs argument to NULL instead of a new dict
3296            # and must therefore correct the control flow state
3297            entry = self.starstar_arg.entry
3298            entry.xdecref_cleanup = 1
3299            for ass in entry.cf_assignments:
3300                if not ass.is_arg and ass.lhs.is_name:
3301                    ass.lhs.cf_maybe_null = True
3302
3303    def signature_has_nongeneric_args(self):
3304        argcount = len(self.args)
3305        if argcount == 0 or (
3306                argcount == 1 and (self.args[0].is_self_arg or
3307                                   self.args[0].is_type_arg)):
3308            return 0
3309        return 1
3310
3311    def signature_has_generic_args(self):
3312        return self.signature.has_generic_args
3313
3314    def generate_function_body(self, code):
3315        args = []
3316        if self.signature.has_dummy_arg:
3317            args.append(Naming.self_cname)
3318        for arg in self.args:
3319            if arg.hdr_type and not (arg.type.is_memoryviewslice or
3320                                     arg.type.is_struct or
3321                                     arg.type.is_complex):
3322                args.append(arg.type.cast_code(arg.entry.cname))
3323            else:
3324                args.append(arg.entry.cname)
3325        if self.star_arg:
3326            args.append(self.star_arg.entry.cname)
3327        if self.starstar_arg:
3328            args.append(self.starstar_arg.entry.cname)
3329        args = ', '.join(args)
3330        if not self.return_type.is_void:
3331            code.put('%s = ' % Naming.retval_cname)
3332        code.putln('%s(%s);' % (
3333            self.target.entry.pyfunc_cname, args))
3334
3335    def generate_function_definitions(self, env, code):
3336        lenv = self.target.local_scope
3337        # Generate C code for header and body of function
3338        code.mark_pos(self.pos)
3339        code.putln("")
3340        code.putln("/* Python wrapper */")
3341        preprocessor_guard = self.target.get_preprocessor_guard()
3342        if preprocessor_guard:
3343            code.putln(preprocessor_guard)
3344
3345        code.enter_cfunc_scope(lenv)
3346        code.return_from_error_cleanup_label = code.new_label()
3347
3348        with_pymethdef = (self.target.needs_assignment_synthesis(env, code) or
3349                          self.target.pymethdef_required)
3350        self.generate_function_header(code, with_pymethdef)
3351        self.generate_argument_declarations(lenv, code)
3352        tempvardecl_code = code.insertion_point()
3353
3354        if self.return_type.is_pyobject:
3355            retval_init = ' = 0'
3356        else:
3357            retval_init = ''
3358        if not self.return_type.is_void:
3359            code.putln('%s%s;' % (
3360                self.return_type.declaration_code(Naming.retval_cname),
3361                retval_init))
3362        code.put_declare_refcount_context()
3363        code.put_setup_refcount_context('%s (wrapper)' % self.name)
3364
3365        self.generate_argument_parsing_code(lenv, code)
3366        self.generate_argument_type_tests(code)
3367        self.generate_function_body(code)
3368
3369        # ----- Go back and insert temp variable declarations
3370        tempvardecl_code.put_temp_declarations(code.funcstate)
3371
3372        code.mark_pos(self.pos)
3373        code.putln("")
3374        code.putln("/* function exit code */")
3375
3376        # ----- Error cleanup
3377        if code.error_label in code.labels_used:
3378            code.put_goto(code.return_label)
3379            code.put_label(code.error_label)
3380            for cname, type in code.funcstate.all_managed_temps():
3381                code.put_xdecref(cname, type)
3382            err_val = self.error_value()
3383            if err_val is not None:
3384                code.putln("%s = %s;" % (Naming.retval_cname, err_val))
3385
3386        # ----- Non-error return cleanup
3387        code.put_label(code.return_label)
3388        for entry in lenv.var_entries:
3389            if entry.is_arg and entry.type.is_pyobject:
3390                code.put_var_decref(entry)
3391
3392        code.put_finish_refcount_context()
3393        if not self.return_type.is_void:
3394            code.putln("return %s;" % Naming.retval_cname)
3395        code.putln('}')
3396        code.exit_cfunc_scope()
3397        if preprocessor_guard:
3398            code.putln("#endif /*!(%s)*/" % preprocessor_guard)
3399
3400    def generate_function_header(self, code, with_pymethdef, proto_only=0):
3401        arg_code_list = []
3402        sig = self.signature
3403
3404        if sig.has_dummy_arg or self.self_in_stararg:
3405            arg_code = "PyObject *%s" % Naming.self_cname
3406            if not sig.has_dummy_arg:
3407                arg_code = 'CYTHON_UNUSED ' + arg_code
3408            arg_code_list.append(arg_code)
3409
3410        for arg in self.args:
3411            if not arg.is_generic:
3412                if arg.is_self_arg or arg.is_type_arg:
3413                    arg_code_list.append("PyObject *%s" % arg.hdr_cname)
3414                else:
3415                    arg_code_list.append(
3416                        arg.hdr_type.declaration_code(arg.hdr_cname))
3417        entry = self.target.entry
3418        if not entry.is_special and sig.method_flags() == [TypeSlots.method_noargs]:
3419            arg_code_list.append("CYTHON_UNUSED PyObject *unused")
3420        if entry.scope.is_c_class_scope and entry.name == "__ipow__":
3421            arg_code_list.append("CYTHON_UNUSED PyObject *unused")
3422        if sig.has_generic_args:
3423            arg_code_list.append(
3424                "PyObject *%s, PyObject *%s" % (
3425                    Naming.args_cname, Naming.kwds_cname))
3426        arg_code = ", ".join(arg_code_list)
3427
3428        # Prevent warning: unused function '__pyx_pw_5numpy_7ndarray_1__getbuffer__'
3429        mf = ""
3430        if (entry.name in ("__getbuffer__", "__releasebuffer__")
3431                and entry.scope.is_c_class_scope):
3432            mf = "CYTHON_UNUSED "
3433            with_pymethdef = False
3434
3435        dc = self.return_type.declaration_code(entry.func_cname)
3436        header = "static %s%s(%s)" % (mf, dc, arg_code)
3437        code.putln("%s; /*proto*/" % header)
3438
3439        if proto_only:
3440            if self.target.fused_py_func:
3441                # If we are the specialized version of the cpdef, we still
3442                # want the prototype for the "fused cpdef", in case we're
3443                # checking to see if our method was overridden in Python
3444                self.target.fused_py_func.generate_function_header(
3445                    code, with_pymethdef, proto_only=True)
3446            return
3447
3448        if (Options.docstrings and entry.doc and
3449                not self.target.fused_py_func and
3450                not entry.scope.is_property_scope and
3451                (not entry.is_special or entry.wrapperbase_cname)):
3452            # h_code = code.globalstate['h_code']
3453            docstr = entry.doc
3454
3455            if docstr.is_unicode:
3456                docstr = docstr.as_utf8_string()
3457
3458            if not (entry.is_special and entry.name in ('__getbuffer__', '__releasebuffer__')):
3459                code.putln('static char %s[] = %s;' % (
3460                    entry.doc_cname,
3461                    docstr.as_c_string_literal()))
3462
3463            if entry.is_special:
3464                code.putln('#if CYTHON_COMPILING_IN_CPYTHON')
3465                code.putln(
3466                    "struct wrapperbase %s;" % entry.wrapperbase_cname)
3467                code.putln('#endif')
3468
3469        if with_pymethdef or self.target.fused_py_func:
3470            code.put(
3471                "static PyMethodDef %s = " % entry.pymethdef_cname)
3472            code.put_pymethoddef(self.target.entry, ";", allow_skip=False)
3473        code.putln("%s {" % header)
3474
3475    def generate_argument_declarations(self, env, code):
3476        for arg in self.args:
3477            if arg.is_generic:
3478                if arg.needs_conversion:
3479                    code.putln("PyObject *%s = 0;" % arg.hdr_cname)
3480                else:
3481                    code.put_var_declaration(arg.entry)
3482        for entry in env.var_entries:
3483            if entry.is_arg:
3484                code.put_var_declaration(entry)
3485
3486    def generate_argument_parsing_code(self, env, code):
3487        # Generate fast equivalent of PyArg_ParseTuple call for
3488        # generic arguments, if any, including args/kwargs
3489        old_error_label = code.new_error_label()
3490        our_error_label = code.error_label
3491        end_label = code.new_label("argument_unpacking_done")
3492
3493        has_kwonly_args = self.num_kwonly_args > 0
3494        has_star_or_kw_args = self.star_arg is not None \
3495            or self.starstar_arg is not None or has_kwonly_args
3496
3497        for arg in self.args:
3498            if not arg.type.is_pyobject:
3499                if not arg.type.create_from_py_utility_code(env):
3500                    pass  # will fail later
3501
3502        if not self.signature_has_generic_args():
3503            if has_star_or_kw_args:
3504                error(self.pos, "This method cannot have * or keyword arguments")
3505            self.generate_argument_conversion_code(code)
3506
3507        elif not self.signature_has_nongeneric_args():
3508            # func(*args) or func(**kw) or func(*args, **kw)
3509            self.generate_stararg_copy_code(code)
3510
3511        else:
3512            self.generate_tuple_and_keyword_parsing_code(self.args, end_label, code)
3513
3514        code.error_label = old_error_label
3515        if code.label_used(our_error_label):
3516            if not code.label_used(end_label):
3517                code.put_goto(end_label)
3518            code.put_label(our_error_label)
3519            if has_star_or_kw_args:
3520                self.generate_arg_decref(self.star_arg, code)
3521                if self.starstar_arg:
3522                    if self.starstar_arg.entry.xdecref_cleanup:
3523                        code.put_var_xdecref_clear(self.starstar_arg.entry)
3524                    else:
3525                        code.put_var_decref_clear(self.starstar_arg.entry)
3526            code.put_add_traceback(self.target.entry.qualified_name)
3527            code.put_finish_refcount_context()
3528            code.putln("return %s;" % self.error_value())
3529        if code.label_used(end_label):
3530            code.put_label(end_label)
3531
3532    def generate_arg_xdecref(self, arg, code):
3533        if arg:
3534            code.put_var_xdecref_clear(arg.entry)
3535
3536    def generate_arg_decref(self, arg, code):
3537        if arg:
3538            code.put_var_decref_clear(arg.entry)
3539
3540    def generate_stararg_copy_code(self, code):
3541        if not self.star_arg:
3542            code.globalstate.use_utility_code(
3543                UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c"))
3544            code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > 0)) {" %
3545                       Naming.args_cname)
3546            code.put('__Pyx_RaiseArgtupleInvalid("%s", 1, 0, 0, PyTuple_GET_SIZE(%s)); return %s;' % (
3547                self.name, Naming.args_cname, self.error_value()))
3548            code.putln("}")
3549
3550        if self.starstar_arg:
3551            if self.star_arg or not self.starstar_arg.entry.cf_used:
3552                kwarg_check = "unlikely(%s)" % Naming.kwds_cname
3553            else:
3554                kwarg_check = "%s" % Naming.kwds_cname
3555        else:
3556            kwarg_check = "unlikely(%s) && unlikely(PyDict_Size(%s) > 0)" % (
3557                Naming.kwds_cname, Naming.kwds_cname)
3558        code.globalstate.use_utility_code(
3559            UtilityCode.load_cached("KeywordStringCheck", "FunctionArguments.c"))
3560        code.putln(
3561            "if (%s && unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % (
3562                kwarg_check, Naming.kwds_cname, self.name,
3563                bool(self.starstar_arg), self.error_value()))
3564
3565        if self.starstar_arg and self.starstar_arg.entry.cf_used:
3566            if all(ref.node.allow_null for ref in self.starstar_arg.entry.cf_references):
3567                code.putln("if (%s) {" % kwarg_check)
3568                code.putln("%s = PyDict_Copy(%s); if (unlikely(!%s)) return %s;" % (
3569                    self.starstar_arg.entry.cname,
3570                    Naming.kwds_cname,
3571                    self.starstar_arg.entry.cname,
3572                    self.error_value()))
3573                code.put_gotref(self.starstar_arg.entry.cname)
3574                code.putln("} else {")
3575                code.putln("%s = NULL;" % (self.starstar_arg.entry.cname,))
3576                code.putln("}")
3577                self.starstar_arg.entry.xdecref_cleanup = 1
3578            else:
3579                code.put("%s = (%s) ? PyDict_Copy(%s) : PyDict_New(); " % (
3580                    self.starstar_arg.entry.cname,
3581                    Naming.kwds_cname,
3582                    Naming.kwds_cname))
3583                code.putln("if (unlikely(!%s)) return %s;" % (
3584                    self.starstar_arg.entry.cname, self.error_value()))
3585                self.starstar_arg.entry.xdecref_cleanup = 0
3586                code.put_gotref(self.starstar_arg.entry.cname)
3587
3588        if self.self_in_stararg and not self.target.is_staticmethod:
3589            # need to create a new tuple with 'self' inserted as first item
3590            code.put("%s = PyTuple_New(PyTuple_GET_SIZE(%s)+1); if (unlikely(!%s)) " % (
3591                self.star_arg.entry.cname,
3592                Naming.args_cname,
3593                self.star_arg.entry.cname))
3594            if self.starstar_arg and self.starstar_arg.entry.cf_used:
3595                code.putln("{")
3596                code.put_xdecref_clear(self.starstar_arg.entry.cname, py_object_type)
3597                code.putln("return %s;" % self.error_value())
3598                code.putln("}")
3599            else:
3600                code.putln("return %s;" % self.error_value())
3601            code.put_gotref(self.star_arg.entry.cname)
3602            code.put_incref(Naming.self_cname, py_object_type)
3603            code.put_giveref(Naming.self_cname)
3604            code.putln("PyTuple_SET_ITEM(%s, 0, %s);" % (
3605                self.star_arg.entry.cname, Naming.self_cname))
3606            temp = code.funcstate.allocate_temp(PyrexTypes.c_py_ssize_t_type, manage_ref=False)
3607            code.putln("for (%s=0; %s < PyTuple_GET_SIZE(%s); %s++) {" % (
3608                temp, temp, Naming.args_cname, temp))
3609            code.putln("PyObject* item = PyTuple_GET_ITEM(%s, %s);" % (
3610                Naming.args_cname, temp))
3611            code.put_incref("item", py_object_type)
3612            code.put_giveref("item")
3613            code.putln("PyTuple_SET_ITEM(%s, %s+1, item);" % (
3614                self.star_arg.entry.cname, temp))
3615            code.putln("}")
3616            code.funcstate.release_temp(temp)
3617            self.star_arg.entry.xdecref_cleanup = 0
3618        elif self.star_arg:
3619            code.put_incref(Naming.args_cname, py_object_type)
3620            code.putln("%s = %s;" % (
3621                self.star_arg.entry.cname,
3622                Naming.args_cname))
3623            self.star_arg.entry.xdecref_cleanup = 0
3624
3625    def generate_tuple_and_keyword_parsing_code(self, args, success_label, code):
3626        argtuple_error_label = code.new_label("argtuple_error")
3627
3628        positional_args = []
3629        required_kw_only_args = []
3630        optional_kw_only_args = []
3631        for arg in args:
3632            if arg.is_generic:
3633                if arg.default:
3634                    if not arg.is_self_arg and not arg.is_type_arg:
3635                        if arg.kw_only:
3636                            optional_kw_only_args.append(arg)
3637                        else:
3638                            positional_args.append(arg)
3639                elif arg.kw_only:
3640                    required_kw_only_args.append(arg)
3641                elif not arg.is_self_arg and not arg.is_type_arg:
3642                    positional_args.append(arg)
3643
3644        # sort required kw-only args before optional ones to avoid special
3645        # cases in the unpacking code
3646        kw_only_args = required_kw_only_args + optional_kw_only_args
3647
3648        min_positional_args = self.num_required_args - self.num_required_kw_args
3649        if len(args) > 0 and (args[0].is_self_arg or args[0].is_type_arg):
3650            min_positional_args -= 1
3651        max_positional_args = len(positional_args)
3652        has_fixed_positional_count = not self.star_arg and \
3653            min_positional_args == max_positional_args
3654        has_kw_only_args = bool(kw_only_args)
3655
3656        if self.starstar_arg or self.star_arg:
3657            self.generate_stararg_init_code(max_positional_args, code)
3658
3659        code.putln('{')
3660        all_args = tuple(positional_args) + tuple(kw_only_args)
3661        code.putln("static PyObject **%s[] = {%s,0};" % (
3662            Naming.pykwdlist_cname,
3663            ','.join(['&%s' % code.intern_identifier(arg.name)
3664                      for arg in all_args])))
3665
3666        # Before being converted and assigned to the target variables,
3667        # borrowed references to all unpacked argument values are
3668        # collected into a local PyObject* array called "values",
3669        # regardless if they were taken from default arguments,
3670        # positional arguments or keyword arguments.  Note that
3671        # C-typed default arguments are handled at conversion time,
3672        # so their array value is NULL in the end if no argument
3673        # was passed for them.
3674        self.generate_argument_values_setup_code(all_args, code)
3675
3676        # --- optimised code when we receive keyword arguments
3677        code.putln("if (%s(%s)) {" % (
3678            (self.num_required_kw_args > 0) and "likely" or "unlikely",
3679            Naming.kwds_cname))
3680        self.generate_keyword_unpacking_code(
3681            min_positional_args, max_positional_args,
3682            has_fixed_positional_count, has_kw_only_args,
3683            all_args, argtuple_error_label, code)
3684
3685        # --- optimised code when we do not receive any keyword arguments
3686        if (self.num_required_kw_args and min_positional_args > 0) or min_positional_args == max_positional_args:
3687            # Python raises arg tuple related errors first, so we must
3688            # check the length here
3689            if min_positional_args == max_positional_args and not self.star_arg:
3690                compare = '!='
3691            else:
3692                compare = '<'
3693            code.putln('} else if (PyTuple_GET_SIZE(%s) %s %d) {' % (
3694                Naming.args_cname, compare, min_positional_args))
3695            code.put_goto(argtuple_error_label)
3696
3697        if self.num_required_kw_args:
3698            # pure error case: keywords required but not passed
3699            if max_positional_args > min_positional_args and not self.star_arg:
3700                code.putln('} else if (PyTuple_GET_SIZE(%s) > %d) {' % (
3701                    Naming.args_cname, max_positional_args))
3702                code.put_goto(argtuple_error_label)
3703            code.putln('} else {')
3704            for i, arg in enumerate(kw_only_args):
3705                if not arg.default:
3706                    pystring_cname = code.intern_identifier(arg.name)
3707                    # required keyword-only argument missing
3708                    code.globalstate.use_utility_code(
3709                        UtilityCode.load_cached("RaiseKeywordRequired", "FunctionArguments.c"))
3710                    code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % (
3711                        self.name,
3712                        pystring_cname))
3713                    code.putln(code.error_goto(self.pos))
3714                    break
3715
3716        else:
3717            # optimised tuple unpacking code
3718            code.putln('} else {')
3719            if min_positional_args == max_positional_args:
3720                # parse the exact number of positional arguments from
3721                # the args tuple
3722                for i, arg in enumerate(positional_args):
3723                    code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (i, Naming.args_cname, i))
3724            else:
3725                # parse the positional arguments from the variable length
3726                # args tuple and reject illegal argument tuple sizes
3727                code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
3728                if self.star_arg:
3729                    code.putln('default:')
3730                reversed_args = list(enumerate(positional_args))[::-1]
3731                for i, arg in reversed_args:
3732                    if i >= min_positional_args-1:
3733                        if i != reversed_args[0][0]:
3734                            code.putln('CYTHON_FALLTHROUGH;')
3735                        code.put('case %2d: ' % (i+1))
3736                    code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (i, Naming.args_cname, i))
3737                if min_positional_args == 0:
3738                    code.putln('CYTHON_FALLTHROUGH;')
3739                    code.put('case  0: ')
3740                code.putln('break;')
3741                if self.star_arg:
3742                    if min_positional_args:
3743                        for i in range(min_positional_args-1, -1, -1):
3744                            code.putln('case %2d:' % i)
3745                        code.put_goto(argtuple_error_label)
3746                else:
3747                    code.put('default: ')
3748                    code.put_goto(argtuple_error_label)
3749                code.putln('}')
3750
3751        code.putln('}') # end of the conditional unpacking blocks
3752
3753        # Convert arg values to their final type and assign them.
3754        # Also inject non-Python default arguments, which do cannot
3755        # live in the values[] array.
3756        for i, arg in enumerate(all_args):
3757            self.generate_arg_assignment(arg, "values[%d]" % i, code)
3758
3759        code.putln('}') # end of the whole argument unpacking block
3760
3761        if code.label_used(argtuple_error_label):
3762            code.put_goto(success_label)
3763            code.put_label(argtuple_error_label)
3764            code.globalstate.use_utility_code(
3765                UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c"))
3766            code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, PyTuple_GET_SIZE(%s)); ' % (
3767                self.name, has_fixed_positional_count,
3768                min_positional_args, max_positional_args,
3769                Naming.args_cname))
3770            code.putln(code.error_goto(self.pos))
3771
3772    def generate_arg_assignment(self, arg, item, code):
3773        if arg.type.is_pyobject:
3774            # Python default arguments were already stored in 'item' at the very beginning
3775            if arg.is_generic:
3776                item = PyrexTypes.typecast(arg.type, PyrexTypes.py_object_type, item)
3777            entry = arg.entry
3778            code.putln("%s = %s;" % (entry.cname, item))
3779        else:
3780            if arg.type.from_py_function:
3781                if arg.default:
3782                    # C-typed default arguments must be handled here
3783                    code.putln('if (%s) {' % item)
3784                code.putln(arg.type.from_py_call_code(
3785                    item, arg.entry.cname, arg.pos, code))
3786                if arg.default:
3787                    code.putln('} else {')
3788                    code.putln("%s = %s;" % (
3789                        arg.entry.cname,
3790                        arg.calculate_default_value_code(code)))
3791                    if arg.type.is_memoryviewslice:
3792                        code.put_incref_memoryviewslice(arg.entry.cname,
3793                                                        have_gil=True)
3794                    code.putln('}')
3795            else:
3796                error(arg.pos, "Cannot convert Python object argument to type '%s'" % arg.type)
3797
3798    def generate_stararg_init_code(self, max_positional_args, code):
3799        if self.starstar_arg:
3800            self.starstar_arg.entry.xdecref_cleanup = 0
3801            code.putln('%s = PyDict_New(); if (unlikely(!%s)) return %s;' % (
3802                self.starstar_arg.entry.cname,
3803                self.starstar_arg.entry.cname,
3804                self.error_value()))
3805            code.put_gotref(self.starstar_arg.entry.cname)
3806        if self.star_arg:
3807            self.star_arg.entry.xdecref_cleanup = 0
3808            code.putln('if (PyTuple_GET_SIZE(%s) > %d) {' % (
3809                Naming.args_cname,
3810                max_positional_args))
3811            code.putln('%s = PyTuple_GetSlice(%s, %d, PyTuple_GET_SIZE(%s));' % (
3812                self.star_arg.entry.cname, Naming.args_cname,
3813                max_positional_args, Naming.args_cname))
3814            code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname)
3815            if self.starstar_arg:
3816                code.put_decref_clear(self.starstar_arg.entry.cname, py_object_type)
3817            code.put_finish_refcount_context()
3818            code.putln('return %s;' % self.error_value())
3819            code.putln('}')
3820            code.put_gotref(self.star_arg.entry.cname)
3821            code.putln('} else {')
3822            code.put("%s = %s; " % (self.star_arg.entry.cname, Naming.empty_tuple))
3823            code.put_incref(Naming.empty_tuple, py_object_type)
3824            code.putln('}')
3825
3826    def generate_argument_values_setup_code(self, args, code):
3827        max_args = len(args)
3828        # the 'values' array collects borrowed references to arguments
3829        # before doing any type coercion etc.
3830        code.putln("PyObject* values[%d] = {%s};" % (
3831            max_args, ','.join('0'*max_args)))
3832
3833        if self.target.defaults_struct:
3834            code.putln('%s *%s = __Pyx_CyFunction_Defaults(%s, %s);' % (
3835                self.target.defaults_struct, Naming.dynamic_args_cname,
3836                self.target.defaults_struct, Naming.self_cname))
3837
3838        # assign borrowed Python default values to the values array,
3839        # so that they can be overwritten by received arguments below
3840        for i, arg in enumerate(args):
3841            if arg.default and arg.type.is_pyobject:
3842                default_value = arg.calculate_default_value_code(code)
3843                code.putln('values[%d] = %s;' % (i, arg.type.as_pyobject(default_value)))
3844
3845    def generate_keyword_unpacking_code(self, min_positional_args, max_positional_args,
3846                                        has_fixed_positional_count, has_kw_only_args,
3847                                        all_args, argtuple_error_label, code):
3848        code.putln('Py_ssize_t kw_args;')
3849        code.putln('const Py_ssize_t pos_args = PyTuple_GET_SIZE(%s);' % Naming.args_cname)
3850        # copy the values from the args tuple and check that it's not too long
3851        code.putln('switch (pos_args) {')
3852        if self.star_arg:
3853            code.putln('default:')
3854        for i in range(max_positional_args-1, -1, -1):
3855            code.put('case %2d: ' % (i+1))
3856            code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (
3857                i, Naming.args_cname, i))
3858            code.putln('CYTHON_FALLTHROUGH;')
3859        code.putln('case  0: break;')
3860        if not self.star_arg:
3861            code.put('default: ') # more arguments than allowed
3862            code.put_goto(argtuple_error_label)
3863        code.putln('}')
3864
3865        # The code above is very often (but not always) the same as
3866        # the optimised non-kwargs tuple unpacking code, so we keep
3867        # the code block above at the very top, before the following
3868        # 'external' PyDict_Size() call, to make it easy for the C
3869        # compiler to merge the two separate tuple unpacking
3870        # implementations into one when they turn out to be identical.
3871
3872        # If we received kwargs, fill up the positional/required
3873        # arguments with values from the kw dict
3874        code.putln('kw_args = PyDict_Size(%s);' % Naming.kwds_cname)
3875        if self.num_required_args or max_positional_args > 0:
3876            last_required_arg = -1
3877            for i, arg in enumerate(all_args):
3878                if not arg.default:
3879                    last_required_arg = i
3880            if last_required_arg < max_positional_args:
3881                last_required_arg = max_positional_args-1
3882            if max_positional_args > 0:
3883                code.putln('switch (pos_args) {')
3884            for i, arg in enumerate(all_args[:last_required_arg+1]):
3885                if max_positional_args > 0 and i <= max_positional_args:
3886                    if i != 0:
3887                        code.putln('CYTHON_FALLTHROUGH;')
3888                    if self.star_arg and i == max_positional_args:
3889                        code.putln('default:')
3890                    else:
3891                        code.putln('case %2d:' % i)
3892                pystring_cname = code.intern_identifier(arg.name)
3893                if arg.default:
3894                    if arg.kw_only:
3895                        # optional kw-only args are handled separately below
3896                        continue
3897                    code.putln('if (kw_args > 0) {')
3898                    # don't overwrite default argument
3899                    code.putln('PyObject* value = __Pyx_PyDict_GetItemStr(%s, %s);' % (
3900                        Naming.kwds_cname, pystring_cname))
3901                    code.putln('if (value) { values[%d] = value; kw_args--; }' % i)
3902                    code.putln('}')
3903                else:
3904                    code.putln('if (likely((values[%d] = __Pyx_PyDict_GetItemStr(%s, %s)) != 0)) kw_args--;' % (
3905                        i, Naming.kwds_cname, pystring_cname))
3906                    if i < min_positional_args:
3907                        if i == 0:
3908                            # special case: we know arg 0 is missing
3909                            code.put('else ')
3910                            code.put_goto(argtuple_error_label)
3911                        else:
3912                            # print the correct number of values (args or
3913                            # kwargs) that were passed into positional
3914                            # arguments up to this point
3915                            code.putln('else {')
3916                            code.globalstate.use_utility_code(
3917                                UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c"))
3918                            code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, %d); ' % (
3919                                self.name, has_fixed_positional_count,
3920                                min_positional_args, max_positional_args, i))
3921                            code.putln(code.error_goto(self.pos))
3922                            code.putln('}')
3923                    elif arg.kw_only:
3924                        code.putln('else {')
3925                        code.globalstate.use_utility_code(
3926                            UtilityCode.load_cached("RaiseKeywordRequired", "FunctionArguments.c"))
3927                        code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % (
3928                            self.name, pystring_cname))
3929                        code.putln(code.error_goto(self.pos))
3930                        code.putln('}')
3931            if max_positional_args > 0:
3932                code.putln('}')
3933
3934        if has_kw_only_args:
3935            # unpack optional keyword-only arguments separately because
3936            # checking for interned strings in a dict is faster than iterating
3937            self.generate_optional_kwonly_args_unpacking_code(all_args, code)
3938
3939        code.putln('if (unlikely(kw_args > 0)) {')
3940        # non-positional/-required kw args left in dict: default args,
3941        # kw-only args, **kwargs or error
3942        #
3943        # This is sort of a catch-all: except for checking required
3944        # arguments, this will always do the right thing for unpacking
3945        # keyword arguments, so that we can concentrate on optimising
3946        # common cases above.
3947        if max_positional_args == 0:
3948            pos_arg_count = "0"
3949        elif self.star_arg:
3950            code.putln("const Py_ssize_t used_pos_args = (pos_args < %d) ? pos_args : %d;" % (
3951                max_positional_args, max_positional_args))
3952            pos_arg_count = "used_pos_args"
3953        else:
3954            pos_arg_count = "pos_args"
3955        code.globalstate.use_utility_code(
3956            UtilityCode.load_cached("ParseKeywords", "FunctionArguments.c"))
3957        code.putln('if (unlikely(__Pyx_ParseOptionalKeywords(%s, %s, %s, values, %s, "%s") < 0)) %s' % (
3958            Naming.kwds_cname,
3959            Naming.pykwdlist_cname,
3960            self.starstar_arg and self.starstar_arg.entry.cname or '0',
3961            pos_arg_count,
3962            self.name,
3963            code.error_goto(self.pos)))
3964        code.putln('}')
3965
3966    def generate_optional_kwonly_args_unpacking_code(self, all_args, code):
3967        optional_args = []
3968        first_optional_arg = -1
3969        for i, arg in enumerate(all_args):
3970            if not arg.kw_only or not arg.default:
3971                continue
3972            if not optional_args:
3973                first_optional_arg = i
3974            optional_args.append(arg.name)
3975        if optional_args:
3976            if len(optional_args) > 1:
3977                # if we receive more than the named kwargs, we either have **kwargs
3978                # (in which case we must iterate anyway) or it's an error (which we
3979                # also handle during iteration) => skip this part if there are more
3980                code.putln('if (kw_args > 0 && %s(kw_args <= %d)) {' % (
3981                    not self.starstar_arg and 'likely' or '',
3982                    len(optional_args)))
3983                code.putln('Py_ssize_t index;')
3984                # not unrolling the loop here reduces the C code overhead
3985                code.putln('for (index = %d; index < %d && kw_args > 0; index++) {' % (
3986                    first_optional_arg, first_optional_arg + len(optional_args)))
3987            else:
3988                code.putln('if (kw_args == 1) {')
3989                code.putln('const Py_ssize_t index = %d;' % first_optional_arg)
3990            code.putln('PyObject* value = __Pyx_PyDict_GetItemStr(%s, *%s[index]);' % (
3991                Naming.kwds_cname, Naming.pykwdlist_cname))
3992            code.putln('if (value) { values[index] = value; kw_args--; }')
3993            if len(optional_args) > 1:
3994                code.putln('}')
3995            code.putln('}')
3996
3997    def generate_argument_conversion_code(self, code):
3998        # Generate code to convert arguments from signature type to
3999        # declared type, if needed.  Also copies signature arguments
4000        # into closure fields.
4001        for arg in self.args:
4002            if arg.needs_conversion:
4003                self.generate_arg_conversion(arg, code)
4004
4005    def generate_arg_conversion(self, arg, code):
4006        # Generate conversion code for one argument.
4007        old_type = arg.hdr_type
4008        new_type = arg.type
4009        if old_type.is_pyobject:
4010            if arg.default:
4011                code.putln("if (%s) {" % arg.hdr_cname)
4012            else:
4013                code.putln("assert(%s); {" % arg.hdr_cname)
4014            self.generate_arg_conversion_from_pyobject(arg, code)
4015            code.putln("}")
4016        elif new_type.is_pyobject:
4017            self.generate_arg_conversion_to_pyobject(arg, code)
4018        else:
4019            if new_type.assignable_from(old_type):
4020                code.putln("%s = %s;" % (arg.entry.cname, arg.hdr_cname))
4021            else:
4022                error(arg.pos, "Cannot convert 1 argument from '%s' to '%s'" % (old_type, new_type))
4023
4024    def generate_arg_conversion_from_pyobject(self, arg, code):
4025        new_type = arg.type
4026        # copied from CoerceFromPyTypeNode
4027        if new_type.from_py_function:
4028            code.putln(new_type.from_py_call_code(
4029                arg.hdr_cname,
4030                arg.entry.cname,
4031                arg.pos,
4032                code,
4033            ))
4034        else:
4035            error(arg.pos, "Cannot convert Python object argument to type '%s'" % new_type)
4036
4037    def generate_arg_conversion_to_pyobject(self, arg, code):
4038        old_type = arg.hdr_type
4039        func = old_type.to_py_function
4040        if func:
4041            code.putln("%s = %s(%s); %s" % (
4042                arg.entry.cname,
4043                func,
4044                arg.hdr_cname,
4045                code.error_goto_if_null(arg.entry.cname, arg.pos)))
4046            code.put_var_gotref(arg.entry)
4047        else:
4048            error(arg.pos, "Cannot convert argument of type '%s' to Python object" % old_type)
4049
4050    def generate_argument_type_tests(self, code):
4051        # Generate type tests for args whose signature
4052        # type is PyObject * and whose declared type is
4053        # a subtype thereof.
4054        for arg in self.args:
4055            if arg.needs_type_test:
4056                self.generate_arg_type_test(arg, code)
4057            elif not arg.accept_none and (arg.type.is_pyobject or
4058                                          arg.type.is_buffer or
4059                                          arg.type.is_memoryviewslice):
4060                self.generate_arg_none_check(arg, code)
4061
4062    def error_value(self):
4063        return self.signature.error_value
4064
4065
4066class GeneratorDefNode(DefNode):
4067    # Generator function node that creates a new generator instance when called.
4068    #
4069    # gbody          GeneratorBodyDefNode   the function implementing the generator
4070    #
4071
4072    is_generator = True
4073    is_coroutine = False
4074    is_iterable_coroutine = False
4075    is_asyncgen = False
4076    gen_type_name = 'Generator'
4077    needs_closure = True
4078
4079    child_attrs = DefNode.child_attrs + ["gbody"]
4080
4081    def __init__(self, pos, **kwargs):
4082        # XXX: don't actually needs a body
4083        kwargs['body'] = StatListNode(pos, stats=[], is_terminator=True)
4084        super(GeneratorDefNode, self).__init__(pos, **kwargs)
4085
4086    def analyse_declarations(self, env):
4087        super(GeneratorDefNode, self).analyse_declarations(env)
4088        self.gbody.local_scope = self.local_scope
4089        self.gbody.analyse_declarations(env)
4090
4091    def generate_function_body(self, env, code):
4092        body_cname = self.gbody.entry.func_cname
4093        name = code.intern_identifier(self.name)
4094        qualname = code.intern_identifier(self.qualname)
4095        module_name = code.intern_identifier(self.module_name)
4096
4097        code.putln('{')
4098        code.putln('__pyx_CoroutineObject *gen = __Pyx_%s_New('
4099                   '(__pyx_coroutine_body_t) %s, %s, (PyObject *) %s, %s, %s, %s); %s' % (
4100                       self.gen_type_name,
4101                       body_cname, self.code_object.calculate_result_code(code) if self.code_object else 'NULL',
4102                       Naming.cur_scope_cname, name, qualname, module_name,
4103                       code.error_goto_if_null('gen', self.pos)))
4104        code.put_decref(Naming.cur_scope_cname, py_object_type)
4105        if self.requires_classobj:
4106            classobj_cname = 'gen->classobj'
4107            code.putln('%s = __Pyx_CyFunction_GetClassObj(%s);' % (
4108                classobj_cname, Naming.self_cname))
4109            code.put_incref(classobj_cname, py_object_type)
4110            code.put_giveref(classobj_cname)
4111        code.put_finish_refcount_context()
4112        code.putln('return (PyObject *) gen;')
4113        code.putln('}')
4114
4115    def generate_function_definitions(self, env, code):
4116        env.use_utility_code(UtilityCode.load_cached(self.gen_type_name, "Coroutine.c"))
4117        self.gbody.generate_function_header(code, proto=True)
4118        super(GeneratorDefNode, self).generate_function_definitions(env, code)
4119        self.gbody.generate_function_definitions(env, code)
4120
4121
4122class AsyncDefNode(GeneratorDefNode):
4123    gen_type_name = 'Coroutine'
4124    is_coroutine = True
4125
4126
4127class IterableAsyncDefNode(AsyncDefNode):
4128    gen_type_name = 'IterableCoroutine'
4129    is_iterable_coroutine = True
4130
4131
4132class AsyncGenNode(AsyncDefNode):
4133    gen_type_name = 'AsyncGen'
4134    is_asyncgen = True
4135
4136
4137class GeneratorBodyDefNode(DefNode):
4138    # Main code body of a generator implemented as a DefNode.
4139    #
4140
4141    is_generator_body = True
4142    is_inlined = False
4143    is_async_gen_body = False
4144    inlined_comprehension_type = None  # container type for inlined comprehensions
4145
4146    def __init__(self, pos=None, name=None, body=None, is_async_gen_body=False):
4147        super(GeneratorBodyDefNode, self).__init__(
4148            pos=pos, body=body, name=name, is_async_gen_body=is_async_gen_body,
4149            doc=None, args=[], star_arg=None, starstar_arg=None)
4150
4151    def declare_generator_body(self, env):
4152        prefix = env.next_id(env.scope_prefix)
4153        name = env.next_id('generator')
4154        cname = Naming.genbody_prefix + prefix + name
4155        entry = env.declare_var(None, py_object_type, self.pos,
4156                                cname=cname, visibility='private')
4157        entry.func_cname = cname
4158        entry.qualified_name = EncodedString(self.name)
4159        # Work-around for https://github.com/cython/cython/issues/1699
4160        # We don't currently determine whether the generator entry is used or not,
4161        # so mark it as used to avoid false warnings.
4162        entry.used = True
4163        self.entry = entry
4164
4165    def analyse_declarations(self, env):
4166        self.analyse_argument_types(env)
4167        self.declare_generator_body(env)
4168
4169    def generate_function_header(self, code, proto=False):
4170        header = "static PyObject *%s(__pyx_CoroutineObject *%s, CYTHON_UNUSED PyThreadState *%s, PyObject *%s)" % (
4171            self.entry.func_cname,
4172            Naming.generator_cname,
4173            Naming.local_tstate_cname,
4174            Naming.sent_value_cname)
4175        if proto:
4176            code.putln('%s; /* proto */' % header)
4177        else:
4178            code.putln('%s /* generator body */\n{' % header)
4179
4180    def generate_function_definitions(self, env, code):
4181        lenv = self.local_scope
4182
4183        # Generate closure function definitions
4184        self.body.generate_function_definitions(lenv, code)
4185
4186        # Generate C code for header and body of function
4187        code.enter_cfunc_scope(lenv)
4188        code.return_from_error_cleanup_label = code.new_label()
4189
4190        # ----- Top-level constants used by this function
4191        code.mark_pos(self.pos)
4192        self.generate_cached_builtins_decls(lenv, code)
4193        # ----- Function header
4194        code.putln("")
4195        self.generate_function_header(code)
4196        closure_init_code = code.insertion_point()
4197        # ----- Local variables
4198        code.putln("PyObject *%s = NULL;" % Naming.retval_cname)
4199        tempvardecl_code = code.insertion_point()
4200        code.put_declare_refcount_context()
4201        code.put_setup_refcount_context(self.entry.name or self.entry.qualified_name)
4202        profile = code.globalstate.directives['profile']
4203        linetrace = code.globalstate.directives['linetrace']
4204        if profile or linetrace:
4205            tempvardecl_code.put_trace_declarations()
4206            code.funcstate.can_trace = True
4207            code_object = self.code_object.calculate_result_code(code) if self.code_object else None
4208            code.put_trace_frame_init(code_object)
4209
4210        # ----- Resume switch point.
4211        code.funcstate.init_closure_temps(lenv.scope_class.type.scope)
4212        resume_code = code.insertion_point()
4213        first_run_label = code.new_label('first_run')
4214        code.use_label(first_run_label)
4215        code.put_label(first_run_label)
4216        code.putln('%s' %
4217                   (code.error_goto_if_null(Naming.sent_value_cname, self.pos)))
4218
4219        # ----- prepare target container for inlined comprehension
4220        if self.is_inlined and self.inlined_comprehension_type is not None:
4221            target_type = self.inlined_comprehension_type
4222            if target_type is Builtin.list_type:
4223                comp_init = 'PyList_New(0)'
4224            elif target_type is Builtin.set_type:
4225                comp_init = 'PySet_New(NULL)'
4226            elif target_type is Builtin.dict_type:
4227                comp_init = 'PyDict_New()'
4228            else:
4229                raise InternalError(
4230                    "invalid type of inlined comprehension: %s" % target_type)
4231            code.putln("%s = %s; %s" % (
4232                Naming.retval_cname, comp_init,
4233                code.error_goto_if_null(Naming.retval_cname, self.pos)))
4234            code.put_gotref(Naming.retval_cname)
4235
4236        # ----- Function body
4237        self.generate_function_body(env, code)
4238        # ----- Closure initialization
4239        if lenv.scope_class.type.scope.var_entries:
4240            closure_init_code.putln('%s = %s;' % (
4241                lenv.scope_class.type.declaration_code(Naming.cur_scope_cname),
4242                lenv.scope_class.type.cast_code('%s->closure' %
4243                                                Naming.generator_cname)))
4244            # FIXME: this silences a potential "unused" warning => try to avoid unused closures in more cases
4245            code.putln("CYTHON_MAYBE_UNUSED_VAR(%s);" % Naming.cur_scope_cname)
4246
4247        if profile or linetrace:
4248            code.funcstate.can_trace = False
4249
4250        code.mark_pos(self.pos)
4251        code.putln("")
4252        code.putln("/* function exit code */")
4253
4254        # on normal generator termination, we do not take the exception propagation
4255        # path: no traceback info is required and not creating it is much faster
4256        if not self.is_inlined and not self.body.is_terminator:
4257            if self.is_async_gen_body:
4258                code.globalstate.use_utility_code(
4259                    UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c"))
4260            code.putln('PyErr_SetNone(%s);' % (
4261                '__Pyx_PyExc_StopAsyncIteration' if self.is_async_gen_body else 'PyExc_StopIteration'))
4262        # ----- Error cleanup
4263        if code.label_used(code.error_label):
4264            if not self.body.is_terminator:
4265                code.put_goto(code.return_label)
4266            code.put_label(code.error_label)
4267            if self.is_inlined and self.inlined_comprehension_type is not None:
4268                code.put_xdecref_clear(Naming.retval_cname, py_object_type)
4269            if Future.generator_stop in env.global_scope().context.future_directives:
4270                # PEP 479: turn accidental StopIteration exceptions into a RuntimeError
4271                code.globalstate.use_utility_code(UtilityCode.load_cached("pep479", "Coroutine.c"))
4272                code.putln("__Pyx_Generator_Replace_StopIteration(%d);" % bool(self.is_async_gen_body))
4273            for cname, type in code.funcstate.all_managed_temps():
4274                code.put_xdecref(cname, type)
4275            code.put_add_traceback(self.entry.qualified_name)
4276
4277        # ----- Non-error return cleanup
4278        code.put_label(code.return_label)
4279        if self.is_inlined:
4280            code.put_xgiveref(Naming.retval_cname)
4281        else:
4282            code.put_xdecref_clear(Naming.retval_cname, py_object_type)
4283        # For Py3.7, clearing is already done below.
4284        code.putln("#if !CYTHON_USE_EXC_INFO_STACK")
4285        code.putln("__Pyx_Coroutine_ResetAndClearException(%s);" % Naming.generator_cname)
4286        code.putln("#endif")
4287        code.putln('%s->resume_label = -1;' % Naming.generator_cname)
4288        # clean up as early as possible to help breaking any reference cycles
4289        code.putln('__Pyx_Coroutine_clear((PyObject*)%s);' % Naming.generator_cname)
4290        if profile or linetrace:
4291            code.put_trace_return(Naming.retval_cname,
4292                                  nogil=not code.funcstate.gil_owned)
4293        code.put_finish_refcount_context()
4294        code.putln("return %s;" % Naming.retval_cname)
4295        code.putln("}")
4296
4297        # ----- Go back and insert temp variable declarations
4298        tempvardecl_code.put_temp_declarations(code.funcstate)
4299        # ----- Generator resume code
4300        if profile or linetrace:
4301            resume_code.put_trace_call(self.entry.qualified_name, self.pos,
4302                                       nogil=not code.funcstate.gil_owned)
4303        resume_code.putln("switch (%s->resume_label) {" % (
4304                       Naming.generator_cname))
4305
4306        resume_code.putln("case 0: goto %s;" % first_run_label)
4307
4308        for i, label in code.yield_labels:
4309            resume_code.putln("case %d: goto %s;" % (i, label))
4310        resume_code.putln("default: /* CPython raises the right error here */")
4311        if profile or linetrace:
4312            resume_code.put_trace_return("Py_None",
4313                                         nogil=not code.funcstate.gil_owned)
4314        resume_code.put_finish_refcount_context()
4315        resume_code.putln("return NULL;")
4316        resume_code.putln("}")
4317
4318        code.exit_cfunc_scope()
4319
4320
4321class OverrideCheckNode(StatNode):
4322    # A Node for dispatching to the def method if it
4323    # is overridden.
4324    #
4325    #  py_func
4326    #
4327    #  args
4328    #  func_temp
4329    #  body
4330
4331    child_attrs = ['body']
4332
4333    body = None
4334
4335    def analyse_expressions(self, env):
4336        self.args = env.arg_entries
4337        if self.py_func.is_module_scope:
4338            first_arg = 0
4339        else:
4340            first_arg = 1
4341        from . import ExprNodes
4342        self.func_node = ExprNodes.RawCNameExprNode(self.pos, py_object_type)
4343        call_node = ExprNodes.SimpleCallNode(
4344            self.pos, function=self.func_node,
4345            args=[ExprNodes.NameNode(self.pos, name=arg.name)
4346                  for arg in self.args[first_arg:]])
4347        if env.return_type.is_void or env.return_type.is_returncode:
4348            self.body = StatListNode(self.pos, stats=[
4349                ExprStatNode(self.pos, expr=call_node),
4350                ReturnStatNode(self.pos, value=None)])
4351        else:
4352            self.body = ReturnStatNode(self.pos, value=call_node)
4353        self.body = self.body.analyse_expressions(env)
4354        return self
4355
4356    def generate_execution_code(self, code):
4357        interned_attr_cname = code.intern_identifier(self.py_func.entry.name)
4358        # Check to see if we are an extension type
4359        if self.py_func.is_module_scope:
4360            self_arg = "((PyObject *)%s)" % Naming.module_cname
4361        else:
4362            self_arg = "((PyObject *)%s)" % self.args[0].cname
4363        code.putln("/* Check if called by wrapper */")
4364        code.putln("if (unlikely(%s)) ;" % Naming.skip_dispatch_cname)
4365        code.putln("/* Check if overridden in Python */")
4366        if self.py_func.is_module_scope:
4367            code.putln("else {")
4368        else:
4369            code.putln("else if (unlikely((Py_TYPE(%s)->tp_dictoffset != 0)"
4370                       " || (Py_TYPE(%s)->tp_flags & (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) {" % (
4371                self_arg, self_arg))
4372
4373        code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS")
4374        code.globalstate.use_utility_code(
4375            UtilityCode.load_cached("PyDictVersioning", "ObjectHandling.c"))
4376        # TODO: remove the object dict version check by 'inlining' the getattr implementation for methods.
4377        # This would allow checking the dict versions around _PyType_Lookup() if it returns a descriptor,
4378        # and would (tada!) make this check a pure type based thing instead of supporting only a single
4379        # instance at a time.
4380        code.putln("static PY_UINT64_T %s = __PYX_DICT_VERSION_INIT, %s = __PYX_DICT_VERSION_INIT;" % (
4381            Naming.tp_dict_version_temp, Naming.obj_dict_version_temp))
4382        code.putln("if (unlikely(!__Pyx_object_dict_version_matches(%s, %s, %s))) {" % (
4383            self_arg, Naming.tp_dict_version_temp, Naming.obj_dict_version_temp))
4384        code.putln("PY_UINT64_T %s = __Pyx_get_tp_dict_version(%s);" % (
4385            Naming.type_dict_guard_temp, self_arg))
4386        code.putln("#endif")
4387
4388        func_node_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
4389        self.func_node.set_cname(func_node_temp)
4390        # need to get attribute manually--scope would return cdef method
4391        code.globalstate.use_utility_code(
4392            UtilityCode.load_cached("PyObjectGetAttrStr", "ObjectHandling.c"))
4393        err = code.error_goto_if_null(func_node_temp, self.pos)
4394        code.putln("%s = __Pyx_PyObject_GetAttrStr(%s, %s); %s" % (
4395            func_node_temp, self_arg, interned_attr_cname, err))
4396        code.put_gotref(func_node_temp)
4397
4398        is_builtin_function_or_method = "PyCFunction_Check(%s)" % func_node_temp
4399        is_overridden = "(PyCFunction_GET_FUNCTION(%s) != (PyCFunction)(void*)%s)" % (
4400            func_node_temp, self.py_func.entry.func_cname)
4401        code.putln("if (!%s || %s) {" % (is_builtin_function_or_method, is_overridden))
4402        self.body.generate_execution_code(code)
4403        code.putln("}")
4404
4405        # NOTE: it's not 100% sure that we catch the exact versions here that were used for the lookup,
4406        # but it is very unlikely that the versions change during lookup, and the type dict safe guard
4407        # should increase the chance of detecting such a case.
4408        code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS")
4409        code.putln("%s = __Pyx_get_tp_dict_version(%s);" % (
4410            Naming.tp_dict_version_temp, self_arg))
4411        code.putln("%s = __Pyx_get_object_dict_version(%s);" % (
4412            Naming.obj_dict_version_temp, self_arg))
4413        # Safety check that the type dict didn't change during the lookup.  Since CPython looks up the
4414        # attribute (descriptor) first in the type dict and then in the instance dict or through the
4415        # descriptor, the only really far-away lookup when we get here is one in the type dict. So we
4416        # double check the type dict version before and afterwards to guard against later changes of
4417        # the type dict during the lookup process.
4418        code.putln("if (unlikely(%s != %s)) {" % (
4419            Naming.type_dict_guard_temp, Naming.tp_dict_version_temp))
4420        code.putln("%s = %s = __PYX_DICT_VERSION_INIT;" % (
4421            Naming.tp_dict_version_temp, Naming.obj_dict_version_temp))
4422        code.putln("}")
4423        code.putln("#endif")
4424
4425        code.put_decref_clear(func_node_temp, PyrexTypes.py_object_type)
4426        code.funcstate.release_temp(func_node_temp)
4427
4428        code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS")
4429        code.putln("}")
4430        code.putln("#endif")
4431
4432        code.putln("}")
4433
4434
4435class ClassDefNode(StatNode, BlockNode):
4436    pass
4437
4438
4439class PyClassDefNode(ClassDefNode):
4440    #  A Python class definition.
4441    #
4442    #  name     EncodedString   Name of the class
4443    #  doc      string or None
4444    #  body     StatNode        Attribute definition code
4445    #  entry    Symtab.Entry
4446    #  scope    PyClassScope
4447    #  decorators    [DecoratorNode]        list of decorators or None
4448    #
4449    #  The following subnodes are constructed internally:
4450    #
4451    #  dict     DictNode   Class dictionary or Py3 namespace
4452    #  classobj ClassNode  Class object
4453    #  target   NameNode   Variable to assign class object to
4454
4455    child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "class_result",
4456                   "target", "class_cell", "decorators"]
4457    decorators = None
4458    class_result = None
4459    is_py3_style_class = False  # Python3 style class (kwargs)
4460    metaclass = None
4461    mkw = None
4462
4463    def __init__(self, pos, name, bases, doc, body, decorators=None,
4464                 keyword_args=None, force_py3_semantics=False):
4465        StatNode.__init__(self, pos)
4466        self.name = name
4467        self.doc = doc
4468        self.body = body
4469        self.decorators = decorators
4470        self.bases = bases
4471        from . import ExprNodes
4472        if self.doc and Options.docstrings:
4473            doc = embed_position(self.pos, self.doc)
4474            doc_node = ExprNodes.StringNode(pos, value=doc)
4475        else:
4476            doc_node = None
4477
4478        allow_py2_metaclass = not force_py3_semantics
4479        if keyword_args:
4480            allow_py2_metaclass = False
4481            self.is_py3_style_class = True
4482            if keyword_args.is_dict_literal:
4483                if keyword_args.key_value_pairs:
4484                    for i, item in list(enumerate(keyword_args.key_value_pairs))[::-1]:
4485                        if item.key.value == 'metaclass':
4486                            if self.metaclass is not None:
4487                                error(item.pos, "keyword argument 'metaclass' passed multiple times")
4488                            # special case: we already know the metaclass,
4489                            # so we don't need to do the "build kwargs,
4490                            # find metaclass" dance at runtime
4491                            self.metaclass = item.value
4492                            del keyword_args.key_value_pairs[i]
4493                    self.mkw = keyword_args
4494                else:
4495                    assert self.metaclass is not None
4496            else:
4497                # MergedDictNode
4498                self.mkw = ExprNodes.ProxyNode(keyword_args)
4499
4500        if force_py3_semantics or self.bases or self.mkw or self.metaclass:
4501            if self.metaclass is None:
4502                if keyword_args and not keyword_args.is_dict_literal:
4503                    # **kwargs may contain 'metaclass' arg
4504                    mkdict = self.mkw
4505                else:
4506                    mkdict = None
4507                if (not mkdict and
4508                        self.bases.is_sequence_constructor and
4509                        not self.bases.args):
4510                    pass  # no base classes => no inherited metaclass
4511                else:
4512                    self.metaclass = ExprNodes.PyClassMetaclassNode(
4513                        pos, class_def_node=self)
4514                needs_metaclass_calculation = False
4515            else:
4516                needs_metaclass_calculation = True
4517
4518            self.dict = ExprNodes.PyClassNamespaceNode(
4519                pos, name=name, doc=doc_node, class_def_node=self)
4520            self.classobj = ExprNodes.Py3ClassNode(
4521                pos, name=name, class_def_node=self, doc=doc_node,
4522                calculate_metaclass=needs_metaclass_calculation,
4523                allow_py2_metaclass=allow_py2_metaclass)
4524        else:
4525            # no bases, no metaclass => old style class creation
4526            self.dict = ExprNodes.DictNode(pos, key_value_pairs=[])
4527            self.classobj = ExprNodes.ClassNode(
4528                pos, name=name, class_def_node=self, doc=doc_node)
4529
4530        self.target = ExprNodes.NameNode(pos, name=name)
4531        self.class_cell = ExprNodes.ClassCellInjectorNode(self.pos)
4532
4533    def as_cclass(self):
4534        """
4535        Return this node as if it were declared as an extension class
4536        """
4537        if self.is_py3_style_class:
4538            error(self.classobj.pos, "Python3 style class could not be represented as C class")
4539            return
4540
4541        from . import ExprNodes
4542        return CClassDefNode(self.pos,
4543                             visibility='private',
4544                             module_name=None,
4545                             class_name=self.name,
4546                             bases=self.bases or ExprNodes.TupleNode(self.pos, args=[]),
4547                             decorators=self.decorators,
4548                             body=self.body,
4549                             in_pxd=False,
4550                             doc=self.doc)
4551
4552    def create_scope(self, env):
4553        genv = env
4554        while genv.is_py_class_scope or genv.is_c_class_scope:
4555            genv = genv.outer_scope
4556        cenv = self.scope = PyClassScope(name=self.name, outer_scope=genv)
4557        return cenv
4558
4559    def analyse_declarations(self, env):
4560        class_result = self.classobj
4561        if self.decorators:
4562            from .ExprNodes import SimpleCallNode
4563            for decorator in self.decorators[::-1]:
4564                class_result = SimpleCallNode(
4565                    decorator.pos,
4566                    function=decorator.decorator,
4567                    args=[class_result])
4568            self.decorators = None
4569        self.class_result = class_result
4570        if self.bases:
4571            self.bases.analyse_declarations(env)
4572        if self.mkw:
4573            self.mkw.analyse_declarations(env)
4574        self.class_result.analyse_declarations(env)
4575        self.target.analyse_target_declaration(env)
4576        cenv = self.create_scope(env)
4577        cenv.directives = env.directives
4578        cenv.class_obj_cname = self.target.entry.cname
4579        self.body.analyse_declarations(cenv)
4580
4581    def analyse_expressions(self, env):
4582        if self.bases:
4583            self.bases = self.bases.analyse_expressions(env)
4584        if self.mkw:
4585            self.mkw = self.mkw.analyse_expressions(env)
4586        if self.metaclass:
4587            self.metaclass = self.metaclass.analyse_expressions(env)
4588        self.dict = self.dict.analyse_expressions(env)
4589        self.class_result = self.class_result.analyse_expressions(env)
4590        cenv = self.scope
4591        self.body = self.body.analyse_expressions(cenv)
4592        self.target.analyse_target_expression(env, self.classobj)
4593        self.class_cell = self.class_cell.analyse_expressions(cenv)
4594        return self
4595
4596    def generate_function_definitions(self, env, code):
4597        self.generate_lambda_definitions(self.scope, code)
4598        self.body.generate_function_definitions(self.scope, code)
4599
4600    def generate_execution_code(self, code):
4601        code.mark_pos(self.pos)
4602        code.pyclass_stack.append(self)
4603        cenv = self.scope
4604        if self.bases:
4605            self.bases.generate_evaluation_code(code)
4606        if self.mkw:
4607            self.mkw.generate_evaluation_code(code)
4608        if self.metaclass:
4609            self.metaclass.generate_evaluation_code(code)
4610        self.dict.generate_evaluation_code(code)
4611        cenv.namespace_cname = cenv.class_obj_cname = self.dict.result()
4612
4613        class_cell = self.class_cell
4614        if class_cell is not None and not class_cell.is_active:
4615            class_cell = None
4616
4617        if class_cell is not None:
4618            class_cell.generate_evaluation_code(code)
4619        self.body.generate_execution_code(code)
4620        self.class_result.generate_evaluation_code(code)
4621        if class_cell is not None:
4622            class_cell.generate_injection_code(
4623                code, self.class_result.result())
4624        if class_cell is not None:
4625            class_cell.generate_disposal_code(code)
4626            class_cell.free_temps(code)
4627
4628        cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
4629        self.target.generate_assignment_code(self.class_result, code)
4630        self.dict.generate_disposal_code(code)
4631        self.dict.free_temps(code)
4632        if self.metaclass:
4633            self.metaclass.generate_disposal_code(code)
4634            self.metaclass.free_temps(code)
4635        if self.mkw:
4636            self.mkw.generate_disposal_code(code)
4637            self.mkw.free_temps(code)
4638        if self.bases:
4639            self.bases.generate_disposal_code(code)
4640            self.bases.free_temps(code)
4641        code.pyclass_stack.pop()
4642
4643
4644class CClassDefNode(ClassDefNode):
4645    #  An extension type definition.
4646    #
4647    #  visibility         'private' or 'public' or 'extern'
4648    #  typedef_flag       boolean
4649    #  api                boolean
4650    #  module_name        string or None    For import of extern type objects
4651    #  class_name         string            Unqualified name of class
4652    #  as_name            string or None    Name to declare as in this scope
4653    #  bases              TupleNode         Base class(es)
4654    #  objstruct_name     string or None    Specified C name of object struct
4655    #  typeobj_name       string or None    Specified C name of type object
4656    #  check_size         'warn', 'error', 'ignore'     What to do if tp_basicsize does not match
4657    #  in_pxd             boolean           Is in a .pxd file
4658    #  decorators         [DecoratorNode]   list of decorators or None
4659    #  doc                string or None
4660    #  body               StatNode or None
4661    #  entry              Symtab.Entry
4662    #  base_type          PyExtensionType or None
4663    #  buffer_defaults_node DictNode or None Declares defaults for a buffer
4664    #  buffer_defaults_pos
4665
4666    child_attrs = ["body"]
4667    buffer_defaults_node = None
4668    buffer_defaults_pos = None
4669    typedef_flag = False
4670    api = False
4671    objstruct_name = None
4672    typeobj_name = None
4673    check_size = None
4674    decorators = None
4675    shadow = False
4676
4677    def buffer_defaults(self, env):
4678        if not hasattr(self, '_buffer_defaults'):
4679            from . import Buffer
4680            if self.buffer_defaults_node:
4681                self._buffer_defaults = Buffer.analyse_buffer_options(
4682                    self.buffer_defaults_pos,
4683                    env, [], self.buffer_defaults_node,
4684                    need_complete=False)
4685            else:
4686                self._buffer_defaults = None
4687        return self._buffer_defaults
4688
4689    def declare(self, env):
4690        if self.module_name and self.visibility != 'extern':
4691            module_path = self.module_name.split(".")
4692            home_scope = env.find_imported_module(module_path, self.pos)
4693            if not home_scope:
4694                return None
4695        else:
4696            home_scope = env
4697
4698        self.entry = home_scope.declare_c_class(
4699            name=self.class_name,
4700            pos=self.pos,
4701            defining=0,
4702            implementing=0,
4703            module_name=self.module_name,
4704            base_type=None,
4705            objstruct_cname=self.objstruct_name,
4706            typeobj_cname=self.typeobj_name,
4707            visibility=self.visibility,
4708            typedef_flag=self.typedef_flag,
4709            check_size = self.check_size,
4710            api=self.api,
4711            buffer_defaults=self.buffer_defaults(env),
4712            shadow=self.shadow)
4713
4714    def analyse_declarations(self, env):
4715        #print "CClassDefNode.analyse_declarations:", self.class_name
4716        #print "...visibility =", self.visibility
4717        #print "...module_name =", self.module_name
4718
4719        if env.in_cinclude and not self.objstruct_name:
4720            error(self.pos, "Object struct name specification required for C class defined in 'extern from' block")
4721        if self.decorators:
4722            error(self.pos, "Decorators not allowed on cdef classes (used on type '%s')" % self.class_name)
4723        self.base_type = None
4724        # Now that module imports are cached, we need to
4725        # import the modules for extern classes.
4726        if self.module_name:
4727            self.module = None
4728            for module in env.cimported_modules:
4729                if module.name == self.module_name:
4730                    self.module = module
4731            if self.module is None:
4732                self.module = ModuleScope(self.module_name, None, env.context)
4733                self.module.has_extern_class = 1
4734                env.add_imported_module(self.module)
4735
4736        if self.bases.args:
4737            base = self.bases.args[0]
4738            base_type = base.analyse_as_type(env)
4739            if base_type in (PyrexTypes.c_int_type, PyrexTypes.c_long_type, PyrexTypes.c_float_type):
4740                # Use the Python rather than C variant of these types.
4741                base_type = env.lookup(base_type.sign_and_name()).type
4742            if base_type is None:
4743                error(base.pos, "First base of '%s' is not an extension type" % self.class_name)
4744            elif base_type == PyrexTypes.py_object_type:
4745                base_class_scope = None
4746            elif not base_type.is_extension_type and \
4747                     not (base_type.is_builtin_type and base_type.objstruct_cname):
4748                error(base.pos, "'%s' is not an extension type" % base_type)
4749            elif not base_type.is_complete():
4750                error(base.pos, "Base class '%s' of type '%s' is incomplete" % (
4751                    base_type.name, self.class_name))
4752            elif base_type.scope and base_type.scope.directives and \
4753                     base_type.is_final_type:
4754                error(base.pos, "Base class '%s' of type '%s' is final" % (
4755                    base_type, self.class_name))
4756            elif base_type.is_builtin_type and \
4757                     base_type.name in ('tuple', 'str', 'bytes'):
4758                error(base.pos, "inheritance from PyVarObject types like '%s' is not currently supported"
4759                      % base_type.name)
4760            else:
4761                self.base_type = base_type
4762            if env.directives.get('freelist', 0) > 0 and base_type != PyrexTypes.py_object_type:
4763                warning(self.pos, "freelists cannot be used on subtypes, only the base class can manage them", 1)
4764
4765        has_body = self.body is not None
4766        if has_body and self.base_type and not self.base_type.scope:
4767            # To properly initialize inherited attributes, the base type must
4768            # be analysed before this type.
4769            self.base_type.defered_declarations.append(lambda : self.analyse_declarations(env))
4770            return
4771
4772        if self.module_name and self.visibility != 'extern':
4773            module_path = self.module_name.split(".")
4774            home_scope = env.find_imported_module(module_path, self.pos)
4775            if not home_scope:
4776                return
4777        else:
4778            home_scope = env
4779
4780        if self.visibility == 'extern':
4781            if (self.module_name == '__builtin__' and
4782                    self.class_name in Builtin.builtin_types and
4783                    env.qualified_name[:8] != 'cpython.'): # allow overloaded names for cimporting from cpython
4784                warning(self.pos, "%s already a builtin Cython type" % self.class_name, 1)
4785
4786        self.entry = home_scope.declare_c_class(
4787            name=self.class_name,
4788            pos=self.pos,
4789            defining=has_body and self.in_pxd,
4790            implementing=has_body and not self.in_pxd,
4791            module_name=self.module_name,
4792            base_type=self.base_type,
4793            objstruct_cname=self.objstruct_name,
4794            typeobj_cname=self.typeobj_name,
4795            check_size=self.check_size,
4796            visibility=self.visibility,
4797            typedef_flag=self.typedef_flag,
4798            api=self.api,
4799            buffer_defaults=self.buffer_defaults(env),
4800            shadow=self.shadow)
4801
4802        if self.shadow:
4803            home_scope.lookup(self.class_name).as_variable = self.entry
4804        if home_scope is not env and self.visibility == 'extern':
4805            env.add_imported_entry(self.class_name, self.entry, self.pos)
4806        self.scope = scope = self.entry.type.scope
4807        if scope is not None:
4808            scope.directives = env.directives
4809
4810        if self.doc and Options.docstrings:
4811            scope.doc = embed_position(self.pos, self.doc)
4812
4813        if has_body:
4814            self.body.analyse_declarations(scope)
4815            dict_entry = self.scope.lookup_here("__dict__")
4816            if dict_entry and dict_entry.is_variable and (not scope.defined and not scope.implemented):
4817                dict_entry.getter_cname = self.scope.mangle_internal("__dict__getter")
4818                self.scope.declare_property("__dict__", dict_entry.doc, dict_entry.pos)
4819            if self.in_pxd:
4820                scope.defined = 1
4821            else:
4822                scope.implemented = 1
4823
4824        if len(self.bases.args) > 1:
4825            if not has_body or self.in_pxd:
4826                error(self.bases.args[1].pos, "Only declare first base in declaration.")
4827            # At runtime, we check that the other bases are heap types
4828            # and that a __dict__ is added if required.
4829            for other_base in self.bases.args[1:]:
4830                if other_base.analyse_as_type(env):
4831                    error(other_base.pos, "Only one extension type base class allowed.")
4832            self.entry.type.early_init = 0
4833            from . import ExprNodes
4834            self.type_init_args = ExprNodes.TupleNode(
4835                self.pos,
4836                args=[ExprNodes.IdentifierStringNode(self.pos, value=self.class_name),
4837                      self.bases,
4838                      ExprNodes.DictNode(self.pos, key_value_pairs=[])])
4839        elif self.base_type:
4840            self.entry.type.early_init = self.base_type.is_external or self.base_type.early_init
4841            self.type_init_args = None
4842        else:
4843            self.entry.type.early_init = 1
4844            self.type_init_args = None
4845
4846        env.allocate_vtable_names(self.entry)
4847
4848        for thunk in self.entry.type.defered_declarations:
4849            thunk()
4850
4851    def analyse_expressions(self, env):
4852        if self.body:
4853            scope = self.entry.type.scope
4854            self.body = self.body.analyse_expressions(scope)
4855        if self.type_init_args:
4856            self.type_init_args.analyse_expressions(env)
4857        return self
4858
4859    def generate_function_definitions(self, env, code):
4860        if self.body:
4861            self.generate_lambda_definitions(self.scope, code)
4862            self.body.generate_function_definitions(self.scope, code)
4863
4864    def generate_execution_code(self, code):
4865        # This is needed to generate evaluation code for
4866        # default values of method arguments.
4867        code.mark_pos(self.pos)
4868        if self.body:
4869            self.body.generate_execution_code(code)
4870        if not self.entry.type.early_init:
4871            if self.type_init_args:
4872                self.type_init_args.generate_evaluation_code(code)
4873                bases = "PyTuple_GET_ITEM(%s, 1)" % self.type_init_args.result()
4874                first_base = "((PyTypeObject*)PyTuple_GET_ITEM(%s, 0))" % bases
4875                # Let Python do the base types compatibility checking.
4876                trial_type = code.funcstate.allocate_temp(PyrexTypes.py_object_type, True)
4877                code.putln("%s = PyType_Type.tp_new(&PyType_Type, %s, NULL);" % (
4878                    trial_type, self.type_init_args.result()))
4879                code.putln(code.error_goto_if_null(trial_type, self.pos))
4880                code.put_gotref(trial_type)
4881                code.putln("if (((PyTypeObject*) %s)->tp_base != %s) {" % (
4882                    trial_type, first_base))
4883                code.putln("PyErr_Format(PyExc_TypeError, \"best base '%s' must be equal to first base '%s'\",")
4884                code.putln("             ((PyTypeObject*) %s)->tp_base->tp_name, %s->tp_name);" % (
4885                           trial_type, first_base))
4886                code.putln(code.error_goto(self.pos))
4887                code.putln("}")
4888                code.funcstate.release_temp(trial_type)
4889                code.put_incref(bases, PyrexTypes.py_object_type)
4890                code.put_giveref(bases)
4891                code.putln("%s.tp_bases = %s;" % (self.entry.type.typeobj_cname, bases))
4892                code.put_decref_clear(trial_type, PyrexTypes.py_object_type)
4893                self.type_init_args.generate_disposal_code(code)
4894                self.type_init_args.free_temps(code)
4895
4896            self.generate_type_ready_code(self.entry, code, True)
4897
4898    # Also called from ModuleNode for early init types.
4899    @staticmethod
4900    def generate_type_ready_code(entry, code, heap_type_bases=False):
4901        # Generate a call to PyType_Ready for an extension
4902        # type defined in this module.
4903        type = entry.type
4904        typeobj_cname = type.typeobj_cname
4905        scope = type.scope
4906        if not scope:  # could be None if there was an error
4907            return
4908        if entry.visibility != 'extern':
4909            for slot in TypeSlots.slot_table:
4910                slot.generate_dynamic_init_code(scope, code)
4911            if heap_type_bases:
4912                code.globalstate.use_utility_code(
4913                    UtilityCode.load_cached('PyType_Ready', 'ExtensionTypes.c'))
4914                readyfunc = "__Pyx_PyType_Ready"
4915            else:
4916                readyfunc = "PyType_Ready"
4917            code.putln(
4918                "if (%s(&%s) < 0) %s" % (
4919                    readyfunc,
4920                    typeobj_cname,
4921                    code.error_goto(entry.pos)))
4922            # Don't inherit tp_print from builtin types, restoring the
4923            # behavior of using tp_repr or tp_str instead.
4924            # ("tp_print" was renamed to "tp_vectorcall_offset" in Py3.8b1)
4925            code.putln("#if PY_VERSION_HEX < 0x030800B1")
4926            code.putln("%s.tp_print = 0;" % typeobj_cname)
4927            code.putln("#endif")
4928
4929            # Use specialised attribute lookup for types with generic lookup but no instance dict.
4930            getattr_slot_func = TypeSlots.get_slot_code_by_name(scope, 'tp_getattro')
4931            dictoffset_slot_func = TypeSlots.get_slot_code_by_name(scope, 'tp_dictoffset')
4932            if getattr_slot_func == '0' and dictoffset_slot_func == '0':
4933                if type.is_final_type:
4934                    py_cfunc = "__Pyx_PyObject_GenericGetAttrNoDict"  # grepable
4935                    utility_func = "PyObject_GenericGetAttrNoDict"
4936                else:
4937                    py_cfunc = "__Pyx_PyObject_GenericGetAttr"
4938                    utility_func = "PyObject_GenericGetAttr"
4939                code.globalstate.use_utility_code(UtilityCode.load_cached(utility_func, "ObjectHandling.c"))
4940
4941                code.putln("if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) &&"
4942                           " likely(!%s.tp_dictoffset && %s.tp_getattro == PyObject_GenericGetAttr)) {" % (
4943                    typeobj_cname, typeobj_cname))
4944                code.putln("%s.tp_getattro = %s;" % (
4945                    typeobj_cname, py_cfunc))
4946                code.putln("}")
4947
4948            # Fix special method docstrings. This is a bit of a hack, but
4949            # unless we let PyType_Ready create the slot wrappers we have
4950            # a significant performance hit. (See trac #561.)
4951            for func in entry.type.scope.pyfunc_entries:
4952                is_buffer = func.name in ('__getbuffer__', '__releasebuffer__')
4953                if (func.is_special and Options.docstrings and
4954                        func.wrapperbase_cname and not is_buffer):
4955                    slot = TypeSlots.method_name_to_slot.get(func.name)
4956                    preprocessor_guard = slot.preprocessor_guard_code() if slot else None
4957                    if preprocessor_guard:
4958                        code.putln(preprocessor_guard)
4959                    code.putln('#if CYTHON_COMPILING_IN_CPYTHON')
4960                    code.putln("{")
4961                    code.putln(
4962                        'PyObject *wrapper = PyObject_GetAttrString((PyObject *)&%s, "%s"); %s' % (
4963                            typeobj_cname,
4964                            func.name,
4965                            code.error_goto_if_null('wrapper', entry.pos)))
4966                    code.putln(
4967                        "if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {")
4968                    code.putln(
4969                        "%s = *((PyWrapperDescrObject *)wrapper)->d_base;" % (
4970                            func.wrapperbase_cname))
4971                    code.putln(
4972                        "%s.doc = %s;" % (func.wrapperbase_cname, func.doc_cname))
4973                    code.putln(
4974                        "((PyWrapperDescrObject *)wrapper)->d_base = &%s;" % (
4975                            func.wrapperbase_cname))
4976                    code.putln("}")
4977                    code.putln("}")
4978                    code.putln('#endif')
4979                    if preprocessor_guard:
4980                        code.putln('#endif')
4981            if type.vtable_cname:
4982                code.globalstate.use_utility_code(
4983                    UtilityCode.load_cached('SetVTable', 'ImportExport.c'))
4984                code.putln(
4985                    "if (__Pyx_SetVtable(%s.tp_dict, %s) < 0) %s" % (
4986                        typeobj_cname,
4987                        type.vtabptr_cname,
4988                        code.error_goto(entry.pos)))
4989                if heap_type_bases:
4990                    code.globalstate.use_utility_code(
4991                        UtilityCode.load_cached('MergeVTables', 'ImportExport.c'))
4992                    code.putln("if (__Pyx_MergeVtables(&%s) < 0) %s" % (
4993                        typeobj_cname,
4994                        code.error_goto(entry.pos)))
4995            if not type.scope.is_internal and not type.scope.directives.get('internal'):
4996                # scope.is_internal is set for types defined by
4997                # Cython (such as closures), the 'internal'
4998                # directive is set by users
4999                code.putln(
5000                    'if (PyObject_SetAttr(%s, %s, (PyObject *)&%s) < 0) %s' % (
5001                        Naming.module_cname,
5002                        code.intern_identifier(scope.class_name),
5003                        typeobj_cname,
5004                        code.error_goto(entry.pos)))
5005            weakref_entry = scope.lookup_here("__weakref__") if not scope.is_closure_class_scope else None
5006            if weakref_entry:
5007                if weakref_entry.type is py_object_type:
5008                    tp_weaklistoffset = "%s.tp_weaklistoffset" % typeobj_cname
5009                    if type.typedef_flag:
5010                        objstruct = type.objstruct_cname
5011                    else:
5012                        objstruct = "struct %s" % type.objstruct_cname
5013                    code.putln("if (%s == 0) %s = offsetof(%s, %s);" % (
5014                        tp_weaklistoffset,
5015                        tp_weaklistoffset,
5016                        objstruct,
5017                        weakref_entry.cname))
5018                else:
5019                    error(weakref_entry.pos, "__weakref__ slot must be of type 'object'")
5020            if scope.lookup_here("__reduce_cython__") if not scope.is_closure_class_scope else None:
5021                # Unfortunately, we cannot reliably detect whether a
5022                # superclass defined __reduce__ at compile time, so we must
5023                # do so at runtime.
5024                code.globalstate.use_utility_code(
5025                    UtilityCode.load_cached('SetupReduce', 'ExtensionTypes.c'))
5026                code.putln('if (__Pyx_setup_reduce((PyObject*)&%s) < 0) %s' % (
5027                              typeobj_cname,
5028                              code.error_goto(entry.pos)))
5029        # Generate code to initialise the typeptr of an extension
5030        # type defined in this module to point to its type object.
5031        if type.typeobj_cname:
5032            code.putln(
5033                "%s = &%s;" % (
5034                    type.typeptr_cname, type.typeobj_cname))
5035
5036    def annotate(self, code):
5037        if self.type_init_args:
5038            self.type_init_args.annotate(code)
5039        if self.body:
5040            self.body.annotate(code)
5041
5042
5043class PropertyNode(StatNode):
5044    #  Definition of a property in an extension type.
5045    #
5046    #  name   string
5047    #  doc    EncodedString or None    Doc string
5048    #  entry  Symtab.Entry
5049    #  body   StatListNode
5050
5051    child_attrs = ["body"]
5052
5053    def analyse_declarations(self, env):
5054        self.entry = env.declare_property(self.name, self.doc, self.pos)
5055        self.entry.scope.directives = env.directives
5056        self.body.analyse_declarations(self.entry.scope)
5057
5058    def analyse_expressions(self, env):
5059        self.body = self.body.analyse_expressions(env)
5060        return self
5061
5062    def generate_function_definitions(self, env, code):
5063        self.body.generate_function_definitions(env, code)
5064
5065    def generate_execution_code(self, code):
5066        pass
5067
5068    def annotate(self, code):
5069        self.body.annotate(code)
5070
5071
5072class GlobalNode(StatNode):
5073    # Global variable declaration.
5074    #
5075    # names    [string]
5076
5077    child_attrs = []
5078
5079    def analyse_declarations(self, env):
5080        for name in self.names:
5081            env.declare_global(name, self.pos)
5082
5083    def analyse_expressions(self, env):
5084        return self
5085
5086    def generate_execution_code(self, code):
5087        pass
5088
5089
5090class NonlocalNode(StatNode):
5091    # Nonlocal variable declaration via the 'nonlocal' keyword.
5092    #
5093    # names    [string]
5094
5095    child_attrs = []
5096
5097    def analyse_declarations(self, env):
5098        for name in self.names:
5099            env.declare_nonlocal(name, self.pos)
5100
5101    def analyse_expressions(self, env):
5102        return self
5103
5104    def generate_execution_code(self, code):
5105        pass
5106
5107
5108class ExprStatNode(StatNode):
5109    #  Expression used as a statement.
5110    #
5111    #  expr   ExprNode
5112
5113    child_attrs = ["expr"]
5114
5115    def analyse_declarations(self, env):
5116        from . import ExprNodes
5117        expr = self.expr
5118        if isinstance(expr, ExprNodes.GeneralCallNode):
5119            func = expr.function.as_cython_attribute()
5120            if func == u'declare':
5121                args, kwds = expr.explicit_args_kwds()
5122                if len(args):
5123                    error(expr.pos, "Variable names must be specified.")
5124                for var, type_node in kwds.key_value_pairs:
5125                    type = type_node.analyse_as_type(env)
5126                    if type is None:
5127                        error(type_node.pos, "Unknown type")
5128                    else:
5129                        env.declare_var(var.value, type, var.pos, is_cdef=True)
5130                self.__class__ = PassStatNode
5131        elif getattr(expr, 'annotation', None) is not None:
5132            if expr.is_name:
5133                # non-code variable annotation, e.g. "name: type"
5134                expr.declare_from_annotation(env)
5135                self.__class__ = PassStatNode
5136            elif expr.is_attribute or expr.is_subscript:
5137                # unused expression with annotation, e.g. "a[0]: type" or "a.xyz : type"
5138                self.__class__ = PassStatNode
5139
5140    def analyse_expressions(self, env):
5141        self.expr.result_is_used = False  # hint that .result() may safely be left empty
5142        self.expr = self.expr.analyse_expressions(env)
5143        # Repeat in case of node replacement.
5144        self.expr.result_is_used = False  # hint that .result() may safely be left empty
5145        return self
5146
5147    def nogil_check(self, env):
5148        if self.expr.type.is_pyobject and self.expr.is_temp:
5149            self.gil_error()
5150
5151    gil_message = "Discarding owned Python object"
5152
5153    def generate_execution_code(self, code):
5154        code.mark_pos(self.pos)
5155        self.expr.result_is_used = False  # hint that .result() may safely be left empty
5156        self.expr.generate_evaluation_code(code)
5157        if not self.expr.is_temp and self.expr.result():
5158            result = self.expr.result()
5159            if not self.expr.type.is_void:
5160                result = "(void)(%s)" % result
5161            code.putln("%s;" % result)
5162        self.expr.generate_disposal_code(code)
5163        self.expr.free_temps(code)
5164
5165    def generate_function_definitions(self, env, code):
5166        self.expr.generate_function_definitions(env, code)
5167
5168    def annotate(self, code):
5169        self.expr.annotate(code)
5170
5171
5172class AssignmentNode(StatNode):
5173    #  Abstract base class for assignment nodes.
5174    #
5175    #  The analyse_expressions and generate_execution_code
5176    #  phases of assignments are split into two sub-phases
5177    #  each, to enable all the right hand sides of a
5178    #  parallel assignment to be evaluated before assigning
5179    #  to any of the left hand sides.
5180
5181    def analyse_expressions(self, env):
5182        node = self.analyse_types(env)
5183        if isinstance(node, AssignmentNode) and not isinstance(node, ParallelAssignmentNode):
5184            if node.rhs.type.is_ptr and node.rhs.is_ephemeral():
5185                error(self.pos, "Storing unsafe C derivative of temporary Python reference")
5186        return node
5187
5188#       def analyse_expressions(self, env):
5189#           self.analyse_expressions_1(env)
5190#           self.analyse_expressions_2(env)
5191
5192    def generate_execution_code(self, code):
5193        code.mark_pos(self.pos)
5194        self.generate_rhs_evaluation_code(code)
5195        self.generate_assignment_code(code)
5196
5197
5198class SingleAssignmentNode(AssignmentNode):
5199    #  The simplest case:
5200    #
5201    #    a = b
5202    #
5203    #  lhs                      ExprNode      Left hand side
5204    #  rhs                      ExprNode      Right hand side
5205    #  first                    bool          Is this guaranteed the first assignment to lhs?
5206    #  is_overloaded_assignment bool          Is this assignment done via an overloaded operator=
5207    #  exception_check
5208    #  exception_value
5209
5210    child_attrs = ["lhs", "rhs"]
5211    first = False
5212    is_overloaded_assignment = False
5213    declaration_only = False
5214
5215    def analyse_declarations(self, env):
5216        from . import ExprNodes
5217
5218        # handle declarations of the form x = cython.foo()
5219        if isinstance(self.rhs, ExprNodes.CallNode):
5220            func_name = self.rhs.function.as_cython_attribute()
5221            if func_name:
5222                args, kwds = self.rhs.explicit_args_kwds()
5223                if func_name in ['declare', 'typedef']:
5224                    if len(args) > 2:
5225                        error(args[2].pos, "Invalid positional argument.")
5226                        return
5227                    if kwds is not None:
5228                        kwdict = kwds.compile_time_value(None)
5229                        if func_name == 'typedef' or 'visibility' not in kwdict:
5230                            error(kwds.pos, "Invalid keyword argument.")
5231                            return
5232                        visibility = kwdict['visibility']
5233                    else:
5234                        visibility = 'private'
5235                    type = args[0].analyse_as_type(env)
5236                    if type is None:
5237                        error(args[0].pos, "Unknown type")
5238                        return
5239                    lhs = self.lhs
5240                    if func_name == 'declare':
5241                        if isinstance(lhs, ExprNodes.NameNode):
5242                            vars = [(lhs.name, lhs.pos)]
5243                        elif isinstance(lhs, ExprNodes.TupleNode):
5244                            vars = [(var.name, var.pos) for var in lhs.args]
5245                        else:
5246                            error(lhs.pos, "Invalid declaration")
5247                            return
5248                        for var, pos in vars:
5249                            env.declare_var(var, type, pos, is_cdef=True, visibility=visibility)
5250                        if len(args) == 2:
5251                            # we have a value
5252                            self.rhs = args[1]
5253                        else:
5254                            self.declaration_only = True
5255                    else:
5256                        self.declaration_only = True
5257                        if not isinstance(lhs, ExprNodes.NameNode):
5258                            error(lhs.pos, "Invalid declaration.")
5259                        env.declare_typedef(lhs.name, type, self.pos, visibility='private')
5260
5261                elif func_name in ['struct', 'union']:
5262                    self.declaration_only = True
5263                    if len(args) > 0 or kwds is None:
5264                        error(self.rhs.pos, "Struct or union members must be given by name.")
5265                        return
5266                    members = []
5267                    for member, type_node in kwds.key_value_pairs:
5268                        type = type_node.analyse_as_type(env)
5269                        if type is None:
5270                            error(type_node.pos, "Unknown type")
5271                        else:
5272                            members.append((member.value, type, member.pos))
5273                    if len(members) < len(kwds.key_value_pairs):
5274                        return
5275                    if not isinstance(self.lhs, ExprNodes.NameNode):
5276                        error(self.lhs.pos, "Invalid declaration.")
5277                    name = self.lhs.name
5278                    scope = StructOrUnionScope(name)
5279                    env.declare_struct_or_union(name, func_name, scope, False, self.rhs.pos)
5280                    for member, type, pos in members:
5281                        scope.declare_var(member, type, pos)
5282
5283                elif func_name == 'fused_type':
5284                    # dtype = cython.fused_type(...)
5285                    self.declaration_only = True
5286                    if kwds:
5287                        error(self.rhs.function.pos,
5288                              "fused_type does not take keyword arguments")
5289
5290                    fusednode = FusedTypeNode(self.rhs.pos,
5291                                              name=self.lhs.name, types=args)
5292                    fusednode.analyse_declarations(env)
5293
5294        if self.declaration_only:
5295            return
5296        else:
5297            self.lhs.analyse_target_declaration(env)
5298
5299    def analyse_types(self, env, use_temp=0):
5300        from . import ExprNodes
5301
5302        self.rhs = self.rhs.analyse_types(env)
5303
5304        unrolled_assignment = self.unroll_rhs(env)
5305        if unrolled_assignment:
5306            return unrolled_assignment
5307
5308        self.lhs = self.lhs.analyse_target_types(env)
5309        self.lhs.gil_assignment_check(env)
5310        unrolled_assignment = self.unroll_lhs(env)
5311        if unrolled_assignment:
5312            return unrolled_assignment
5313
5314        if isinstance(self.lhs, ExprNodes.MemoryViewIndexNode):
5315            self.lhs.analyse_broadcast_operation(self.rhs)
5316            self.lhs = self.lhs.analyse_as_memview_scalar_assignment(self.rhs)
5317        elif self.lhs.type.is_array:
5318            if not isinstance(self.lhs, ExprNodes.SliceIndexNode):
5319                # cannot assign to C array, only to its full slice
5320                self.lhs = ExprNodes.SliceIndexNode(self.lhs.pos, base=self.lhs, start=None, stop=None)
5321                self.lhs = self.lhs.analyse_target_types(env)
5322
5323        if self.lhs.type.is_cpp_class:
5324            op = env.lookup_operator_for_types(self.pos, '=', [self.lhs.type, self.rhs.type])
5325            if op:
5326                rhs = self.rhs
5327                self.is_overloaded_assignment = True
5328                self.exception_check = op.type.exception_check
5329                self.exception_value = op.type.exception_value
5330                if self.exception_check == '+' and self.exception_value is None:
5331                    env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp"))
5332            else:
5333                rhs = self.rhs.coerce_to(self.lhs.type, env)
5334        else:
5335            rhs = self.rhs.coerce_to(self.lhs.type, env)
5336
5337        if use_temp or rhs.is_attribute or (
5338                not rhs.is_name and not rhs.is_literal and
5339                rhs.type.is_pyobject):
5340            # things like (cdef) attribute access are not safe (traverses pointers)
5341            rhs = rhs.coerce_to_temp(env)
5342        elif rhs.type.is_pyobject:
5343            rhs = rhs.coerce_to_simple(env)
5344        self.rhs = rhs
5345        return self
5346
5347    def unroll(self, node, target_size, env):
5348        from . import ExprNodes, UtilNodes
5349
5350        base = node
5351        start_node = stop_node = step_node = check_node = None
5352
5353        if node.type.is_ctuple:
5354            slice_size = node.type.size
5355
5356        elif node.type.is_ptr or node.type.is_array:
5357            while isinstance(node, ExprNodes.SliceIndexNode) and not (node.start or node.stop):
5358                base = node = node.base
5359            if isinstance(node, ExprNodes.SliceIndexNode):
5360                base = node.base
5361                start_node = node.start
5362                if start_node:
5363                    start_node = start_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env)
5364                stop_node = node.stop
5365                if stop_node:
5366                    stop_node = stop_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env)
5367                else:
5368                    if node.type.is_array and node.type.size:
5369                        stop_node = ExprNodes.IntNode(
5370                            self.pos, value=str(node.type.size),
5371                            constant_result=(node.type.size if isinstance(node.type.size, _py_int_types)
5372                                             else ExprNodes.constant_value_not_set))
5373                    else:
5374                        error(self.pos, "C array iteration requires known end index")
5375                        return
5376                step_node = None  #node.step
5377                if step_node:
5378                    step_node = step_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env)
5379
5380                # TODO: Factor out SliceIndexNode.generate_slice_guard_code() for use here.
5381                def get_const(node, none_value):
5382                    if node is None:
5383                        return none_value
5384                    elif node.has_constant_result():
5385                        return node.constant_result
5386                    else:
5387                        raise ValueError("Not a constant.")
5388
5389                try:
5390                    slice_size = (get_const(stop_node, None) - get_const(start_node, 0)) / get_const(step_node, 1)
5391                except ValueError:
5392                    error(self.pos, "C array assignment currently requires known endpoints")
5393                    return
5394
5395            elif node.type.is_array:
5396                slice_size = node.type.size
5397                if not isinstance(slice_size, _py_int_types):
5398                    return  # might still work when coercing to Python
5399            else:
5400                return
5401
5402        else:
5403            return
5404
5405        if slice_size != target_size:
5406            error(self.pos, "Assignment to/from slice of wrong length, expected %s, got %s" % (
5407                slice_size, target_size))
5408            return
5409
5410        items = []
5411        base = UtilNodes.LetRefNode(base)
5412        refs = [base]
5413        if start_node and not start_node.is_literal:
5414            start_node = UtilNodes.LetRefNode(start_node)
5415            refs.append(start_node)
5416        if stop_node and not stop_node.is_literal:
5417            stop_node = UtilNodes.LetRefNode(stop_node)
5418            refs.append(stop_node)
5419        if step_node and not step_node.is_literal:
5420            step_node = UtilNodes.LetRefNode(step_node)
5421            refs.append(step_node)
5422
5423        for ix in range(target_size):
5424            ix_node = ExprNodes.IntNode(self.pos, value=str(ix), constant_result=ix, type=PyrexTypes.c_py_ssize_t_type)
5425            if step_node is not None:
5426                if step_node.has_constant_result():
5427                    step_value = ix_node.constant_result * step_node.constant_result
5428                    ix_node = ExprNodes.IntNode(self.pos, value=str(step_value), constant_result=step_value)
5429                else:
5430                    ix_node = ExprNodes.MulNode(self.pos, operator='*', operand1=step_node, operand2=ix_node)
5431            if start_node is not None:
5432                if start_node.has_constant_result() and ix_node.has_constant_result():
5433                    index_value = ix_node.constant_result + start_node.constant_result
5434                    ix_node = ExprNodes.IntNode(self.pos, value=str(index_value), constant_result=index_value)
5435                else:
5436                    ix_node = ExprNodes.AddNode(
5437                        self.pos, operator='+', operand1=start_node, operand2=ix_node)
5438            items.append(ExprNodes.IndexNode(self.pos, base=base, index=ix_node.analyse_types(env)))
5439        return check_node, refs, items
5440
5441    def unroll_assignments(self, refs, check_node, lhs_list, rhs_list, env):
5442        from . import UtilNodes
5443        assignments = []
5444        for lhs, rhs in zip(lhs_list, rhs_list):
5445            assignments.append(SingleAssignmentNode(self.pos, lhs=lhs, rhs=rhs, first=self.first))
5446        node = ParallelAssignmentNode(pos=self.pos, stats=assignments).analyse_expressions(env)
5447        if check_node:
5448            node = StatListNode(pos=self.pos, stats=[check_node, node])
5449        for ref in refs[::-1]:
5450            node = UtilNodes.LetNode(ref, node)
5451        return node
5452
5453    def unroll_rhs(self, env):
5454        from . import ExprNodes
5455        if not isinstance(self.lhs, ExprNodes.TupleNode):
5456            return
5457        if any(arg.is_starred for arg in self.lhs.args):
5458            return
5459
5460        unrolled = self.unroll(self.rhs, len(self.lhs.args), env)
5461        if not unrolled:
5462            return
5463        check_node, refs, rhs = unrolled
5464        return self.unroll_assignments(refs, check_node, self.lhs.args, rhs, env)
5465
5466    def unroll_lhs(self, env):
5467        if self.lhs.type.is_ctuple:
5468            # Handled directly.
5469            return
5470        from . import ExprNodes
5471        if not isinstance(self.rhs, ExprNodes.TupleNode):
5472            return
5473
5474        unrolled = self.unroll(self.lhs, len(self.rhs.args), env)
5475        if not unrolled:
5476            return
5477        check_node, refs, lhs = unrolled
5478        return self.unroll_assignments(refs, check_node, lhs, self.rhs.args, env)
5479
5480    def generate_rhs_evaluation_code(self, code):
5481        self.rhs.generate_evaluation_code(code)
5482
5483    def generate_assignment_code(self, code, overloaded_assignment=False):
5484        if self.is_overloaded_assignment:
5485            self.lhs.generate_assignment_code(
5486                self.rhs,
5487                code,
5488                overloaded_assignment=self.is_overloaded_assignment,
5489                exception_check=self.exception_check,
5490                exception_value=self.exception_value)
5491        else:
5492            self.lhs.generate_assignment_code(self.rhs, code)
5493
5494    def generate_function_definitions(self, env, code):
5495        self.rhs.generate_function_definitions(env, code)
5496
5497    def annotate(self, code):
5498        self.lhs.annotate(code)
5499        self.rhs.annotate(code)
5500
5501
5502class CascadedAssignmentNode(AssignmentNode):
5503    #  An assignment with multiple left hand sides:
5504    #
5505    #    a = b = c
5506    #
5507    #  lhs_list   [ExprNode]   Left hand sides
5508    #  rhs        ExprNode     Right hand sides
5509    #
5510    #  Used internally:
5511    #
5512    #  coerced_values       [ExprNode]   RHS coerced to all distinct LHS types
5513    #  cloned_values        [ExprNode]   cloned RHS value for each LHS
5514    #  assignment_overloads [Bool]       If each assignment uses a C++ operator=
5515
5516    child_attrs = ["lhs_list", "rhs", "coerced_values", "cloned_values"]
5517    cloned_values = None
5518    coerced_values = None
5519    assignment_overloads = None
5520
5521    def analyse_declarations(self, env):
5522        for lhs in self.lhs_list:
5523            lhs.analyse_target_declaration(env)
5524
5525    def analyse_types(self, env, use_temp=0):
5526        from .ExprNodes import CloneNode, ProxyNode
5527
5528        # collect distinct types used on the LHS
5529        lhs_types = set()
5530        for i, lhs in enumerate(self.lhs_list):
5531            lhs = self.lhs_list[i] = lhs.analyse_target_types(env)
5532            lhs.gil_assignment_check(env)
5533            lhs_types.add(lhs.type)
5534
5535        rhs = self.rhs.analyse_types(env)
5536        # common special case: only one type needed on the LHS => coerce only once
5537        if len(lhs_types) == 1:
5538            # Avoid coercion for overloaded assignment operators.
5539            if next(iter(lhs_types)).is_cpp_class:
5540                op = env.lookup_operator('=', [lhs, self.rhs])
5541                if not op:
5542                    rhs = rhs.coerce_to(lhs_types.pop(), env)
5543            else:
5544                rhs = rhs.coerce_to(lhs_types.pop(), env)
5545
5546        if not rhs.is_name and not rhs.is_literal and (
5547                use_temp or rhs.is_attribute or rhs.type.is_pyobject):
5548            rhs = rhs.coerce_to_temp(env)
5549        else:
5550            rhs = rhs.coerce_to_simple(env)
5551        self.rhs = ProxyNode(rhs) if rhs.is_temp else rhs
5552
5553        # clone RHS and coerce it to all distinct LHS types
5554        self.coerced_values = []
5555        coerced_values = {}
5556        self.assignment_overloads = []
5557        for lhs in self.lhs_list:
5558            overloaded = lhs.type.is_cpp_class and env.lookup_operator('=', [lhs, self.rhs])
5559            self.assignment_overloads.append(overloaded)
5560            if lhs.type not in coerced_values and lhs.type != rhs.type:
5561                rhs = CloneNode(self.rhs)
5562                if not overloaded:
5563                    rhs = rhs.coerce_to(lhs.type, env)
5564                self.coerced_values.append(rhs)
5565                coerced_values[lhs.type] = rhs
5566
5567        # clone coerced values for all LHS assignments
5568        self.cloned_values = []
5569        for lhs in self.lhs_list:
5570            rhs = coerced_values.get(lhs.type, self.rhs)
5571            self.cloned_values.append(CloneNode(rhs))
5572        return self
5573
5574    def generate_rhs_evaluation_code(self, code):
5575        self.rhs.generate_evaluation_code(code)
5576
5577    def generate_assignment_code(self, code, overloaded_assignment=False):
5578        # prepare all coercions
5579        for rhs in self.coerced_values:
5580            rhs.generate_evaluation_code(code)
5581        # assign clones to LHS
5582        for lhs, rhs, overload in zip(self.lhs_list, self.cloned_values, self.assignment_overloads):
5583            rhs.generate_evaluation_code(code)
5584            lhs.generate_assignment_code(rhs, code, overloaded_assignment=overload)
5585        # dispose of coerced values and original RHS
5586        for rhs_value in self.coerced_values:
5587            rhs_value.generate_disposal_code(code)
5588            rhs_value.free_temps(code)
5589        self.rhs.generate_disposal_code(code)
5590        self.rhs.free_temps(code)
5591
5592    def generate_function_definitions(self, env, code):
5593        self.rhs.generate_function_definitions(env, code)
5594
5595    def annotate(self, code):
5596        for rhs in self.coerced_values:
5597            rhs.annotate(code)
5598        for lhs, rhs in zip(self.lhs_list, self.cloned_values):
5599            lhs.annotate(code)
5600            rhs.annotate(code)
5601        self.rhs.annotate(code)
5602
5603
5604class ParallelAssignmentNode(AssignmentNode):
5605    #  A combined packing/unpacking assignment:
5606    #
5607    #    a, b, c =  d, e, f
5608    #
5609    #  This has been rearranged by the parser into
5610    #
5611    #    a = d ; b = e ; c = f
5612    #
5613    #  but we must evaluate all the right hand sides
5614    #  before assigning to any of the left hand sides.
5615    #
5616    #  stats     [AssignmentNode]   The constituent assignments
5617
5618    child_attrs = ["stats"]
5619
5620    def analyse_declarations(self, env):
5621        for stat in self.stats:
5622            stat.analyse_declarations(env)
5623
5624    def analyse_expressions(self, env):
5625        self.stats = [stat.analyse_types(env, use_temp=1)
5626                      for stat in self.stats]
5627        return self
5628
5629#    def analyse_expressions(self, env):
5630#        for stat in self.stats:
5631#            stat.analyse_expressions_1(env, use_temp=1)
5632#        for stat in self.stats:
5633#            stat.analyse_expressions_2(env)
5634
5635    def generate_execution_code(self, code):
5636        code.mark_pos(self.pos)
5637        for stat in self.stats:
5638            stat.generate_rhs_evaluation_code(code)
5639        for stat in self.stats:
5640            stat.generate_assignment_code(code)
5641
5642    def generate_function_definitions(self, env, code):
5643        for stat in self.stats:
5644            stat.generate_function_definitions(env, code)
5645
5646    def annotate(self, code):
5647        for stat in self.stats:
5648            stat.annotate(code)
5649
5650
5651class InPlaceAssignmentNode(AssignmentNode):
5652    #  An in place arithmetic operand:
5653    #
5654    #    a += b
5655    #    a -= b
5656    #    ...
5657    #
5658    #  lhs      ExprNode      Left hand side
5659    #  rhs      ExprNode      Right hand side
5660    #  operator char          one of "+-*/%^&|"
5661    #
5662    #  This code is a bit tricky because in order to obey Python
5663    #  semantics the sub-expressions (e.g. indices) of the lhs must
5664    #  not be evaluated twice. So we must re-use the values calculated
5665    #  in evaluation phase for the assignment phase as well.
5666    #  Fortunately, the type of the lhs node is fairly constrained
5667    #  (it must be a NameNode, AttributeNode, or IndexNode).
5668
5669    child_attrs = ["lhs", "rhs"]
5670
5671    def analyse_declarations(self, env):
5672        self.lhs.analyse_target_declaration(env)
5673
5674    def analyse_types(self, env):
5675        self.rhs = self.rhs.analyse_types(env)
5676        self.lhs = self.lhs.analyse_target_types(env)
5677
5678        # When assigning to a fully indexed buffer or memoryview, coerce the rhs
5679        if self.lhs.is_memview_index or self.lhs.is_buffer_access:
5680            self.rhs = self.rhs.coerce_to(self.lhs.type, env)
5681        elif self.lhs.type.is_string and self.operator in '+-':
5682            # use pointer arithmetic for char* LHS instead of string concat
5683            self.rhs = self.rhs.coerce_to(PyrexTypes.c_py_ssize_t_type, env)
5684        return self
5685
5686    def generate_execution_code(self, code):
5687        code.mark_pos(self.pos)
5688        lhs, rhs = self.lhs, self.rhs
5689        rhs.generate_evaluation_code(code)
5690        lhs.generate_subexpr_evaluation_code(code)
5691        c_op = self.operator
5692        if c_op == "//":
5693            c_op = "/"
5694        elif c_op == "**":
5695            error(self.pos, "No C inplace power operator")
5696        if lhs.is_buffer_access or lhs.is_memview_index:
5697            if lhs.type.is_pyobject:
5698                error(self.pos, "In-place operators not allowed on object buffers in this release.")
5699            if c_op in ('/', '%') and lhs.type.is_int and not code.globalstate.directives['cdivision']:
5700                error(self.pos, "In-place non-c divide operators not allowed on int buffers.")
5701            lhs.generate_buffer_setitem_code(rhs, code, c_op)
5702        elif lhs.is_memview_slice:
5703            error(self.pos, "Inplace operators not supported on memoryview slices")
5704        else:
5705            # C++
5706            # TODO: make sure overload is declared
5707            code.putln("%s %s= %s;" % (lhs.result(), c_op, rhs.result()))
5708        lhs.generate_subexpr_disposal_code(code)
5709        lhs.free_subexpr_temps(code)
5710        rhs.generate_disposal_code(code)
5711        rhs.free_temps(code)
5712
5713    def annotate(self, code):
5714        self.lhs.annotate(code)
5715        self.rhs.annotate(code)
5716
5717    def create_binop_node(self):
5718        from . import ExprNodes
5719        return ExprNodes.binop_node(self.pos, self.operator, self.lhs, self.rhs)
5720
5721
5722class PrintStatNode(StatNode):
5723    #  print statement
5724    #
5725    #  arg_tuple         TupleNode
5726    #  stream            ExprNode or None (stdout)
5727    #  append_newline    boolean
5728
5729    child_attrs = ["arg_tuple", "stream"]
5730
5731    def analyse_expressions(self, env):
5732        if self.stream:
5733            stream = self.stream.analyse_expressions(env)
5734            self.stream = stream.coerce_to_pyobject(env)
5735        arg_tuple = self.arg_tuple.analyse_expressions(env)
5736        self.arg_tuple = arg_tuple.coerce_to_pyobject(env)
5737        env.use_utility_code(printing_utility_code)
5738        if len(self.arg_tuple.args) == 1 and self.append_newline:
5739            env.use_utility_code(printing_one_utility_code)
5740        return self
5741
5742    nogil_check = Node.gil_error
5743    gil_message = "Python print statement"
5744
5745    def generate_execution_code(self, code):
5746        code.mark_pos(self.pos)
5747        if self.stream:
5748            self.stream.generate_evaluation_code(code)
5749            stream_result = self.stream.py_result()
5750        else:
5751            stream_result = '0'
5752        if len(self.arg_tuple.args) == 1 and self.append_newline:
5753            arg = self.arg_tuple.args[0]
5754            arg.generate_evaluation_code(code)
5755
5756            code.putln(
5757                "if (__Pyx_PrintOne(%s, %s) < 0) %s" % (
5758                    stream_result,
5759                    arg.py_result(),
5760                    code.error_goto(self.pos)))
5761            arg.generate_disposal_code(code)
5762            arg.free_temps(code)
5763        else:
5764            self.arg_tuple.generate_evaluation_code(code)
5765            code.putln(
5766                "if (__Pyx_Print(%s, %s, %d) < 0) %s" % (
5767                    stream_result,
5768                    self.arg_tuple.py_result(),
5769                    self.append_newline,
5770                    code.error_goto(self.pos)))
5771            self.arg_tuple.generate_disposal_code(code)
5772            self.arg_tuple.free_temps(code)
5773
5774        if self.stream:
5775            self.stream.generate_disposal_code(code)
5776            self.stream.free_temps(code)
5777
5778    def generate_function_definitions(self, env, code):
5779        if self.stream:
5780            self.stream.generate_function_definitions(env, code)
5781        self.arg_tuple.generate_function_definitions(env, code)
5782
5783    def annotate(self, code):
5784        if self.stream:
5785            self.stream.annotate(code)
5786        self.arg_tuple.annotate(code)
5787
5788
5789class ExecStatNode(StatNode):
5790    #  exec statement
5791    #
5792    #  args     [ExprNode]
5793
5794    child_attrs = ["args"]
5795
5796    def analyse_expressions(self, env):
5797        for i, arg in enumerate(self.args):
5798            arg = arg.analyse_expressions(env)
5799            arg = arg.coerce_to_pyobject(env)
5800            self.args[i] = arg
5801        env.use_utility_code(Builtin.pyexec_utility_code)
5802        return self
5803
5804    nogil_check = Node.gil_error
5805    gil_message = "Python exec statement"
5806
5807    def generate_execution_code(self, code):
5808        code.mark_pos(self.pos)
5809        args = []
5810        for arg in self.args:
5811            arg.generate_evaluation_code(code)
5812            args.append(arg.py_result())
5813        args = tuple(args + ['0', '0'][:3-len(args)])
5814        temp_result = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
5815        code.putln("%s = __Pyx_PyExec3(%s, %s, %s);" % ((temp_result,) + args))
5816        for arg in self.args:
5817            arg.generate_disposal_code(code)
5818            arg.free_temps(code)
5819        code.putln(
5820            code.error_goto_if_null(temp_result, self.pos))
5821        code.put_gotref(temp_result)
5822        code.put_decref_clear(temp_result, py_object_type)
5823        code.funcstate.release_temp(temp_result)
5824
5825    def annotate(self, code):
5826        for arg in self.args:
5827            arg.annotate(code)
5828
5829
5830class DelStatNode(StatNode):
5831    #  del statement
5832    #
5833    #  args     [ExprNode]
5834
5835    child_attrs = ["args"]
5836    ignore_nonexisting = False
5837
5838    def analyse_declarations(self, env):
5839        for arg in self.args:
5840            arg.analyse_target_declaration(env)
5841
5842    def analyse_expressions(self, env):
5843        for i, arg in enumerate(self.args):
5844            arg = self.args[i] = arg.analyse_target_expression(env, None)
5845            if arg.type.is_pyobject or (arg.is_name and arg.type.is_memoryviewslice):
5846                if arg.is_name and arg.entry.is_cglobal:
5847                    error(arg.pos, "Deletion of global C variable")
5848            elif arg.type.is_ptr and arg.type.base_type.is_cpp_class:
5849                self.cpp_check(env)
5850            elif arg.type.is_cpp_class:
5851                error(arg.pos, "Deletion of non-heap C++ object")
5852            elif arg.is_subscript and arg.base.type is Builtin.bytearray_type:
5853                pass  # del ba[i]
5854            else:
5855                error(arg.pos, "Deletion of non-Python, non-C++ object")
5856            #arg.release_target_temp(env)
5857        return self
5858
5859    def nogil_check(self, env):
5860        for arg in self.args:
5861            if arg.type.is_pyobject:
5862                self.gil_error()
5863
5864    gil_message = "Deleting Python object"
5865
5866    def generate_execution_code(self, code):
5867        code.mark_pos(self.pos)
5868        for arg in self.args:
5869            if (arg.type.is_pyobject or
5870                    arg.type.is_memoryviewslice or
5871                    arg.is_subscript and arg.base.type is Builtin.bytearray_type):
5872                arg.generate_deletion_code(
5873                    code, ignore_nonexisting=self.ignore_nonexisting)
5874            elif arg.type.is_ptr and arg.type.base_type.is_cpp_class:
5875                arg.generate_evaluation_code(code)
5876                code.putln("delete %s;" % arg.result())
5877                arg.generate_disposal_code(code)
5878                arg.free_temps(code)
5879            # else error reported earlier
5880
5881    def annotate(self, code):
5882        for arg in self.args:
5883            arg.annotate(code)
5884
5885
5886class PassStatNode(StatNode):
5887    #  pass statement
5888
5889    child_attrs = []
5890
5891    def analyse_expressions(self, env):
5892        return self
5893
5894    def generate_execution_code(self, code):
5895        pass
5896
5897
5898class IndirectionNode(StatListNode):
5899    """
5900    This adds an indirection so that the node can be shared and a subtree can
5901    be removed at any time by clearing self.stats.
5902    """
5903
5904    def __init__(self, stats):
5905        super(IndirectionNode, self).__init__(stats[0].pos, stats=stats)
5906
5907
5908class BreakStatNode(StatNode):
5909
5910    child_attrs = []
5911    is_terminator = True
5912
5913    def analyse_expressions(self, env):
5914        return self
5915
5916    def generate_execution_code(self, code):
5917        code.mark_pos(self.pos)
5918        if not code.break_label:
5919            error(self.pos, "break statement not inside loop")
5920        else:
5921            code.put_goto(code.break_label)
5922
5923
5924class ContinueStatNode(StatNode):
5925
5926    child_attrs = []
5927    is_terminator = True
5928
5929    def analyse_expressions(self, env):
5930        return self
5931
5932    def generate_execution_code(self, code):
5933        if not code.continue_label:
5934            error(self.pos, "continue statement not inside loop")
5935            return
5936        code.mark_pos(self.pos)
5937        code.put_goto(code.continue_label)
5938
5939
5940class ReturnStatNode(StatNode):
5941    #  return statement
5942    #
5943    #  value         ExprNode or None
5944    #  return_type   PyrexType
5945    #  in_generator  return inside of generator => raise StopIteration
5946    #  in_async_gen  return inside of async generator
5947
5948    child_attrs = ["value"]
5949    is_terminator = True
5950    in_generator = False
5951    in_async_gen = False
5952
5953    # Whether we are in a parallel section
5954    in_parallel = False
5955
5956    def analyse_expressions(self, env):
5957        return_type = env.return_type
5958        self.return_type = return_type
5959        if not return_type:
5960            error(self.pos, "Return not inside a function body")
5961            return self
5962        if self.value:
5963            if self.in_async_gen:
5964                error(self.pos, "Return with value in async generator")
5965            self.value = self.value.analyse_types(env)
5966            if return_type.is_void or return_type.is_returncode:
5967                error(self.value.pos, "Return with value in void function")
5968            else:
5969                self.value = self.value.coerce_to(env.return_type, env)
5970        else:
5971            if (not return_type.is_void
5972                    and not return_type.is_pyobject
5973                    and not return_type.is_returncode):
5974                error(self.pos, "Return value required")
5975        return self
5976
5977    def nogil_check(self, env):
5978        if self.return_type.is_pyobject:
5979            self.gil_error()
5980
5981    gil_message = "Returning Python object"
5982
5983    def generate_execution_code(self, code):
5984        code.mark_pos(self.pos)
5985        if not self.return_type:
5986            # error reported earlier
5987            return
5988
5989        value = self.value
5990        if self.return_type.is_pyobject:
5991            code.put_xdecref(Naming.retval_cname, self.return_type)
5992            if value and value.is_none:
5993                # Use specialised default handling for "return None".
5994                value = None
5995
5996        if value:
5997            value.generate_evaluation_code(code)
5998            if self.return_type.is_memoryviewslice:
5999                from . import MemoryView
6000                MemoryView.put_acquire_memoryviewslice(
6001                    lhs_cname=Naming.retval_cname,
6002                    lhs_type=self.return_type,
6003                    lhs_pos=value.pos,
6004                    rhs=value,
6005                    code=code,
6006                    have_gil=self.in_nogil_context)
6007                value.generate_post_assignment_code(code)
6008            elif self.in_generator:
6009                # return value == raise StopIteration(value), but uncatchable
6010                code.globalstate.use_utility_code(
6011                    UtilityCode.load_cached("ReturnWithStopIteration", "Coroutine.c"))
6012                code.putln("%s = NULL; __Pyx_ReturnWithStopIteration(%s);" % (
6013                    Naming.retval_cname,
6014                    value.py_result()))
6015                value.generate_disposal_code(code)
6016            else:
6017                value.make_owned_reference(code)
6018                code.putln("%s = %s;" % (
6019                    Naming.retval_cname,
6020                    value.result_as(self.return_type)))
6021                value.generate_post_assignment_code(code)
6022            value.free_temps(code)
6023        else:
6024            if self.return_type.is_pyobject:
6025                if self.in_generator:
6026                    if self.in_async_gen:
6027                        code.globalstate.use_utility_code(
6028                            UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c"))
6029                        code.put("PyErr_SetNone(__Pyx_PyExc_StopAsyncIteration); ")
6030                    code.putln("%s = NULL;" % Naming.retval_cname)
6031                else:
6032                    code.put_init_to_py_none(Naming.retval_cname, self.return_type)
6033            elif self.return_type.is_returncode:
6034                self.put_return(code, self.return_type.default_value)
6035
6036        for cname, type in code.funcstate.temps_holding_reference():
6037            code.put_decref_clear(cname, type)
6038
6039        code.put_goto(code.return_label)
6040
6041    def put_return(self, code, value):
6042        if self.in_parallel:
6043            code.putln_openmp("#pragma omp critical(__pyx_returning)")
6044        code.putln("%s = %s;" % (Naming.retval_cname, value))
6045
6046    def generate_function_definitions(self, env, code):
6047        if self.value is not None:
6048            self.value.generate_function_definitions(env, code)
6049
6050    def annotate(self, code):
6051        if self.value:
6052            self.value.annotate(code)
6053
6054
6055class RaiseStatNode(StatNode):
6056    #  raise statement
6057    #
6058    #  exc_type    ExprNode or None
6059    #  exc_value   ExprNode or None
6060    #  exc_tb      ExprNode or None
6061    #  cause       ExprNode or None
6062
6063    child_attrs = ["exc_type", "exc_value", "exc_tb", "cause"]
6064    is_terminator = True
6065
6066    def analyse_expressions(self, env):
6067        if self.exc_type:
6068            exc_type = self.exc_type.analyse_types(env)
6069            self.exc_type = exc_type.coerce_to_pyobject(env)
6070        if self.exc_value:
6071            exc_value = self.exc_value.analyse_types(env)
6072            self.exc_value = exc_value.coerce_to_pyobject(env)
6073        if self.exc_tb:
6074            exc_tb = self.exc_tb.analyse_types(env)
6075            self.exc_tb = exc_tb.coerce_to_pyobject(env)
6076        if self.cause:
6077            cause = self.cause.analyse_types(env)
6078            self.cause = cause.coerce_to_pyobject(env)
6079        # special cases for builtin exceptions
6080        self.builtin_exc_name = None
6081        if self.exc_type and not self.exc_value and not self.exc_tb:
6082            exc = self.exc_type
6083            from . import ExprNodes
6084            if (isinstance(exc, ExprNodes.SimpleCallNode) and
6085                    not (exc.args or (exc.arg_tuple is not None and exc.arg_tuple.args))):
6086                exc = exc.function  # extract the exception type
6087            if exc.is_name and exc.entry.is_builtin:
6088                self.builtin_exc_name = exc.name
6089                if self.builtin_exc_name == 'MemoryError':
6090                    self.exc_type = None # has a separate implementation
6091        return self
6092
6093    nogil_check = Node.gil_error
6094    gil_message = "Raising exception"
6095
6096    def generate_execution_code(self, code):
6097        code.mark_pos(self.pos)
6098        if self.builtin_exc_name == 'MemoryError':
6099            code.putln('PyErr_NoMemory(); %s' % code.error_goto(self.pos))
6100            return
6101
6102        if self.exc_type:
6103            self.exc_type.generate_evaluation_code(code)
6104            type_code = self.exc_type.py_result()
6105            if self.exc_type.is_name:
6106                code.globalstate.use_entry_utility_code(self.exc_type.entry)
6107        else:
6108            type_code = "0"
6109        if self.exc_value:
6110            self.exc_value.generate_evaluation_code(code)
6111            value_code = self.exc_value.py_result()
6112        else:
6113            value_code = "0"
6114        if self.exc_tb:
6115            self.exc_tb.generate_evaluation_code(code)
6116            tb_code = self.exc_tb.py_result()
6117        else:
6118            tb_code = "0"
6119        if self.cause:
6120            self.cause.generate_evaluation_code(code)
6121            cause_code = self.cause.py_result()
6122        else:
6123            cause_code = "0"
6124        code.globalstate.use_utility_code(raise_utility_code)
6125        code.putln(
6126            "__Pyx_Raise(%s, %s, %s, %s);" % (
6127                type_code,
6128                value_code,
6129                tb_code,
6130                cause_code))
6131        for obj in (self.exc_type, self.exc_value, self.exc_tb, self.cause):
6132            if obj:
6133                obj.generate_disposal_code(code)
6134                obj.free_temps(code)
6135        code.putln(
6136            code.error_goto(self.pos))
6137
6138    def generate_function_definitions(self, env, code):
6139        if self.exc_type is not None:
6140            self.exc_type.generate_function_definitions(env, code)
6141        if self.exc_value is not None:
6142            self.exc_value.generate_function_definitions(env, code)
6143        if self.exc_tb is not None:
6144            self.exc_tb.generate_function_definitions(env, code)
6145        if self.cause is not None:
6146            self.cause.generate_function_definitions(env, code)
6147
6148    def annotate(self, code):
6149        if self.exc_type:
6150            self.exc_type.annotate(code)
6151        if self.exc_value:
6152            self.exc_value.annotate(code)
6153        if self.exc_tb:
6154            self.exc_tb.annotate(code)
6155        if self.cause:
6156            self.cause.annotate(code)
6157
6158
6159class ReraiseStatNode(StatNode):
6160
6161    child_attrs = []
6162    is_terminator = True
6163
6164    def analyse_expressions(self, env):
6165        return self
6166
6167    nogil_check = Node.gil_error
6168    gil_message = "Raising exception"
6169
6170    def generate_execution_code(self, code):
6171        code.mark_pos(self.pos)
6172        vars = code.funcstate.exc_vars
6173        if vars:
6174            code.globalstate.use_utility_code(restore_exception_utility_code)
6175            code.put_giveref(vars[0])
6176            code.put_giveref(vars[1])
6177            # fresh exceptions may not have a traceback yet (-> finally!)
6178            code.put_xgiveref(vars[2])
6179            code.putln("__Pyx_ErrRestoreWithState(%s, %s, %s);" % tuple(vars))
6180            for varname in vars:
6181                code.put("%s = 0; " % varname)
6182            code.putln()
6183            code.putln(code.error_goto(self.pos))
6184        else:
6185            code.globalstate.use_utility_code(
6186                UtilityCode.load_cached("ReRaiseException", "Exceptions.c"))
6187            code.putln("__Pyx_ReraiseException(); %s" % code.error_goto(self.pos))
6188
6189class AssertStatNode(StatNode):
6190    #  assert statement
6191    #
6192    #  cond    ExprNode
6193    #  value   ExprNode or None
6194
6195    child_attrs = ["cond", "value"]
6196
6197    def analyse_expressions(self, env):
6198        self.cond = self.cond.analyse_boolean_expression(env)
6199        if self.value:
6200            value = self.value.analyse_types(env)
6201            if value.type is Builtin.tuple_type or not value.type.is_builtin_type:
6202                # prevent tuple values from being interpreted as argument value tuples
6203                from .ExprNodes import TupleNode
6204                value = TupleNode(value.pos, args=[value], slow=True)
6205                self.value = value.analyse_types(env, skip_children=True).coerce_to_pyobject(env)
6206            else:
6207                self.value = value.coerce_to_pyobject(env)
6208        return self
6209
6210    nogil_check = Node.gil_error
6211    gil_message = "Raising exception"
6212
6213    def generate_execution_code(self, code):
6214        code.putln("#ifndef CYTHON_WITHOUT_ASSERTIONS")
6215        code.putln("if (unlikely(!Py_OptimizeFlag)) {")
6216        code.mark_pos(self.pos)
6217        self.cond.generate_evaluation_code(code)
6218        code.putln(
6219            "if (unlikely(!%s)) {" % self.cond.result())
6220        if self.value:
6221            self.value.generate_evaluation_code(code)
6222            code.putln(
6223                "PyErr_SetObject(PyExc_AssertionError, %s);" % self.value.py_result())
6224            self.value.generate_disposal_code(code)
6225            self.value.free_temps(code)
6226        else:
6227            code.putln(
6228                "PyErr_SetNone(PyExc_AssertionError);")
6229        code.putln(
6230            code.error_goto(self.pos))
6231        code.putln(
6232            "}")
6233        self.cond.generate_disposal_code(code)
6234        self.cond.free_temps(code)
6235        code.putln(
6236            "}")
6237        code.putln("#endif")
6238
6239    def generate_function_definitions(self, env, code):
6240        self.cond.generate_function_definitions(env, code)
6241        if self.value is not None:
6242            self.value.generate_function_definitions(env, code)
6243
6244    def annotate(self, code):
6245        self.cond.annotate(code)
6246        if self.value:
6247            self.value.annotate(code)
6248
6249
6250class IfStatNode(StatNode):
6251    #  if statement
6252    #
6253    #  if_clauses   [IfClauseNode]
6254    #  else_clause  StatNode or None
6255
6256    child_attrs = ["if_clauses", "else_clause"]
6257
6258    def analyse_declarations(self, env):
6259        for if_clause in self.if_clauses:
6260            if_clause.analyse_declarations(env)
6261        if self.else_clause:
6262            self.else_clause.analyse_declarations(env)
6263
6264    def analyse_expressions(self, env):
6265        self.if_clauses = [if_clause.analyse_expressions(env) for if_clause in self.if_clauses]
6266        if self.else_clause:
6267            self.else_clause = self.else_clause.analyse_expressions(env)
6268        return self
6269
6270    def generate_execution_code(self, code):
6271        code.mark_pos(self.pos)
6272        end_label = code.new_label()
6273        last = len(self.if_clauses)
6274        if self.else_clause:
6275            # If the 'else' clause is 'unlikely', then set the preceding 'if' clause to 'likely' to reflect that.
6276            self._set_branch_hint(self.if_clauses[-1], self.else_clause, inverse=True)
6277        else:
6278            last -= 1  # avoid redundant goto at end of last if-clause
6279        for i, if_clause in enumerate(self.if_clauses):
6280            self._set_branch_hint(if_clause, if_clause.body)
6281            if_clause.generate_execution_code(code, end_label, is_last=i == last)
6282        if self.else_clause:
6283            code.mark_pos(self.else_clause.pos)
6284            code.putln("/*else*/ {")
6285            self.else_clause.generate_execution_code(code)
6286            code.putln("}")
6287        code.put_label(end_label)
6288
6289    def _set_branch_hint(self, clause, statements_node, inverse=False):
6290        if not statements_node.is_terminator:
6291            return
6292        if not isinstance(statements_node, StatListNode) or not statements_node.stats:
6293            return
6294        # Anything that unconditionally raises exceptions should be considered unlikely.
6295        if isinstance(statements_node.stats[-1], (RaiseStatNode, ReraiseStatNode)):
6296            if len(statements_node.stats) > 1:
6297                # Allow simple statements before the 'raise', but no conditions, loops, etc.
6298                non_branch_nodes = (ExprStatNode, AssignmentNode, DelStatNode, GlobalNode, NonlocalNode)
6299                for node in statements_node.stats[:-1]:
6300                    if not isinstance(node, non_branch_nodes):
6301                        return
6302            clause.branch_hint = 'likely' if inverse else 'unlikely'
6303
6304    def generate_function_definitions(self, env, code):
6305        for clause in self.if_clauses:
6306            clause.generate_function_definitions(env, code)
6307        if self.else_clause is not None:
6308            self.else_clause.generate_function_definitions(env, code)
6309
6310    def annotate(self, code):
6311        for if_clause in self.if_clauses:
6312            if_clause.annotate(code)
6313        if self.else_clause:
6314            self.else_clause.annotate(code)
6315
6316
6317class IfClauseNode(Node):
6318    #  if or elif clause in an if statement
6319    #
6320    #  condition   ExprNode
6321    #  body        StatNode
6322
6323    child_attrs = ["condition", "body"]
6324    branch_hint = None
6325
6326    def analyse_declarations(self, env):
6327        self.body.analyse_declarations(env)
6328
6329    def analyse_expressions(self, env):
6330        self.condition = self.condition.analyse_temp_boolean_expression(env)
6331        self.body = self.body.analyse_expressions(env)
6332        return self
6333
6334    def generate_execution_code(self, code, end_label, is_last):
6335        self.condition.generate_evaluation_code(code)
6336        code.mark_pos(self.pos)
6337        condition = self.condition.result()
6338        if self.branch_hint:
6339            condition = '%s(%s)' % (self.branch_hint, condition)
6340        code.putln("if (%s) {" % condition)
6341        self.condition.generate_disposal_code(code)
6342        self.condition.free_temps(code)
6343        self.body.generate_execution_code(code)
6344        code.mark_pos(self.pos, trace=False)
6345        if not (is_last or self.body.is_terminator):
6346            code.put_goto(end_label)
6347        code.putln("}")
6348
6349    def generate_function_definitions(self, env, code):
6350        self.condition.generate_function_definitions(env, code)
6351        self.body.generate_function_definitions(env, code)
6352
6353    def annotate(self, code):
6354        self.condition.annotate(code)
6355        self.body.annotate(code)
6356
6357
6358class SwitchCaseNode(StatNode):
6359    # Generated in the optimization of an if-elif-else node
6360    #
6361    # conditions    [ExprNode]
6362    # body          StatNode
6363
6364    child_attrs = ['conditions', 'body']
6365
6366    def generate_condition_evaluation_code(self, code):
6367        for cond in self.conditions:
6368            cond.generate_evaluation_code(code)
6369
6370    def generate_execution_code(self, code):
6371        num_conditions = len(self.conditions)
6372        line_tracing_enabled = code.globalstate.directives['linetrace']
6373        for i, cond in enumerate(self.conditions, 1):
6374            code.putln("case %s:" % cond.result())
6375            code.mark_pos(cond.pos)  # Tracing code must appear *after* the 'case' statement.
6376            if line_tracing_enabled and i < num_conditions:
6377                # Allow fall-through after the line tracing code.
6378                code.putln('CYTHON_FALLTHROUGH;')
6379        self.body.generate_execution_code(code)
6380        code.mark_pos(self.pos, trace=False)
6381        code.putln("break;")
6382
6383    def generate_function_definitions(self, env, code):
6384        for cond in self.conditions:
6385            cond.generate_function_definitions(env, code)
6386        self.body.generate_function_definitions(env, code)
6387
6388    def annotate(self, code):
6389        for cond in self.conditions:
6390            cond.annotate(code)
6391        self.body.annotate(code)
6392
6393
6394class SwitchStatNode(StatNode):
6395    # Generated in the optimization of an if-elif-else node
6396    #
6397    # test          ExprNode
6398    # cases         [SwitchCaseNode]
6399    # else_clause   StatNode or None
6400
6401    child_attrs = ['test', 'cases', 'else_clause']
6402
6403    def generate_execution_code(self, code):
6404        self.test.generate_evaluation_code(code)
6405        # Make sure all conditions are evaluated before going into the switch() statement.
6406        # This is required in order to prevent any execution code from leaking into the space between the cases.
6407        for case in self.cases:
6408            case.generate_condition_evaluation_code(code)
6409        code.mark_pos(self.pos)
6410        code.putln("switch (%s) {" % self.test.result())
6411        for case in self.cases:
6412            case.generate_execution_code(code)
6413        if self.else_clause is not None:
6414            code.putln("default:")
6415            self.else_clause.generate_execution_code(code)
6416            code.putln("break;")
6417        else:
6418            # Always generate a default clause to prevent C compiler warnings
6419            # about unmatched enum values (it was not the user who decided to
6420            # generate the switch statement, so shouldn't be bothered).
6421            code.putln("default: break;")
6422        code.putln("}")
6423        self.test.generate_disposal_code(code)
6424        self.test.free_temps(code)
6425
6426    def generate_function_definitions(self, env, code):
6427        self.test.generate_function_definitions(env, code)
6428        for case in self.cases:
6429            case.generate_function_definitions(env, code)
6430        if self.else_clause is not None:
6431            self.else_clause.generate_function_definitions(env, code)
6432
6433    def annotate(self, code):
6434        self.test.annotate(code)
6435        for case in self.cases:
6436            case.annotate(code)
6437        if self.else_clause is not None:
6438            self.else_clause.annotate(code)
6439
6440
6441class LoopNode(object):
6442    pass
6443
6444
6445class WhileStatNode(LoopNode, StatNode):
6446    #  while statement
6447    #
6448    #  condition    ExprNode
6449    #  body         StatNode
6450    #  else_clause  StatNode
6451
6452    child_attrs = ["condition", "body", "else_clause"]
6453
6454    def analyse_declarations(self, env):
6455        self.body.analyse_declarations(env)
6456        if self.else_clause:
6457            self.else_clause.analyse_declarations(env)
6458
6459    def analyse_expressions(self, env):
6460        if self.condition:
6461            self.condition = self.condition.analyse_temp_boolean_expression(env)
6462        self.body = self.body.analyse_expressions(env)
6463        if self.else_clause:
6464            self.else_clause = self.else_clause.analyse_expressions(env)
6465        return self
6466
6467    def generate_execution_code(self, code):
6468        code.mark_pos(self.pos)
6469        old_loop_labels = code.new_loop_labels()
6470        code.putln(
6471            "while (1) {")
6472        if self.condition:
6473            self.condition.generate_evaluation_code(code)
6474            self.condition.generate_disposal_code(code)
6475            code.putln(
6476                "if (!%s) break;" % self.condition.result())
6477            self.condition.free_temps(code)
6478        self.body.generate_execution_code(code)
6479        code.put_label(code.continue_label)
6480        code.putln("}")
6481        break_label = code.break_label
6482        code.set_loop_labels(old_loop_labels)
6483        if self.else_clause:
6484            code.mark_pos(self.else_clause.pos)
6485            code.putln("/*else*/ {")
6486            self.else_clause.generate_execution_code(code)
6487            code.putln("}")
6488        code.put_label(break_label)
6489
6490    def generate_function_definitions(self, env, code):
6491        if self.condition:
6492            self.condition.generate_function_definitions(env, code)
6493        self.body.generate_function_definitions(env, code)
6494        if self.else_clause is not None:
6495            self.else_clause.generate_function_definitions(env, code)
6496
6497    def annotate(self, code):
6498        if self.condition:
6499            self.condition.annotate(code)
6500        self.body.annotate(code)
6501        if self.else_clause:
6502            self.else_clause.annotate(code)
6503
6504
6505class DictIterationNextNode(Node):
6506    # Helper node for calling PyDict_Next() inside of a WhileStatNode
6507    # and checking the dictionary size for changes.  Created in
6508    # Optimize.py.
6509    child_attrs = ['dict_obj', 'expected_size', 'pos_index_var',
6510                   'coerced_key_var', 'coerced_value_var', 'coerced_tuple_var',
6511                   'key_target', 'value_target', 'tuple_target', 'is_dict_flag']
6512
6513    coerced_key_var = key_ref = None
6514    coerced_value_var = value_ref = None
6515    coerced_tuple_var = tuple_ref = None
6516
6517    def __init__(self, dict_obj, expected_size, pos_index_var,
6518                 key_target, value_target, tuple_target, is_dict_flag):
6519        Node.__init__(
6520            self, dict_obj.pos,
6521            dict_obj=dict_obj,
6522            expected_size=expected_size,
6523            pos_index_var=pos_index_var,
6524            key_target=key_target,
6525            value_target=value_target,
6526            tuple_target=tuple_target,
6527            is_dict_flag=is_dict_flag,
6528            is_temp=True,
6529            type=PyrexTypes.c_bint_type)
6530
6531    def analyse_expressions(self, env):
6532        from . import ExprNodes
6533        self.dict_obj = self.dict_obj.analyse_types(env)
6534        self.expected_size = self.expected_size.analyse_types(env)
6535        if self.pos_index_var:
6536            self.pos_index_var = self.pos_index_var.analyse_types(env)
6537        if self.key_target:
6538            self.key_target = self.key_target.analyse_target_types(env)
6539            self.key_ref = ExprNodes.TempNode(self.key_target.pos, PyrexTypes.py_object_type)
6540            self.coerced_key_var = self.key_ref.coerce_to(self.key_target.type, env)
6541        if self.value_target:
6542            self.value_target = self.value_target.analyse_target_types(env)
6543            self.value_ref = ExprNodes.TempNode(self.value_target.pos, type=PyrexTypes.py_object_type)
6544            self.coerced_value_var = self.value_ref.coerce_to(self.value_target.type, env)
6545        if self.tuple_target:
6546            self.tuple_target = self.tuple_target.analyse_target_types(env)
6547            self.tuple_ref = ExprNodes.TempNode(self.tuple_target.pos, PyrexTypes.py_object_type)
6548            self.coerced_tuple_var = self.tuple_ref.coerce_to(self.tuple_target.type, env)
6549        self.is_dict_flag = self.is_dict_flag.analyse_types(env)
6550        return self
6551
6552    def generate_function_definitions(self, env, code):
6553        self.dict_obj.generate_function_definitions(env, code)
6554
6555    def generate_execution_code(self, code):
6556        code.globalstate.use_utility_code(UtilityCode.load_cached("dict_iter", "Optimize.c"))
6557        self.dict_obj.generate_evaluation_code(code)
6558
6559        assignments = []
6560        temp_addresses = []
6561        for var, result, target in [(self.key_ref, self.coerced_key_var, self.key_target),
6562                                    (self.value_ref, self.coerced_value_var, self.value_target),
6563                                    (self.tuple_ref, self.coerced_tuple_var, self.tuple_target)]:
6564            if target is None:
6565                addr = 'NULL'
6566            else:
6567                assignments.append((var, result, target))
6568                var.allocate(code)
6569                addr = '&%s' % var.result()
6570            temp_addresses.append(addr)
6571
6572        result_temp = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False)
6573        code.putln("%s = __Pyx_dict_iter_next(%s, %s, &%s, %s, %s, %s, %s);" % (
6574            result_temp,
6575            self.dict_obj.py_result(),
6576            self.expected_size.result(),
6577            self.pos_index_var.result(),
6578            temp_addresses[0],
6579            temp_addresses[1],
6580            temp_addresses[2],
6581            self.is_dict_flag.result()
6582        ))
6583        code.putln("if (unlikely(%s == 0)) break;" % result_temp)
6584        code.putln(code.error_goto_if("%s == -1" % result_temp, self.pos))
6585        code.funcstate.release_temp(result_temp)
6586
6587        # evaluate all coercions before the assignments
6588        for var, result, target in assignments:
6589            code.put_gotref(var.result())
6590        for var, result, target in assignments:
6591            result.generate_evaluation_code(code)
6592        for var, result, target in assignments:
6593            target.generate_assignment_code(result, code)
6594            var.release(code)
6595
6596
6597class SetIterationNextNode(Node):
6598    # Helper node for calling _PySet_NextEntry() inside of a WhileStatNode
6599    # and checking the set size for changes.  Created in Optimize.py.
6600    child_attrs = ['set_obj', 'expected_size', 'pos_index_var',
6601                   'coerced_value_var', 'value_target', 'is_set_flag']
6602
6603    coerced_value_var = value_ref = None
6604
6605    def __init__(self, set_obj, expected_size, pos_index_var, value_target, is_set_flag):
6606        Node.__init__(
6607            self, set_obj.pos,
6608            set_obj=set_obj,
6609            expected_size=expected_size,
6610            pos_index_var=pos_index_var,
6611            value_target=value_target,
6612            is_set_flag=is_set_flag,
6613            is_temp=True,
6614            type=PyrexTypes.c_bint_type)
6615
6616    def analyse_expressions(self, env):
6617        from . import ExprNodes
6618        self.set_obj = self.set_obj.analyse_types(env)
6619        self.expected_size = self.expected_size.analyse_types(env)
6620        self.pos_index_var = self.pos_index_var.analyse_types(env)
6621        self.value_target = self.value_target.analyse_target_types(env)
6622        self.value_ref = ExprNodes.TempNode(self.value_target.pos, type=PyrexTypes.py_object_type)
6623        self.coerced_value_var = self.value_ref.coerce_to(self.value_target.type, env)
6624        self.is_set_flag = self.is_set_flag.analyse_types(env)
6625        return self
6626
6627    def generate_function_definitions(self, env, code):
6628        self.set_obj.generate_function_definitions(env, code)
6629
6630    def generate_execution_code(self, code):
6631        code.globalstate.use_utility_code(UtilityCode.load_cached("set_iter", "Optimize.c"))
6632        self.set_obj.generate_evaluation_code(code)
6633
6634        value_ref = self.value_ref
6635        value_ref.allocate(code)
6636
6637        result_temp = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False)
6638        code.putln("%s = __Pyx_set_iter_next(%s, %s, &%s, &%s, %s);" % (
6639            result_temp,
6640            self.set_obj.py_result(),
6641            self.expected_size.result(),
6642            self.pos_index_var.result(),
6643            value_ref.result(),
6644            self.is_set_flag.result()
6645        ))
6646        code.putln("if (unlikely(%s == 0)) break;" % result_temp)
6647        code.putln(code.error_goto_if("%s == -1" % result_temp, self.pos))
6648        code.funcstate.release_temp(result_temp)
6649
6650        # evaluate all coercions before the assignments
6651        code.put_gotref(value_ref.result())
6652        self.coerced_value_var.generate_evaluation_code(code)
6653        self.value_target.generate_assignment_code(self.coerced_value_var, code)
6654        value_ref.release(code)
6655
6656
6657def ForStatNode(pos, **kw):
6658    if 'iterator' in kw:
6659        if kw['iterator'].is_async:
6660            return AsyncForStatNode(pos, **kw)
6661        else:
6662            return ForInStatNode(pos, **kw)
6663    else:
6664        return ForFromStatNode(pos, **kw)
6665
6666
6667class _ForInStatNode(LoopNode, StatNode):
6668    #  Base class of 'for-in' statements.
6669    #
6670    #  target        ExprNode
6671    #  iterator      IteratorNode | AIterAwaitExprNode(AsyncIteratorNode)
6672    #  body          StatNode
6673    #  else_clause   StatNode
6674    #  item          NextNode | AwaitExprNode(AsyncNextNode)
6675    #  is_async      boolean        true for 'async for' statements
6676
6677    child_attrs = ["target", "item", "iterator", "body", "else_clause"]
6678    item = None
6679    is_async = False
6680
6681    def _create_item_node(self):
6682        raise NotImplementedError("must be implemented by subclasses")
6683
6684    def analyse_declarations(self, env):
6685        self.target.analyse_target_declaration(env)
6686        self.body.analyse_declarations(env)
6687        if self.else_clause:
6688            self.else_clause.analyse_declarations(env)
6689        self._create_item_node()
6690
6691    def analyse_expressions(self, env):
6692        self.target = self.target.analyse_target_types(env)
6693        self.iterator = self.iterator.analyse_expressions(env)
6694        self._create_item_node()  # must rewrap self.item after analysis
6695        self.item = self.item.analyse_expressions(env)
6696        if (not self.is_async and
6697                (self.iterator.type.is_ptr or self.iterator.type.is_array) and
6698                self.target.type.assignable_from(self.iterator.type)):
6699            # C array slice optimization.
6700            pass
6701        else:
6702            self.item = self.item.coerce_to(self.target.type, env)
6703        self.body = self.body.analyse_expressions(env)
6704        if self.else_clause:
6705            self.else_clause = self.else_clause.analyse_expressions(env)
6706        return self
6707
6708    def generate_execution_code(self, code):
6709        code.mark_pos(self.pos)
6710        old_loop_labels = code.new_loop_labels()
6711        self.iterator.generate_evaluation_code(code)
6712        code.putln("for (;;) {")
6713        self.item.generate_evaluation_code(code)
6714        self.target.generate_assignment_code(self.item, code)
6715        self.body.generate_execution_code(code)
6716        code.mark_pos(self.pos)
6717        code.put_label(code.continue_label)
6718        code.putln("}")
6719        break_label = code.break_label
6720        code.set_loop_labels(old_loop_labels)
6721
6722        if self.else_clause:
6723            # in nested loops, the 'else' block can contain a
6724            # 'continue' statement for the outer loop, but we may need
6725            # to generate cleanup code before taking that path, so we
6726            # intercept it here
6727            orig_continue_label = code.continue_label
6728            code.continue_label = code.new_label('outer_continue')
6729
6730            code.putln("/*else*/ {")
6731            self.else_clause.generate_execution_code(code)
6732            code.putln("}")
6733
6734            if code.label_used(code.continue_label):
6735                code.put_goto(break_label)
6736                code.mark_pos(self.pos)
6737                code.put_label(code.continue_label)
6738                self.iterator.generate_disposal_code(code)
6739                code.put_goto(orig_continue_label)
6740            code.set_loop_labels(old_loop_labels)
6741
6742        code.mark_pos(self.pos)
6743        if code.label_used(break_label):
6744            code.put_label(break_label)
6745        self.iterator.generate_disposal_code(code)
6746        self.iterator.free_temps(code)
6747
6748    def generate_function_definitions(self, env, code):
6749        self.target.generate_function_definitions(env, code)
6750        self.iterator.generate_function_definitions(env, code)
6751        self.body.generate_function_definitions(env, code)
6752        if self.else_clause is not None:
6753            self.else_clause.generate_function_definitions(env, code)
6754
6755    def annotate(self, code):
6756        self.target.annotate(code)
6757        self.iterator.annotate(code)
6758        self.body.annotate(code)
6759        if self.else_clause:
6760            self.else_clause.annotate(code)
6761        self.item.annotate(code)
6762
6763
6764class ForInStatNode(_ForInStatNode):
6765    #  'for' statement
6766
6767    is_async = False
6768
6769    def _create_item_node(self):
6770        from .ExprNodes import NextNode
6771        self.item = NextNode(self.iterator)
6772
6773
6774class AsyncForStatNode(_ForInStatNode):
6775    #  'async for' statement
6776    #
6777    #  iterator      AIterAwaitExprNode(AsyncIteratorNode)
6778    #  item          AwaitIterNextExprNode(AsyncIteratorNode)
6779
6780    is_async = True
6781
6782    def __init__(self, pos, **kw):
6783        assert 'item' not in kw
6784        from . import ExprNodes
6785        # AwaitExprNodes must appear before running MarkClosureVisitor
6786        kw['item'] = ExprNodes.AwaitIterNextExprNode(kw['iterator'].pos, arg=None)
6787        _ForInStatNode.__init__(self, pos, **kw)
6788
6789    def _create_item_node(self):
6790        from . import ExprNodes
6791        self.item.arg = ExprNodes.AsyncNextNode(self.iterator)
6792
6793
6794class ForFromStatNode(LoopNode, StatNode):
6795    #  for name from expr rel name rel expr
6796    #
6797    #  target        NameNode
6798    #  bound1        ExprNode
6799    #  relation1     string
6800    #  relation2     string
6801    #  bound2        ExprNode
6802    #  step          ExprNode or None
6803    #  body          StatNode
6804    #  else_clause   StatNode or None
6805    #
6806    #  Used internally:
6807    #
6808    #  from_range         bool
6809    #  is_py_target       bool
6810    #  loopvar_node       ExprNode (usually a NameNode or temp node)
6811    #  py_loopvar_node    PyTempNode or None
6812    child_attrs = ["target", "bound1", "bound2", "step", "body", "else_clause"]
6813
6814    is_py_target = False
6815    loopvar_node = None
6816    py_loopvar_node = None
6817    from_range = False
6818
6819    gil_message = "For-loop using object bounds or target"
6820
6821    def nogil_check(self, env):
6822        for x in (self.target, self.bound1, self.bound2):
6823            if x.type.is_pyobject:
6824                self.gil_error()
6825
6826    def analyse_declarations(self, env):
6827        self.target.analyse_target_declaration(env)
6828        self.body.analyse_declarations(env)
6829        if self.else_clause:
6830            self.else_clause.analyse_declarations(env)
6831
6832    def analyse_expressions(self, env):
6833        from . import ExprNodes
6834        self.target = self.target.analyse_target_types(env)
6835        self.bound1 = self.bound1.analyse_types(env)
6836        self.bound2 = self.bound2.analyse_types(env)
6837        if self.step is not None:
6838            if isinstance(self.step, ExprNodes.UnaryMinusNode):
6839                warning(self.step.pos, "Probable infinite loop in for-from-by statement. "
6840                        "Consider switching the directions of the relations.", 2)
6841            self.step = self.step.analyse_types(env)
6842
6843        self.set_up_loop(env)
6844        target_type = self.target.type
6845        if not (target_type.is_pyobject or target_type.is_numeric):
6846            error(self.target.pos, "for-from loop variable must be c numeric type or Python object")
6847
6848        self.body = self.body.analyse_expressions(env)
6849        if self.else_clause:
6850            self.else_clause = self.else_clause.analyse_expressions(env)
6851        return self
6852
6853    def set_up_loop(self, env):
6854        from . import ExprNodes
6855
6856        target_type = self.target.type
6857        if target_type.is_numeric:
6858            loop_type = target_type
6859        else:
6860            if target_type.is_enum:
6861                warning(self.target.pos,
6862                        "Integer loops over enum values are fragile. Please cast to a safe integer type instead.")
6863            loop_type = PyrexTypes.c_long_type if target_type.is_pyobject else PyrexTypes.c_int_type
6864            if not self.bound1.type.is_pyobject:
6865                loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound1.type)
6866            if not self.bound2.type.is_pyobject:
6867                loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound2.type)
6868            if self.step is not None and not self.step.type.is_pyobject:
6869                loop_type = PyrexTypes.widest_numeric_type(loop_type, self.step.type)
6870        self.bound1 = self.bound1.coerce_to(loop_type, env)
6871        self.bound2 = self.bound2.coerce_to(loop_type, env)
6872        if not self.bound2.is_literal:
6873            self.bound2 = self.bound2.coerce_to_temp(env)
6874        if self.step is not None:
6875            self.step = self.step.coerce_to(loop_type, env)
6876            if not self.step.is_literal:
6877                self.step = self.step.coerce_to_temp(env)
6878
6879        if target_type.is_numeric or target_type.is_enum:
6880            self.is_py_target = False
6881            if isinstance(self.target, ExprNodes.BufferIndexNode):
6882                raise error(self.pos, "Buffer or memoryview slicing/indexing not allowed as for-loop target.")
6883            self.loopvar_node = self.target
6884            self.py_loopvar_node = None
6885        else:
6886            self.is_py_target = True
6887            c_loopvar_node = ExprNodes.TempNode(self.pos, loop_type, env)
6888            self.loopvar_node = c_loopvar_node
6889            self.py_loopvar_node = ExprNodes.CloneNode(c_loopvar_node).coerce_to_pyobject(env)
6890
6891    def generate_execution_code(self, code):
6892        code.mark_pos(self.pos)
6893        old_loop_labels = code.new_loop_labels()
6894        from_range = self.from_range
6895        self.bound1.generate_evaluation_code(code)
6896        self.bound2.generate_evaluation_code(code)
6897        offset, incop = self.relation_table[self.relation1]
6898        if self.step is not None:
6899            self.step.generate_evaluation_code(code)
6900            step = self.step.result()
6901            incop = "%s=%s" % (incop[0], step)  # e.g. '++' => '+= STEP'
6902        else:
6903            step = '1'
6904
6905        from . import ExprNodes
6906        if isinstance(self.loopvar_node, ExprNodes.TempNode):
6907            self.loopvar_node.allocate(code)
6908        if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
6909            self.py_loopvar_node.allocate(code)
6910
6911        loopvar_type = PyrexTypes.c_long_type if self.target.type.is_enum else self.target.type
6912
6913        if from_range and not self.is_py_target:
6914            loopvar_name = code.funcstate.allocate_temp(loopvar_type, False)
6915        else:
6916            loopvar_name = self.loopvar_node.result()
6917        if loopvar_type.is_int and not loopvar_type.signed and self.relation2[0] == '>':
6918            # Handle the case where the endpoint of an unsigned int iteration
6919            # is within step of 0.
6920            code.putln("for (%s = %s%s + %s; %s %s %s + %s; ) { %s%s;" % (
6921                loopvar_name,
6922                self.bound1.result(), offset, step,
6923                loopvar_name, self.relation2, self.bound2.result(), step,
6924                loopvar_name, incop))
6925        else:
6926            code.putln("for (%s = %s%s; %s %s %s; %s%s) {" % (
6927                loopvar_name,
6928                self.bound1.result(), offset,
6929                loopvar_name, self.relation2, self.bound2.result(),
6930                loopvar_name, incop))
6931
6932        coerced_loopvar_node = self.py_loopvar_node
6933        if coerced_loopvar_node is None and from_range:
6934            coerced_loopvar_node = ExprNodes.RawCNameExprNode(self.target.pos, loopvar_type, loopvar_name)
6935        if coerced_loopvar_node is not None:
6936            coerced_loopvar_node.generate_evaluation_code(code)
6937            self.target.generate_assignment_code(coerced_loopvar_node, code)
6938
6939        self.body.generate_execution_code(code)
6940        code.put_label(code.continue_label)
6941
6942        if not from_range and self.py_loopvar_node:
6943            # This mess is to make for..from loops with python targets behave
6944            # exactly like those with C targets with regards to re-assignment
6945            # of the loop variable.
6946            if self.target.entry.is_pyglobal:
6947                # We know target is a NameNode, this is the only ugly case.
6948                target_node = ExprNodes.PyTempNode(self.target.pos, None)
6949                target_node.allocate(code)
6950                interned_cname = code.intern_identifier(self.target.entry.name)
6951                if self.target.entry.scope.is_module_scope:
6952                    code.globalstate.use_utility_code(
6953                        UtilityCode.load_cached("GetModuleGlobalName", "ObjectHandling.c"))
6954                    lookup_func = '__Pyx_GetModuleGlobalName(%s, %s); %s'
6955                else:
6956                    code.globalstate.use_utility_code(
6957                        UtilityCode.load_cached("GetNameInClass", "ObjectHandling.c"))
6958                    lookup_func = '__Pyx_GetNameInClass(%s, {}, %s); %s'.format(
6959                        self.target.entry.scope.namespace_cname)
6960                code.putln(lookup_func % (
6961                    target_node.result(),
6962                    interned_cname,
6963                    code.error_goto_if_null(target_node.result(), self.target.pos)))
6964                code.put_gotref(target_node.result())
6965            else:
6966                target_node = self.target
6967            from_py_node = ExprNodes.CoerceFromPyTypeNode(
6968                self.loopvar_node.type, target_node, self.target.entry.scope)
6969            from_py_node.temp_code = loopvar_name
6970            from_py_node.generate_result_code(code)
6971            if self.target.entry.is_pyglobal:
6972                code.put_decref(target_node.result(), target_node.type)
6973                target_node.release(code)
6974
6975        code.putln("}")
6976
6977        if not from_range and self.py_loopvar_node:
6978            # This is potentially wasteful, but we don't want the semantics to
6979            # depend on whether or not the loop is a python type.
6980            self.py_loopvar_node.generate_evaluation_code(code)
6981            self.target.generate_assignment_code(self.py_loopvar_node, code)
6982        if from_range and not self.is_py_target:
6983            code.funcstate.release_temp(loopvar_name)
6984
6985        break_label = code.break_label
6986        code.set_loop_labels(old_loop_labels)
6987        if self.else_clause:
6988            code.putln("/*else*/ {")
6989            self.else_clause.generate_execution_code(code)
6990            code.putln("}")
6991        code.put_label(break_label)
6992        self.bound1.generate_disposal_code(code)
6993        self.bound1.free_temps(code)
6994        self.bound2.generate_disposal_code(code)
6995        self.bound2.free_temps(code)
6996        if isinstance(self.loopvar_node, ExprNodes.TempNode):
6997            self.loopvar_node.release(code)
6998        if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
6999            self.py_loopvar_node.release(code)
7000        if self.step is not None:
7001            self.step.generate_disposal_code(code)
7002            self.step.free_temps(code)
7003
7004    relation_table = {
7005        # {relop : (initial offset, increment op)}
7006        '<=': ("",   "++"),
7007        '<' : ("+1", "++"),
7008        '>=': ("",   "--"),
7009        '>' : ("-1", "--"),
7010    }
7011
7012    def generate_function_definitions(self, env, code):
7013        self.target.generate_function_definitions(env, code)
7014        self.bound1.generate_function_definitions(env, code)
7015        self.bound2.generate_function_definitions(env, code)
7016        if self.step is not None:
7017            self.step.generate_function_definitions(env, code)
7018        self.body.generate_function_definitions(env, code)
7019        if self.else_clause is not None:
7020            self.else_clause.generate_function_definitions(env, code)
7021
7022    def annotate(self, code):
7023        self.target.annotate(code)
7024        self.bound1.annotate(code)
7025        self.bound2.annotate(code)
7026        if self.step:
7027            self.step.annotate(code)
7028        self.body.annotate(code)
7029        if self.else_clause:
7030            self.else_clause.annotate(code)
7031
7032
7033class WithStatNode(StatNode):
7034    """
7035    Represents a Python with statement.
7036
7037    Implemented by the WithTransform as follows:
7038
7039        MGR = EXPR
7040        EXIT = MGR.__exit__
7041        VALUE = MGR.__enter__()
7042        EXC = True
7043        try:
7044            try:
7045                TARGET = VALUE  # optional
7046                BODY
7047            except:
7048                EXC = False
7049                if not EXIT(*EXCINFO):
7050                    raise
7051        finally:
7052            if EXC:
7053                EXIT(None, None, None)
7054            MGR = EXIT = VALUE = None
7055    """
7056    #  manager          The with statement manager object
7057    #  target           ExprNode  the target lhs of the __enter__() call
7058    #  body             StatNode
7059    #  enter_call       ExprNode  the call to the __enter__() method
7060    #  exit_var         String    the cname of the __exit__() method reference
7061
7062    child_attrs = ["manager", "enter_call", "target", "body"]
7063
7064    enter_call = None
7065    target_temp = None
7066
7067    def analyse_declarations(self, env):
7068        self.manager.analyse_declarations(env)
7069        self.enter_call.analyse_declarations(env)
7070        self.body.analyse_declarations(env)
7071
7072    def analyse_expressions(self, env):
7073        self.manager = self.manager.analyse_types(env)
7074        self.enter_call = self.enter_call.analyse_types(env)
7075        if self.target:
7076            # set up target_temp before descending into body (which uses it)
7077            from .ExprNodes import TempNode
7078            self.target_temp = TempNode(self.enter_call.pos, self.enter_call.type)
7079        self.body = self.body.analyse_expressions(env)
7080        return self
7081
7082    def generate_function_definitions(self, env, code):
7083        self.manager.generate_function_definitions(env, code)
7084        self.enter_call.generate_function_definitions(env, code)
7085        self.body.generate_function_definitions(env, code)
7086
7087    def generate_execution_code(self, code):
7088        code.mark_pos(self.pos)
7089        code.putln("/*with:*/ {")
7090        self.manager.generate_evaluation_code(code)
7091        self.exit_var = code.funcstate.allocate_temp(py_object_type, manage_ref=False)
7092        code.globalstate.use_utility_code(
7093            UtilityCode.load_cached("PyObjectLookupSpecial", "ObjectHandling.c"))
7094        code.putln("%s = __Pyx_PyObject_LookupSpecial(%s, %s); %s" % (
7095            self.exit_var,
7096            self.manager.py_result(),
7097            code.intern_identifier(EncodedString('__aexit__' if self.is_async else '__exit__')),
7098            code.error_goto_if_null(self.exit_var, self.pos),
7099            ))
7100        code.put_gotref(self.exit_var)
7101
7102        # need to free exit_var in the face of exceptions during setup
7103        old_error_label = code.new_error_label()
7104        intermediate_error_label = code.error_label
7105
7106        self.enter_call.generate_evaluation_code(code)
7107        if self.target:
7108            # The temp result will be cleaned up by the WithTargetAssignmentStatNode
7109            # after assigning its result to the target of the 'with' statement.
7110            self.target_temp.allocate(code)
7111            self.enter_call.make_owned_reference(code)
7112            code.putln("%s = %s;" % (self.target_temp.result(), self.enter_call.result()))
7113            self.enter_call.generate_post_assignment_code(code)
7114        else:
7115            self.enter_call.generate_disposal_code(code)
7116        self.enter_call.free_temps(code)
7117
7118        self.manager.generate_disposal_code(code)
7119        self.manager.free_temps(code)
7120
7121        code.error_label = old_error_label
7122        self.body.generate_execution_code(code)
7123
7124        if code.label_used(intermediate_error_label):
7125            step_over_label = code.new_label()
7126            code.put_goto(step_over_label)
7127            code.put_label(intermediate_error_label)
7128            code.put_decref_clear(self.exit_var, py_object_type)
7129            code.put_goto(old_error_label)
7130            code.put_label(step_over_label)
7131
7132        code.funcstate.release_temp(self.exit_var)
7133        code.putln('}')
7134
7135
7136class WithTargetAssignmentStatNode(AssignmentNode):
7137    # The target assignment of the 'with' statement value (return
7138    # value of the __enter__() call).
7139    #
7140    # This is a special cased assignment that properly cleans up the RHS.
7141    #
7142    # lhs       ExprNode      the assignment target
7143    # rhs       ExprNode      a (coerced) TempNode for the rhs (from WithStatNode)
7144    # with_node WithStatNode  the surrounding with-statement
7145
7146    child_attrs = ["rhs", "lhs"]
7147    with_node = None
7148    rhs = None
7149
7150    def analyse_declarations(self, env):
7151        self.lhs.analyse_target_declaration(env)
7152
7153    def analyse_expressions(self, env):
7154        self.lhs = self.lhs.analyse_target_types(env)
7155        self.lhs.gil_assignment_check(env)
7156        self.rhs = self.with_node.target_temp.coerce_to(self.lhs.type, env)
7157        return self
7158
7159    def generate_execution_code(self, code):
7160        self.rhs.generate_evaluation_code(code)
7161        self.lhs.generate_assignment_code(self.rhs, code)
7162        self.with_node.target_temp.release(code)
7163
7164    def annotate(self, code):
7165        self.lhs.annotate(code)
7166        self.rhs.annotate(code)
7167
7168
7169class TryExceptStatNode(StatNode):
7170    #  try .. except statement
7171    #
7172    #  body             StatNode
7173    #  except_clauses   [ExceptClauseNode]
7174    #  else_clause      StatNode or None
7175
7176    child_attrs = ["body", "except_clauses", "else_clause"]
7177    in_generator = False
7178
7179    def analyse_declarations(self, env):
7180        self.body.analyse_declarations(env)
7181        for except_clause in self.except_clauses:
7182            except_clause.analyse_declarations(env)
7183        if self.else_clause:
7184            self.else_clause.analyse_declarations(env)
7185
7186    def analyse_expressions(self, env):
7187        self.body = self.body.analyse_expressions(env)
7188        default_clause_seen = 0
7189        for i, except_clause in enumerate(self.except_clauses):
7190            except_clause = self.except_clauses[i] = except_clause.analyse_expressions(env)
7191            if default_clause_seen:
7192                error(except_clause.pos, "default 'except:' must be last")
7193            if not except_clause.pattern:
7194                default_clause_seen = 1
7195        self.has_default_clause = default_clause_seen
7196        if self.else_clause:
7197            self.else_clause = self.else_clause.analyse_expressions(env)
7198        return self
7199
7200    nogil_check = Node.gil_error
7201    gil_message = "Try-except statement"
7202
7203    def generate_execution_code(self, code):
7204        code.mark_pos(self.pos)  # before changing the error label, in case of tracing errors
7205        code.putln("{")
7206
7207        old_return_label = code.return_label
7208        old_break_label = code.break_label
7209        old_continue_label = code.continue_label
7210        old_error_label = code.new_error_label()
7211        our_error_label = code.error_label
7212        except_end_label = code.new_label('exception_handled')
7213        except_error_label = code.new_label('except_error')
7214        except_return_label = code.new_label('except_return')
7215        try_return_label = code.new_label('try_return')
7216        try_break_label = code.new_label('try_break') if old_break_label else None
7217        try_continue_label = code.new_label('try_continue') if old_continue_label else None
7218        try_end_label = code.new_label('try_end')
7219
7220        exc_save_vars = [code.funcstate.allocate_temp(py_object_type, False)
7221                         for _ in range(3)]
7222        save_exc = code.insertion_point()
7223        code.putln(
7224            "/*try:*/ {")
7225        code.return_label = try_return_label
7226        code.break_label = try_break_label
7227        code.continue_label = try_continue_label
7228        self.body.generate_execution_code(code)
7229        code.mark_pos(self.pos, trace=False)
7230        code.putln(
7231            "}")
7232        temps_to_clean_up = code.funcstate.all_free_managed_temps()
7233        can_raise = code.label_used(our_error_label)
7234
7235        if can_raise:
7236            # inject code before the try block to save away the exception state
7237            code.globalstate.use_utility_code(reset_exception_utility_code)
7238            if not self.in_generator:
7239                save_exc.putln("__Pyx_PyThreadState_declare")
7240                save_exc.putln("__Pyx_PyThreadState_assign")
7241            save_exc.putln("__Pyx_ExceptionSave(%s);" % (
7242                ', '.join(['&%s' % var for var in exc_save_vars])))
7243            for var in exc_save_vars:
7244                save_exc.put_xgotref(var)
7245
7246            def restore_saved_exception():
7247                for name in exc_save_vars:
7248                    code.put_xgiveref(name)
7249                code.putln("__Pyx_ExceptionReset(%s);" %
7250                           ', '.join(exc_save_vars))
7251        else:
7252            # try block cannot raise exceptions, but we had to allocate the temps above,
7253            # so just keep the C compiler from complaining about them being unused
7254            mark_vars_used =  ["(void)%s;" % var for var in exc_save_vars]
7255            save_exc.putln("%s /* mark used */" % ' '.join(mark_vars_used))
7256
7257            def restore_saved_exception():
7258                pass
7259
7260        code.error_label = except_error_label
7261        code.return_label = except_return_label
7262        normal_case_terminates = self.body.is_terminator
7263        if self.else_clause:
7264            code.mark_pos(self.else_clause.pos)
7265            code.putln(
7266                "/*else:*/ {")
7267            self.else_clause.generate_execution_code(code)
7268            code.putln(
7269                "}")
7270            if not normal_case_terminates:
7271                normal_case_terminates = self.else_clause.is_terminator
7272
7273        if can_raise:
7274            if not normal_case_terminates:
7275                for var in exc_save_vars:
7276                    code.put_xdecref_clear(var, py_object_type)
7277                code.put_goto(try_end_label)
7278            code.put_label(our_error_label)
7279            for temp_name, temp_type in temps_to_clean_up:
7280                code.put_xdecref_clear(temp_name, temp_type)
7281
7282            outer_except = code.funcstate.current_except
7283            # Currently points to self, but the ExceptClauseNode would also be ok. Change if needed.
7284            code.funcstate.current_except = self
7285            for except_clause in self.except_clauses:
7286                except_clause.generate_handling_code(code, except_end_label)
7287            code.funcstate.current_except = outer_except
7288
7289            if not self.has_default_clause:
7290                code.put_goto(except_error_label)
7291
7292        for exit_label, old_label in [(except_error_label, old_error_label),
7293                                      (try_break_label, old_break_label),
7294                                      (try_continue_label, old_continue_label),
7295                                      (try_return_label, old_return_label),
7296                                      (except_return_label, old_return_label)]:
7297            if code.label_used(exit_label):
7298                if not normal_case_terminates and not code.label_used(try_end_label):
7299                    code.put_goto(try_end_label)
7300                code.put_label(exit_label)
7301                code.mark_pos(self.pos, trace=False)
7302                if can_raise:
7303                    restore_saved_exception()
7304                code.put_goto(old_label)
7305
7306        if code.label_used(except_end_label):
7307            if not normal_case_terminates and not code.label_used(try_end_label):
7308                code.put_goto(try_end_label)
7309            code.put_label(except_end_label)
7310            if can_raise:
7311                restore_saved_exception()
7312        if code.label_used(try_end_label):
7313            code.put_label(try_end_label)
7314        code.putln("}")
7315
7316        for cname in exc_save_vars:
7317            code.funcstate.release_temp(cname)
7318
7319        code.return_label = old_return_label
7320        code.break_label = old_break_label
7321        code.continue_label = old_continue_label
7322        code.error_label = old_error_label
7323
7324    def generate_function_definitions(self, env, code):
7325        self.body.generate_function_definitions(env, code)
7326        for except_clause in self.except_clauses:
7327            except_clause.generate_function_definitions(env, code)
7328        if self.else_clause is not None:
7329            self.else_clause.generate_function_definitions(env, code)
7330
7331    def annotate(self, code):
7332        self.body.annotate(code)
7333        for except_node in self.except_clauses:
7334            except_node.annotate(code)
7335        if self.else_clause:
7336            self.else_clause.annotate(code)
7337
7338
7339class ExceptClauseNode(Node):
7340    #  Part of try ... except statement.
7341    #
7342    #  pattern        [ExprNode]
7343    #  target         ExprNode or None
7344    #  body           StatNode
7345    #  excinfo_target TupleNode(3*ResultRefNode) or None   optional target for exception info (not owned here!)
7346    #  match_flag     string             result of exception match
7347    #  exc_value      ExcValueNode       used internally
7348    #  function_name  string             qualified name of enclosing function
7349    #  exc_vars       (string * 3)       local exception variables
7350    #  is_except_as   bool               Py3-style "except ... as xyz"
7351
7352    # excinfo_target is never set by the parser, but can be set by a transform
7353    # in order to extract more extensive information about the exception as a
7354    # sys.exc_info()-style tuple into a target variable
7355
7356    child_attrs = ["pattern", "target", "body", "exc_value"]
7357
7358    exc_value = None
7359    excinfo_target = None
7360    is_except_as = False
7361
7362    def analyse_declarations(self, env):
7363        if self.target:
7364            self.target.analyse_target_declaration(env)
7365        self.body.analyse_declarations(env)
7366
7367    def analyse_expressions(self, env):
7368        self.function_name = env.qualified_name
7369        if self.pattern:
7370            # normalise/unpack self.pattern into a list
7371            for i, pattern in enumerate(self.pattern):
7372                pattern = pattern.analyse_expressions(env)
7373                self.pattern[i] = pattern.coerce_to_pyobject(env)
7374
7375        if self.target:
7376            from . import ExprNodes
7377            self.exc_value = ExprNodes.ExcValueNode(self.pos)
7378            self.target = self.target.analyse_target_expression(env, self.exc_value)
7379
7380        self.body = self.body.analyse_expressions(env)
7381        return self
7382
7383    def generate_handling_code(self, code, end_label):
7384        code.mark_pos(self.pos)
7385
7386        if self.pattern:
7387            has_non_literals = not all(
7388                pattern.is_literal or pattern.is_simple() and not pattern.is_temp
7389                for pattern in self.pattern)
7390
7391            if has_non_literals:
7392                # For non-trivial exception check expressions, hide the live exception from C-API calls.
7393                exc_vars = [code.funcstate.allocate_temp(py_object_type, manage_ref=True)
7394                            for _ in range(3)]
7395                code.globalstate.use_utility_code(UtilityCode.load_cached("PyErrFetchRestore", "Exceptions.c"))
7396                code.putln("__Pyx_ErrFetch(&%s, &%s, &%s);" % tuple(exc_vars))
7397                code.globalstate.use_utility_code(UtilityCode.load_cached("FastTypeChecks", "ModuleSetupCode.c"))
7398                exc_test_func = "__Pyx_PyErr_GivenExceptionMatches(%s, %%s)" % exc_vars[0]
7399            else:
7400                exc_vars = ()
7401                code.globalstate.use_utility_code(UtilityCode.load_cached("PyErrExceptionMatches", "Exceptions.c"))
7402                exc_test_func = "__Pyx_PyErr_ExceptionMatches(%s)"
7403
7404            exc_tests = []
7405            for pattern in self.pattern:
7406                pattern.generate_evaluation_code(code)
7407                exc_tests.append(exc_test_func % pattern.py_result())
7408
7409            match_flag = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
7410            code.putln("%s = %s;" % (match_flag, ' || '.join(exc_tests)))
7411            for pattern in self.pattern:
7412                pattern.generate_disposal_code(code)
7413                pattern.free_temps(code)
7414
7415            if has_non_literals:
7416                code.putln("__Pyx_ErrRestore(%s, %s, %s);" % tuple(exc_vars))
7417                code.putln(' '.join(["%s = 0;" % var for var in exc_vars]))
7418                for temp in exc_vars:
7419                    code.funcstate.release_temp(temp)
7420
7421            code.putln(
7422                "if (%s) {" %
7423                    match_flag)
7424            code.funcstate.release_temp(match_flag)
7425        else:
7426            code.putln("/*except:*/ {")
7427
7428        if (not getattr(self.body, 'stats', True)
7429                and self.excinfo_target is None
7430                and self.target is None):
7431            # most simple case: no exception variable, empty body (pass)
7432            # => reset the exception state, done
7433            code.globalstate.use_utility_code(UtilityCode.load_cached("PyErrFetchRestore", "Exceptions.c"))
7434            code.putln("__Pyx_ErrRestore(0,0,0);")
7435            code.put_goto(end_label)
7436            code.putln("}")
7437            return
7438
7439        exc_vars = [code.funcstate.allocate_temp(py_object_type, manage_ref=True)
7440                    for _ in range(3)]
7441        code.put_add_traceback(self.function_name)
7442        # We always have to fetch the exception value even if
7443        # there is no target, because this also normalises the
7444        # exception and stores it in the thread state.
7445        code.globalstate.use_utility_code(get_exception_utility_code)
7446        exc_args = "&%s, &%s, &%s" % tuple(exc_vars)
7447        code.putln("if (__Pyx_GetException(%s) < 0) %s" % (
7448            exc_args, code.error_goto(self.pos)))
7449        for var in exc_vars:
7450            code.put_gotref(var)
7451        if self.target:
7452            self.exc_value.set_var(exc_vars[1])
7453            self.exc_value.generate_evaluation_code(code)
7454            self.target.generate_assignment_code(self.exc_value, code)
7455        if self.excinfo_target is not None:
7456            for tempvar, node in zip(exc_vars, self.excinfo_target.args):
7457                node.set_var(tempvar)
7458
7459        old_break_label, old_continue_label = code.break_label, code.continue_label
7460        code.break_label = code.new_label('except_break')
7461        code.continue_label = code.new_label('except_continue')
7462
7463        old_exc_vars = code.funcstate.exc_vars
7464        code.funcstate.exc_vars = exc_vars
7465        self.body.generate_execution_code(code)
7466        code.funcstate.exc_vars = old_exc_vars
7467
7468        if not self.body.is_terminator:
7469            for var in exc_vars:
7470                # FIXME: XDECREF() is needed to allow re-raising (which clears the exc_vars),
7471                # but I don't think it's the right solution.
7472                code.put_xdecref_clear(var, py_object_type)
7473            code.put_goto(end_label)
7474
7475        for new_label, old_label in [(code.break_label, old_break_label),
7476                                     (code.continue_label, old_continue_label)]:
7477            if code.label_used(new_label):
7478                code.put_label(new_label)
7479                for var in exc_vars:
7480                    code.put_decref_clear(var, py_object_type)
7481                code.put_goto(old_label)
7482        code.break_label = old_break_label
7483        code.continue_label = old_continue_label
7484
7485        for temp in exc_vars:
7486            code.funcstate.release_temp(temp)
7487
7488        code.putln(
7489            "}")
7490
7491    def generate_function_definitions(self, env, code):
7492        if self.target is not None:
7493            self.target.generate_function_definitions(env, code)
7494        self.body.generate_function_definitions(env, code)
7495
7496    def annotate(self, code):
7497        if self.pattern:
7498            for pattern in self.pattern:
7499                pattern.annotate(code)
7500        if self.target:
7501            self.target.annotate(code)
7502        self.body.annotate(code)
7503
7504
7505class TryFinallyStatNode(StatNode):
7506    #  try ... finally statement
7507    #
7508    #  body             StatNode
7509    #  finally_clause   StatNode
7510    #  finally_except_clause  deep-copy of finally_clause for exception case
7511    #  in_generator     inside of generator => must store away current exception also in return case
7512    #
7513    #  Each of the continue, break, return and error gotos runs
7514    #  into its own deep-copy of the finally block code.
7515    #  In addition, if we're doing an error, we save the
7516    #  exception on entry to the finally block and restore
7517    #  it on exit.
7518
7519    child_attrs = ["body", "finally_clause", "finally_except_clause"]
7520
7521    preserve_exception = 1
7522
7523    # handle exception case, in addition to return/break/continue
7524    handle_error_case = True
7525    func_return_type = None
7526    finally_except_clause = None
7527
7528    is_try_finally_in_nogil = False
7529    in_generator = False
7530
7531    @staticmethod
7532    def create_analysed(pos, env, body, finally_clause):
7533        node = TryFinallyStatNode(pos, body=body, finally_clause=finally_clause)
7534        return node
7535
7536    def analyse_declarations(self, env):
7537        self.body.analyse_declarations(env)
7538        self.finally_except_clause = copy.deepcopy(self.finally_clause)
7539        self.finally_except_clause.analyse_declarations(env)
7540        self.finally_clause.analyse_declarations(env)
7541
7542    def analyse_expressions(self, env):
7543        self.body = self.body.analyse_expressions(env)
7544        self.finally_clause = self.finally_clause.analyse_expressions(env)
7545        self.finally_except_clause = self.finally_except_clause.analyse_expressions(env)
7546        if env.return_type and not env.return_type.is_void:
7547            self.func_return_type = env.return_type
7548        return self
7549
7550    nogil_check = Node.gil_error
7551    gil_message = "Try-finally statement"
7552
7553    def generate_execution_code(self, code):
7554        code.mark_pos(self.pos)  # before changing the error label, in case of tracing errors
7555        code.putln("/*try:*/ {")
7556
7557        old_error_label = code.error_label
7558        old_labels = code.all_new_labels()
7559        new_labels = code.get_all_labels()
7560        new_error_label = code.error_label
7561        if not self.handle_error_case:
7562            code.error_label = old_error_label
7563        catch_label = code.new_label()
7564
7565        was_in_try_finally = code.funcstate.in_try_finally
7566        code.funcstate.in_try_finally = 1
7567
7568        self.body.generate_execution_code(code)
7569
7570        code.funcstate.in_try_finally = was_in_try_finally
7571        code.putln("}")
7572
7573        temps_to_clean_up = code.funcstate.all_free_managed_temps()
7574        code.mark_pos(self.finally_clause.pos)
7575        code.putln("/*finally:*/ {")
7576
7577        # Reset labels only after writing out a potential line trace call for correct nogil error handling.
7578        code.set_all_labels(old_labels)
7579
7580        def fresh_finally_clause(_next=[self.finally_clause]):
7581            # generate the original subtree once and always keep a fresh copy
7582            node = _next[0]
7583            node_copy = copy.deepcopy(node)
7584            if node is self.finally_clause:
7585                _next[0] = node_copy
7586            else:
7587                node = node_copy
7588            return node
7589
7590        preserve_error = self.preserve_exception and code.label_used(new_error_label)
7591        needs_success_cleanup = not self.finally_clause.is_terminator
7592
7593        if not self.body.is_terminator:
7594            code.putln('/*normal exit:*/{')
7595            fresh_finally_clause().generate_execution_code(code)
7596            if not self.finally_clause.is_terminator:
7597                code.put_goto(catch_label)
7598            code.putln('}')
7599
7600        if preserve_error:
7601            code.put_label(new_error_label)
7602            code.putln('/*exception exit:*/{')
7603            if not self.in_generator:
7604                code.putln("__Pyx_PyThreadState_declare")
7605            if self.is_try_finally_in_nogil:
7606                code.declare_gilstate()
7607            if needs_success_cleanup:
7608                exc_lineno_cnames = tuple([
7609                    code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
7610                    for _ in range(2)])
7611                exc_filename_cname = code.funcstate.allocate_temp(
7612                    PyrexTypes.CPtrType(PyrexTypes.c_const_type(PyrexTypes.c_char_type)),
7613                    manage_ref=False)
7614            else:
7615                exc_lineno_cnames = exc_filename_cname = None
7616            exc_vars = tuple([
7617                code.funcstate.allocate_temp(py_object_type, manage_ref=False)
7618                for _ in range(6)])
7619            self.put_error_catcher(
7620                code, temps_to_clean_up, exc_vars, exc_lineno_cnames, exc_filename_cname)
7621            finally_old_labels = code.all_new_labels()
7622
7623            code.putln('{')
7624            old_exc_vars = code.funcstate.exc_vars
7625            code.funcstate.exc_vars = exc_vars[:3]
7626            self.finally_except_clause.generate_execution_code(code)
7627            code.funcstate.exc_vars = old_exc_vars
7628            code.putln('}')
7629
7630            if needs_success_cleanup:
7631                self.put_error_uncatcher(code, exc_vars, exc_lineno_cnames, exc_filename_cname)
7632                if exc_lineno_cnames:
7633                    for cname in exc_lineno_cnames:
7634                        code.funcstate.release_temp(cname)
7635                if exc_filename_cname:
7636                    code.funcstate.release_temp(exc_filename_cname)
7637                code.put_goto(old_error_label)
7638
7639            for new_label, old_label in zip(code.get_all_labels(), finally_old_labels):
7640                if not code.label_used(new_label):
7641                    continue
7642                code.put_label(new_label)
7643                self.put_error_cleaner(code, exc_vars)
7644                code.put_goto(old_label)
7645
7646            for cname in exc_vars:
7647                code.funcstate.release_temp(cname)
7648            code.putln('}')
7649
7650        code.set_all_labels(old_labels)
7651        return_label = code.return_label
7652        exc_vars = ()
7653
7654        for i, (new_label, old_label) in enumerate(zip(new_labels, old_labels)):
7655            if not code.label_used(new_label):
7656                continue
7657            if new_label == new_error_label and preserve_error:
7658                continue  # handled above
7659
7660            code.putln('%s: {' % new_label)
7661            ret_temp = None
7662            if old_label == return_label:
7663                # return actually raises an (uncatchable) exception in generators that we must preserve
7664                if self.in_generator:
7665                    exc_vars = tuple([
7666                        code.funcstate.allocate_temp(py_object_type, manage_ref=False)
7667                        for _ in range(6)])
7668                    self.put_error_catcher(code, [], exc_vars)
7669                if not self.finally_clause.is_terminator:
7670                    # store away return value for later reuse
7671                    if (self.func_return_type and
7672                            not self.is_try_finally_in_nogil and
7673                            not isinstance(self.finally_clause, GILExitNode)):
7674                        ret_temp = code.funcstate.allocate_temp(
7675                            self.func_return_type, manage_ref=False)
7676                        code.putln("%s = %s;" % (ret_temp, Naming.retval_cname))
7677                        if self.func_return_type.is_pyobject:
7678                            code.putln("%s = 0;" % Naming.retval_cname)
7679
7680            fresh_finally_clause().generate_execution_code(code)
7681
7682            if old_label == return_label:
7683                if ret_temp:
7684                    code.putln("%s = %s;" % (Naming.retval_cname, ret_temp))
7685                    if self.func_return_type.is_pyobject:
7686                        code.putln("%s = 0;" % ret_temp)
7687                    code.funcstate.release_temp(ret_temp)
7688                if self.in_generator:
7689                    self.put_error_uncatcher(code, exc_vars)
7690                    for cname in exc_vars:
7691                        code.funcstate.release_temp(cname)
7692
7693            if not self.finally_clause.is_terminator:
7694                code.put_goto(old_label)
7695            code.putln('}')
7696
7697        # End finally
7698        code.put_label(catch_label)
7699        code.putln(
7700            "}")
7701
7702    def generate_function_definitions(self, env, code):
7703        self.body.generate_function_definitions(env, code)
7704        self.finally_clause.generate_function_definitions(env, code)
7705
7706    def put_error_catcher(self, code, temps_to_clean_up, exc_vars,
7707                          exc_lineno_cnames=None, exc_filename_cname=None):
7708        code.globalstate.use_utility_code(restore_exception_utility_code)
7709        code.globalstate.use_utility_code(get_exception_utility_code)
7710        code.globalstate.use_utility_code(swap_exception_utility_code)
7711
7712        if self.is_try_finally_in_nogil:
7713            code.put_ensure_gil(declare_gilstate=False)
7714        code.putln("__Pyx_PyThreadState_assign")
7715
7716        code.putln(' '.join(["%s = 0;" % var for var in exc_vars]))
7717        for temp_name, type in temps_to_clean_up:
7718            code.put_xdecref_clear(temp_name, type)
7719
7720        # not using preprocessor here to avoid warnings about
7721        # unused utility functions and/or temps
7722        code.putln("if (PY_MAJOR_VERSION >= 3)"
7723                   " __Pyx_ExceptionSwap(&%s, &%s, &%s);" % exc_vars[3:])
7724        code.putln("if ((PY_MAJOR_VERSION < 3) ||"
7725                   # if __Pyx_GetException() fails in Py3,
7726                   # store the newly raised exception instead
7727                   " unlikely(__Pyx_GetException(&%s, &%s, &%s) < 0)) "
7728                   "__Pyx_ErrFetch(&%s, &%s, &%s);" % (exc_vars[:3] * 2))
7729        for var in exc_vars:
7730            code.put_xgotref(var)
7731        if exc_lineno_cnames:
7732            code.putln("%s = %s; %s = %s; %s = %s;" % (
7733                exc_lineno_cnames[0], Naming.lineno_cname,
7734                exc_lineno_cnames[1], Naming.clineno_cname,
7735                exc_filename_cname, Naming.filename_cname))
7736
7737        if self.is_try_finally_in_nogil:
7738            code.put_release_ensured_gil()
7739
7740    def put_error_uncatcher(self, code, exc_vars, exc_lineno_cnames=None, exc_filename_cname=None):
7741        code.globalstate.use_utility_code(restore_exception_utility_code)
7742        code.globalstate.use_utility_code(reset_exception_utility_code)
7743
7744        if self.is_try_finally_in_nogil:
7745            code.put_ensure_gil(declare_gilstate=False)
7746
7747        # not using preprocessor here to avoid warnings about
7748        # unused utility functions and/or temps
7749        code.putln("if (PY_MAJOR_VERSION >= 3) {")
7750        for var in exc_vars[3:]:
7751            code.put_xgiveref(var)
7752        code.putln("__Pyx_ExceptionReset(%s, %s, %s);" % exc_vars[3:])
7753        code.putln("}")
7754        for var in exc_vars[:3]:
7755            code.put_xgiveref(var)
7756        code.putln("__Pyx_ErrRestore(%s, %s, %s);" % exc_vars[:3])
7757
7758        if self.is_try_finally_in_nogil:
7759            code.put_release_ensured_gil()
7760
7761        code.putln(' '.join(["%s = 0;" % var for var in exc_vars]))
7762        if exc_lineno_cnames:
7763            code.putln("%s = %s; %s = %s; %s = %s;" % (
7764                Naming.lineno_cname, exc_lineno_cnames[0],
7765                Naming.clineno_cname, exc_lineno_cnames[1],
7766                Naming.filename_cname, exc_filename_cname))
7767
7768    def put_error_cleaner(self, code, exc_vars):
7769        code.globalstate.use_utility_code(reset_exception_utility_code)
7770        if self.is_try_finally_in_nogil:
7771            code.put_ensure_gil(declare_gilstate=False)
7772
7773        # not using preprocessor here to avoid warnings about
7774        # unused utility functions and/or temps
7775        code.putln("if (PY_MAJOR_VERSION >= 3) {")
7776        for var in exc_vars[3:]:
7777            code.put_xgiveref(var)
7778        code.putln("__Pyx_ExceptionReset(%s, %s, %s);" % exc_vars[3:])
7779        code.putln("}")
7780        for var in exc_vars[:3]:
7781            code.put_xdecref_clear(var, py_object_type)
7782        if self.is_try_finally_in_nogil:
7783            code.put_release_ensured_gil()
7784        code.putln(' '.join(["%s = 0;"]*3) % exc_vars[3:])
7785
7786    def annotate(self, code):
7787        self.body.annotate(code)
7788        self.finally_clause.annotate(code)
7789
7790
7791class NogilTryFinallyStatNode(TryFinallyStatNode):
7792    """
7793    A try/finally statement that may be used in nogil code sections.
7794    """
7795
7796    preserve_exception = False
7797    nogil_check = None
7798
7799
7800class GILStatNode(NogilTryFinallyStatNode):
7801    #  'with gil' or 'with nogil' statement
7802    #
7803    #   state   string   'gil' or 'nogil'
7804
7805    state_temp = None
7806
7807    def __init__(self, pos, state, body):
7808        self.state = state
7809        self.create_state_temp_if_needed(pos, state, body)
7810        TryFinallyStatNode.__init__(
7811            self, pos,
7812            body=body,
7813            finally_clause=GILExitNode(
7814                pos, state=state, state_temp=self.state_temp))
7815
7816    def create_state_temp_if_needed(self, pos, state, body):
7817        from .ParseTreeTransforms import YieldNodeCollector
7818        collector = YieldNodeCollector()
7819        collector.visitchildren(body)
7820        if not collector.yields:
7821            return
7822
7823        if state == 'gil':
7824            temp_type = PyrexTypes.c_gilstate_type
7825        else:
7826            temp_type = PyrexTypes.c_threadstate_ptr_type
7827        from . import ExprNodes
7828        self.state_temp = ExprNodes.TempNode(pos, temp_type)
7829
7830    def analyse_declarations(self, env):
7831        env._in_with_gil_block = (self.state == 'gil')
7832        if self.state == 'gil':
7833            env.has_with_gil_block = True
7834
7835        return super(GILStatNode, self).analyse_declarations(env)
7836
7837    def analyse_expressions(self, env):
7838        env.use_utility_code(
7839            UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
7840        was_nogil = env.nogil
7841        env.nogil = self.state == 'nogil'
7842        node = TryFinallyStatNode.analyse_expressions(self, env)
7843        env.nogil = was_nogil
7844        return node
7845
7846    def generate_execution_code(self, code):
7847        code.mark_pos(self.pos)
7848        code.begin_block()
7849        if self.state_temp:
7850            self.state_temp.allocate(code)
7851            variable = self.state_temp.result()
7852        else:
7853            variable = None
7854
7855        old_gil_config = code.funcstate.gil_owned
7856        if self.state == 'gil':
7857            code.put_ensure_gil(variable=variable)
7858            code.funcstate.gil_owned = True
7859        else:
7860            code.put_release_gil(variable=variable)
7861            code.funcstate.gil_owned = False
7862
7863        TryFinallyStatNode.generate_execution_code(self, code)
7864
7865        if self.state_temp:
7866            self.state_temp.release(code)
7867
7868        code.funcstate.gil_owned = old_gil_config
7869        code.end_block()
7870
7871
7872class GILExitNode(StatNode):
7873    """
7874    Used as the 'finally' block in a GILStatNode
7875
7876    state   string   'gil' or 'nogil'
7877    """
7878
7879    child_attrs = []
7880    state_temp = None
7881
7882    def analyse_expressions(self, env):
7883        return self
7884
7885    def generate_execution_code(self, code):
7886        if self.state_temp:
7887            variable = self.state_temp.result()
7888        else:
7889            variable = None
7890
7891        if self.state == 'gil':
7892            code.put_release_ensured_gil(variable)
7893        else:
7894            code.put_acquire_gil(variable)
7895
7896
7897class EnsureGILNode(GILExitNode):
7898    """
7899    Ensure the GIL in nogil functions for cleanup before returning.
7900    """
7901
7902    def generate_execution_code(self, code):
7903        code.put_ensure_gil(declare_gilstate=False)
7904
7905
7906def cython_view_utility_code():
7907    from . import MemoryView
7908    return MemoryView.view_utility_code
7909
7910
7911utility_code_for_cimports = {
7912    # utility code (or inlining c) in a pxd (or pyx) file.
7913    # TODO: Consider a generic user-level mechanism for importing
7914    'cpython.array'         : lambda : UtilityCode.load_cached("ArrayAPI", "arrayarray.h"),
7915    'cpython.array.array'   : lambda : UtilityCode.load_cached("ArrayAPI", "arrayarray.h"),
7916    'cython.view'           : cython_view_utility_code,
7917}
7918
7919utility_code_for_imports = {
7920    # utility code used when special modules are imported.
7921    # TODO: Consider a generic user-level mechanism for importing
7922    'asyncio': ("__Pyx_patch_asyncio", "PatchAsyncIO", "Coroutine.c"),
7923    'inspect': ("__Pyx_patch_inspect", "PatchInspect", "Coroutine.c"),
7924}
7925
7926
7927class CImportStatNode(StatNode):
7928    #  cimport statement
7929    #
7930    #  module_name   string           Qualified name of module being imported
7931    #  as_name       string or None   Name specified in "as" clause, if any
7932    #  is_absolute   bool             True for absolute imports, False otherwise
7933
7934    child_attrs = []
7935    is_absolute = False
7936
7937    def analyse_declarations(self, env):
7938        if not env.is_module_scope:
7939            error(self.pos, "cimport only allowed at module level")
7940            return
7941        module_scope = env.find_module(
7942            self.module_name, self.pos, relative_level=0 if self.is_absolute else -1)
7943        if "." in self.module_name:
7944            names = [EncodedString(name) for name in self.module_name.split(".")]
7945            top_name = names[0]
7946            top_module_scope = env.context.find_submodule(top_name)
7947            module_scope = top_module_scope
7948            for name in names[1:]:
7949                submodule_scope = module_scope.find_submodule(name)
7950                module_scope.declare_module(name, submodule_scope, self.pos)
7951                module_scope = submodule_scope
7952            if self.as_name:
7953                env.declare_module(self.as_name, module_scope, self.pos)
7954            else:
7955                env.add_imported_module(module_scope)
7956                env.declare_module(top_name, top_module_scope, self.pos)
7957        else:
7958            name = self.as_name or self.module_name
7959            env.declare_module(name, module_scope, self.pos)
7960        if self.module_name in utility_code_for_cimports:
7961            env.use_utility_code(utility_code_for_cimports[self.module_name]())
7962
7963    def analyse_expressions(self, env):
7964        return self
7965
7966    def generate_execution_code(self, code):
7967        pass
7968
7969
7970class FromCImportStatNode(StatNode):
7971    #  from ... cimport statement
7972    #
7973    #  module_name     string                        Qualified name of module
7974    #  relative_level  int or None                   Relative import: number of dots before module_name
7975    #  imported_names  [(pos, name, as_name, kind)]  Names to be imported
7976
7977    child_attrs = []
7978    module_name = None
7979    relative_level = None
7980    imported_names = None
7981
7982    def analyse_declarations(self, env):
7983        if not env.is_module_scope:
7984            error(self.pos, "cimport only allowed at module level")
7985            return
7986        if self.relative_level and self.relative_level > env.qualified_name.count('.'):
7987            error(self.pos, "relative cimport beyond main package is not allowed")
7988            return
7989        module_scope = env.find_module(self.module_name, self.pos, relative_level=self.relative_level)
7990        module_name = module_scope.qualified_name
7991        env.add_imported_module(module_scope)
7992        for pos, name, as_name, kind in self.imported_names:
7993            if name == "*":
7994                for local_name, entry in list(module_scope.entries.items()):
7995                    env.add_imported_entry(local_name, entry, pos)
7996            else:
7997                entry = module_scope.lookup(name)
7998                if entry:
7999                    if kind and not self.declaration_matches(entry, kind):
8000                        entry.redeclared(pos)
8001                    entry.used = 1
8002                else:
8003                    if kind == 'struct' or kind == 'union':
8004                        entry = module_scope.declare_struct_or_union(
8005                            name, kind=kind, scope=None, typedef_flag=0, pos=pos)
8006                    elif kind == 'class':
8007                        entry = module_scope.declare_c_class(name, pos=pos, module_name=module_name)
8008                    else:
8009                        submodule_scope = env.context.find_module(
8010                            name, relative_to=module_scope, pos=self.pos, absolute_fallback=False)
8011                        if submodule_scope.parent_module is module_scope:
8012                            env.declare_module(as_name or name, submodule_scope, self.pos)
8013                        else:
8014                            error(pos, "Name '%s' not declared in module '%s'" % (name, module_name))
8015
8016                if entry:
8017                    local_name = as_name or name
8018                    env.add_imported_entry(local_name, entry, pos)
8019
8020        if module_name.startswith('cpython') or module_name.startswith('cython'): # enough for now
8021            if module_name in utility_code_for_cimports:
8022                env.use_utility_code(utility_code_for_cimports[module_name]())
8023            for _, name, _, _ in self.imported_names:
8024                fqname = '%s.%s' % (module_name, name)
8025                if fqname in utility_code_for_cimports:
8026                    env.use_utility_code(utility_code_for_cimports[fqname]())
8027
8028    def declaration_matches(self, entry, kind):
8029        if not entry.is_type:
8030            return 0
8031        type = entry.type
8032        if kind == 'class':
8033            if not type.is_extension_type:
8034                return 0
8035        else:
8036            if not type.is_struct_or_union:
8037                return 0
8038            if kind != type.kind:
8039                return 0
8040        return 1
8041
8042    def analyse_expressions(self, env):
8043        return self
8044
8045    def generate_execution_code(self, code):
8046        pass
8047
8048
8049class FromImportStatNode(StatNode):
8050    #  from ... import statement
8051    #
8052    #  module           ImportNode
8053    #  items            [(string, NameNode)]
8054    #  interned_items   [(string, NameNode, ExprNode)]
8055    #  item             PyTempNode            used internally
8056    #  import_star      boolean               used internally
8057
8058    child_attrs = ["module"]
8059    import_star = 0
8060
8061    def analyse_declarations(self, env):
8062        for name, target in self.items:
8063            if name == "*":
8064                if not env.is_module_scope:
8065                    error(self.pos, "import * only allowed at module level")
8066                    return
8067                env.has_import_star = 1
8068                self.import_star = 1
8069            else:
8070                target.analyse_target_declaration(env)
8071
8072    def analyse_expressions(self, env):
8073        from . import ExprNodes
8074        self.module = self.module.analyse_expressions(env)
8075        self.item = ExprNodes.RawCNameExprNode(self.pos, py_object_type)
8076        self.interned_items = []
8077        for name, target in self.items:
8078            if name == '*':
8079                for _, entry in env.entries.items():
8080                    if not entry.is_type and entry.type.is_extension_type:
8081                        env.use_utility_code(UtilityCode.load_cached("ExtTypeTest", "ObjectHandling.c"))
8082                        break
8083            else:
8084                entry = env.lookup(target.name)
8085                # check whether or not entry is already cimported
8086                if (entry.is_type and entry.type.name == name
8087                        and hasattr(entry.type, 'module_name')):
8088                    if entry.type.module_name == self.module.module_name.value:
8089                        # cimported with absolute name
8090                        continue
8091                    try:
8092                        # cimported with relative name
8093                        module = env.find_module(self.module.module_name.value, pos=self.pos,
8094                                                 relative_level=self.module.level)
8095                        if entry.type.module_name == module.qualified_name:
8096                            continue
8097                    except AttributeError:
8098                        pass
8099                target = target.analyse_target_expression(env, None)  # FIXME?
8100                if target.type is py_object_type:
8101                    coerced_item = None
8102                else:
8103                    coerced_item = self.item.coerce_to(target.type, env)
8104                self.interned_items.append((name, target, coerced_item))
8105        return self
8106
8107    def generate_execution_code(self, code):
8108        code.mark_pos(self.pos)
8109        self.module.generate_evaluation_code(code)
8110        if self.import_star:
8111            code.putln(
8112                'if (%s(%s) < 0) %s;' % (
8113                    Naming.import_star,
8114                    self.module.py_result(),
8115                    code.error_goto(self.pos)))
8116        item_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
8117        self.item.set_cname(item_temp)
8118        if self.interned_items:
8119            code.globalstate.use_utility_code(
8120                UtilityCode.load_cached("ImportFrom", "ImportExport.c"))
8121        for name, target, coerced_item in self.interned_items:
8122            code.putln(
8123                '%s = __Pyx_ImportFrom(%s, %s); %s' % (
8124                    item_temp,
8125                    self.module.py_result(),
8126                    code.intern_identifier(name),
8127                    code.error_goto_if_null(item_temp, self.pos)))
8128            code.put_gotref(item_temp)
8129            if coerced_item is None:
8130                target.generate_assignment_code(self.item, code)
8131            else:
8132                coerced_item.allocate_temp_result(code)
8133                coerced_item.generate_result_code(code)
8134                target.generate_assignment_code(coerced_item, code)
8135            code.put_decref_clear(item_temp, py_object_type)
8136        code.funcstate.release_temp(item_temp)
8137        self.module.generate_disposal_code(code)
8138        self.module.free_temps(code)
8139
8140
8141class ParallelNode(Node):
8142    """
8143    Base class for cython.parallel constructs.
8144    """
8145
8146    nogil_check = None
8147
8148
8149class ParallelStatNode(StatNode, ParallelNode):
8150    """
8151    Base class for 'with cython.parallel.parallel():' and 'for i in prange():'.
8152
8153    assignments     { Entry(var) : (var.pos, inplace_operator_or_None) }
8154                    assignments to variables in this parallel section
8155
8156    parent          parent ParallelStatNode or None
8157    is_parallel     indicates whether this node is OpenMP parallel
8158                    (true for #pragma omp parallel for and
8159                              #pragma omp parallel)
8160
8161    is_parallel is true for:
8162
8163        #pragma omp parallel
8164        #pragma omp parallel for
8165
8166    sections, but NOT for
8167
8168        #pragma omp for
8169
8170    We need this to determine the sharing attributes.
8171
8172    privatization_insertion_point   a code insertion point used to make temps
8173                                    private (esp. the "nsteps" temp)
8174
8175    args         tuple          the arguments passed to the parallel construct
8176    kwargs       DictNode       the keyword arguments passed to the parallel
8177                                construct (replaced by its compile time value)
8178    """
8179
8180    child_attrs = ['body', 'num_threads']
8181
8182    body = None
8183
8184    is_prange = False
8185    is_nested_prange = False
8186
8187    error_label_used = False
8188
8189    num_threads = None
8190    chunksize = None
8191
8192    parallel_exc = (
8193        Naming.parallel_exc_type,
8194        Naming.parallel_exc_value,
8195        Naming.parallel_exc_tb,
8196    )
8197
8198    parallel_pos_info = (
8199        Naming.parallel_filename,
8200        Naming.parallel_lineno,
8201        Naming.parallel_clineno,
8202    )
8203
8204    pos_info = (
8205        Naming.filename_cname,
8206        Naming.lineno_cname,
8207        Naming.clineno_cname,
8208    )
8209
8210    critical_section_counter = 0
8211
8212    def __init__(self, pos, **kwargs):
8213        super(ParallelStatNode, self).__init__(pos, **kwargs)
8214
8215        # All assignments in this scope
8216        self.assignments = kwargs.get('assignments') or {}
8217
8218        # All seen closure cnames and their temporary cnames
8219        self.seen_closure_vars = set()
8220
8221        # Dict of variables that should be declared (first|last|)private or
8222        # reduction { Entry: (op, lastprivate) }.
8223        # If op is not None, it's a reduction.
8224        self.privates = {}
8225
8226        # [NameNode]
8227        self.assigned_nodes = []
8228
8229    def analyse_declarations(self, env):
8230        self.body.analyse_declarations(env)
8231
8232        self.num_threads = None
8233
8234        if self.kwargs:
8235            # Try to find num_threads and chunksize keyword arguments
8236            pairs = []
8237            seen = set()
8238            for dictitem in self.kwargs.key_value_pairs:
8239                if dictitem.key.value in seen:
8240                    error(self.pos, "Duplicate keyword argument found: %s" % dictitem.key.value)
8241                seen.add(dictitem.key.value)
8242                if dictitem.key.value == 'num_threads':
8243                    if not dictitem.value.is_none:
8244                       self.num_threads = dictitem.value
8245                elif self.is_prange and dictitem.key.value == 'chunksize':
8246                    if not dictitem.value.is_none:
8247                        self.chunksize = dictitem.value
8248                else:
8249                    pairs.append(dictitem)
8250
8251            self.kwargs.key_value_pairs = pairs
8252
8253            try:
8254                self.kwargs = self.kwargs.compile_time_value(env)
8255            except Exception as e:
8256                error(self.kwargs.pos, "Only compile-time values may be "
8257                                       "supplied as keyword arguments")
8258        else:
8259            self.kwargs = {}
8260
8261        for kw, val in self.kwargs.items():
8262            if kw not in self.valid_keyword_arguments:
8263                error(self.pos, "Invalid keyword argument: %s" % kw)
8264            else:
8265                setattr(self, kw, val)
8266
8267    def analyse_expressions(self, env):
8268        if self.num_threads:
8269            self.num_threads = self.num_threads.analyse_expressions(env)
8270
8271        if self.chunksize:
8272            self.chunksize = self.chunksize.analyse_expressions(env)
8273
8274        self.body = self.body.analyse_expressions(env)
8275        self.analyse_sharing_attributes(env)
8276
8277        if self.num_threads is not None:
8278            if self.parent and self.parent.num_threads is not None and not self.parent.is_prange:
8279                error(self.pos, "num_threads already declared in outer section")
8280            elif self.parent and not self.parent.is_prange:
8281                error(self.pos, "num_threads must be declared in the parent parallel section")
8282            elif (self.num_threads.type.is_int and
8283                    self.num_threads.is_literal and
8284                    self.num_threads.compile_time_value(env) <= 0):
8285                error(self.pos, "argument to num_threads must be greater than 0")
8286
8287            if not self.num_threads.is_simple() or self.num_threads.type.is_pyobject:
8288                self.num_threads = self.num_threads.coerce_to(
8289                    PyrexTypes.c_int_type, env).coerce_to_temp(env)
8290        return self
8291
8292    def analyse_sharing_attributes(self, env):
8293        """
8294        Analyse the privates for this block and set them in self.privates.
8295        This should be called in a post-order fashion during the
8296        analyse_expressions phase
8297        """
8298        for entry, (pos, op) in self.assignments.items():
8299
8300            if self.is_prange and not self.is_parallel:
8301                # closely nested prange in a with parallel block, disallow
8302                # assigning to privates in the with parallel block (we
8303                # consider it too implicit and magicky for users)
8304                if entry in self.parent.assignments:
8305                    error(pos, "Cannot assign to private of outer parallel block")
8306                    continue
8307
8308            if not self.is_prange and op:
8309                # Again possible, but considered to magicky
8310                error(pos, "Reductions not allowed for parallel blocks")
8311                continue
8312
8313            # By default all variables should have the same values as if
8314            # executed sequentially
8315            lastprivate = True
8316            self.propagate_var_privatization(entry, pos, op, lastprivate)
8317
8318    def propagate_var_privatization(self, entry, pos, op, lastprivate):
8319        """
8320        Propagate the sharing attributes of a variable. If the privatization is
8321        determined by a parent scope, done propagate further.
8322
8323        If we are a prange, we propagate our sharing attributes outwards to
8324        other pranges. If we are a prange in parallel block and the parallel
8325        block does not determine the variable private, we propagate to the
8326        parent of the parent. Recursion stops at parallel blocks, as they have
8327        no concept of lastprivate or reduction.
8328
8329        So the following cases propagate:
8330
8331            sum is a reduction for all loops:
8332
8333                for i in prange(n):
8334                    for j in prange(n):
8335                        for k in prange(n):
8336                            sum += i * j * k
8337
8338            sum is a reduction for both loops, local_var is private to the
8339            parallel with block:
8340
8341                for i in prange(n):
8342                    with parallel:
8343                        local_var = ... # private to the parallel
8344                        for j in prange(n):
8345                            sum += i * j
8346
8347        Nested with parallel blocks are disallowed, because they wouldn't
8348        allow you to propagate lastprivates or reductions:
8349
8350            #pragma omp parallel for lastprivate(i)
8351            for i in prange(n):
8352
8353                sum = 0
8354
8355                #pragma omp parallel private(j, sum)
8356                with parallel:
8357
8358                    #pragma omp parallel
8359                    with parallel:
8360
8361                        #pragma omp for lastprivate(j) reduction(+:sum)
8362                        for j in prange(n):
8363                            sum += i
8364
8365                    # sum and j are well-defined here
8366
8367                # sum and j are undefined here
8368
8369            # sum and j are undefined here
8370        """
8371        self.privates[entry] = (op, lastprivate)
8372
8373        if entry.type.is_memoryviewslice:
8374            error(pos, "Memoryview slices can only be shared in parallel sections")
8375            return
8376
8377        if self.is_prange:
8378            if not self.is_parallel and entry not in self.parent.assignments:
8379                # Parent is a parallel with block
8380                parent = self.parent.parent
8381            else:
8382                parent = self.parent
8383
8384            # We don't need to propagate privates, only reductions and
8385            # lastprivates
8386            if parent and (op or lastprivate):
8387                parent.propagate_var_privatization(entry, pos, op, lastprivate)
8388
8389    def _allocate_closure_temp(self, code, entry):
8390        """
8391        Helper function that allocate a temporary for a closure variable that
8392        is assigned to.
8393        """
8394        if self.parent:
8395            return self.parent._allocate_closure_temp(code, entry)
8396
8397        if entry.cname in self.seen_closure_vars:
8398            return entry.cname
8399
8400        cname = code.funcstate.allocate_temp(entry.type, True)
8401
8402        # Add both the actual cname and the temp cname, as the actual cname
8403        # will be replaced with the temp cname on the entry
8404        self.seen_closure_vars.add(entry.cname)
8405        self.seen_closure_vars.add(cname)
8406
8407        self.modified_entries.append((entry, entry.cname))
8408        code.putln("%s = %s;" % (cname, entry.cname))
8409        entry.cname = cname
8410
8411    def initialize_privates_to_nan(self, code, exclude=None):
8412        first = True
8413
8414        for entry, (op, lastprivate) in sorted(self.privates.items()):
8415            if not op and (not exclude or entry != exclude):
8416                invalid_value = entry.type.invalid_value()
8417
8418                if invalid_value:
8419                    if first:
8420                        code.putln("/* Initialize private variables to "
8421                                   "invalid values */")
8422                        first = False
8423                    code.putln("%s = %s;" % (entry.cname,
8424                                             entry.type.cast_code(invalid_value)))
8425
8426    def evaluate_before_block(self, code, expr):
8427        c = self.begin_of_parallel_control_block_point_after_decls
8428        # we need to set the owner to ourselves temporarily, as
8429        # allocate_temp may generate a comment in the middle of our pragma
8430        # otherwise when DebugFlags.debug_temp_code_comments is in effect
8431        owner = c.funcstate.owner
8432        c.funcstate.owner = c
8433        expr.generate_evaluation_code(c)
8434        c.funcstate.owner = owner
8435
8436        return expr.result()
8437
8438    def put_num_threads(self, code):
8439        """
8440        Write self.num_threads if set as the num_threads OpenMP directive
8441        """
8442        if self.num_threads is not None:
8443            code.put(" num_threads(%s)" % self.evaluate_before_block(code, self.num_threads))
8444
8445
8446    def declare_closure_privates(self, code):
8447        """
8448        If a variable is in a scope object, we need to allocate a temp and
8449        assign the value from the temp to the variable in the scope object
8450        after the parallel section. This kind of copying should be done only
8451        in the outermost parallel section.
8452        """
8453        self.modified_entries = []
8454
8455        for entry in sorted(self.assignments):
8456            if entry.from_closure or entry.in_closure:
8457                self._allocate_closure_temp(code, entry)
8458
8459    def release_closure_privates(self, code):
8460        """
8461        Release any temps used for variables in scope objects. As this is the
8462        outermost parallel block, we don't need to delete the cnames from
8463        self.seen_closure_vars.
8464        """
8465        for entry, original_cname in self.modified_entries:
8466            code.putln("%s = %s;" % (original_cname, entry.cname))
8467            code.funcstate.release_temp(entry.cname)
8468            entry.cname = original_cname
8469
8470    def privatize_temps(self, code, exclude_temps=()):
8471        """
8472        Make any used temporaries private. Before the relevant code block
8473        code.start_collecting_temps() should have been called.
8474        """
8475        c = self.privatization_insertion_point
8476        self.privatization_insertion_point = None
8477
8478        if self.is_parallel:
8479            self.temps = temps = code.funcstate.stop_collecting_temps()
8480            privates, firstprivates = [], []
8481            for temp, type in sorted(temps):
8482                if type.is_pyobject or type.is_memoryviewslice:
8483                    firstprivates.append(temp)
8484                else:
8485                    privates.append(temp)
8486
8487            if privates:
8488                c.put(" private(%s)" % ", ".join(privates))
8489            if firstprivates:
8490                c.put(" firstprivate(%s)" % ", ".join(firstprivates))
8491
8492            if self.breaking_label_used:
8493                shared_vars = [Naming.parallel_why]
8494                if self.error_label_used:
8495                    shared_vars.extend(self.parallel_exc)
8496                    c.put(" private(%s, %s, %s)" % self.pos_info)
8497
8498                c.put(" shared(%s)" % ', '.join(shared_vars))
8499
8500    def cleanup_temps(self, code):
8501        # Now clean up any memoryview slice and object temporaries
8502        if self.is_parallel and not self.is_nested_prange:
8503            code.putln("/* Clean up any temporaries */")
8504            for temp, type in sorted(self.temps):
8505                if type.is_memoryviewslice:
8506                    code.put_xdecref_memoryviewslice(temp, have_gil=False)
8507                elif type.is_pyobject:
8508                    code.put_xdecref(temp, type)
8509                    code.putln("%s = NULL;" % temp)
8510
8511    def setup_parallel_control_flow_block(self, code):
8512        """
8513        Sets up a block that surrounds the parallel block to determine
8514        how the parallel section was exited. Any kind of return is
8515        trapped (break, continue, return, exceptions). This is the idea:
8516
8517        {
8518            int why = 0;
8519
8520            #pragma omp parallel
8521            {
8522                return # -> goto new_return_label;
8523                goto end_parallel;
8524
8525            new_return_label:
8526                why = 3;
8527                goto end_parallel;
8528
8529            end_parallel:;
8530                #pragma omp flush(why) # we need to flush for every iteration
8531            }
8532
8533            if (why == 3)
8534                goto old_return_label;
8535        }
8536        """
8537        self.old_loop_labels = code.new_loop_labels()
8538        self.old_error_label = code.new_error_label()
8539        self.old_return_label = code.return_label
8540        code.return_label = code.new_label(name="return")
8541
8542        code.begin_block() # parallel control flow block
8543        self.begin_of_parallel_control_block_point = code.insertion_point()
8544        self.begin_of_parallel_control_block_point_after_decls = code.insertion_point()
8545
8546        self.undef_builtin_expect_apple_gcc_bug(code)
8547
8548    def begin_parallel_block(self, code):
8549        """
8550        Each OpenMP thread in a parallel section that contains a with gil block
8551        must have the thread-state initialized. The call to
8552        PyGILState_Release() then deallocates our threadstate. If we wouldn't
8553        do this, each with gil block would allocate and deallocate one, thereby
8554        losing exception information before it can be saved before leaving the
8555        parallel section.
8556        """
8557        self.begin_of_parallel_block = code.insertion_point()
8558
8559    def end_parallel_block(self, code):
8560        """
8561        To ensure all OpenMP threads have thread states, we ensure the GIL
8562        in each thread (which creates a thread state if it doesn't exist),
8563        after which we release the GIL.
8564        On exit, reacquire the GIL and release the thread state.
8565
8566        If compiled without OpenMP support (at the C level), then we still have
8567        to acquire the GIL to decref any object temporaries.
8568        """
8569        begin_code = self.begin_of_parallel_block
8570        self.begin_of_parallel_block = None
8571
8572        if self.error_label_used:
8573            end_code = code
8574
8575            begin_code.putln("#ifdef _OPENMP")
8576            begin_code.put_ensure_gil(declare_gilstate=True)
8577            begin_code.putln("Py_BEGIN_ALLOW_THREADS")
8578            begin_code.putln("#endif /* _OPENMP */")
8579
8580            end_code.putln("#ifdef _OPENMP")
8581            end_code.putln("Py_END_ALLOW_THREADS")
8582            end_code.putln("#else")
8583            end_code.put_safe("{\n")
8584            end_code.put_ensure_gil()
8585            end_code.putln("#endif /* _OPENMP */")
8586            self.cleanup_temps(end_code)
8587            end_code.put_release_ensured_gil()
8588            end_code.putln("#ifndef _OPENMP")
8589            end_code.put_safe("}\n")
8590            end_code.putln("#endif /* _OPENMP */")
8591
8592    def trap_parallel_exit(self, code, should_flush=False):
8593        """
8594        Trap any kind of return inside a parallel construct. 'should_flush'
8595        indicates whether the variable should be flushed, which is needed by
8596        prange to skip the loop. It also indicates whether we need to register
8597        a continue (we need this for parallel blocks, but not for prange
8598        loops, as it is a direct jump there).
8599
8600        It uses the same mechanism as try/finally:
8601            1 continue
8602            2 break
8603            3 return
8604            4 error
8605        """
8606        save_lastprivates_label = code.new_label()
8607        dont_return_label = code.new_label()
8608
8609        self.any_label_used = False
8610        self.breaking_label_used = False
8611        self.error_label_used = False
8612
8613        self.parallel_private_temps = []
8614
8615        all_labels = code.get_all_labels()
8616
8617        # Figure this out before starting to generate any code
8618        for label in all_labels:
8619            if code.label_used(label):
8620                self.breaking_label_used = (self.breaking_label_used or
8621                                            label != code.continue_label)
8622                self.any_label_used = True
8623
8624        if self.any_label_used:
8625            code.put_goto(dont_return_label)
8626
8627        for i, label in enumerate(all_labels):
8628            if not code.label_used(label):
8629                continue
8630
8631            is_continue_label = label == code.continue_label
8632
8633            code.put_label(label)
8634
8635            if not (should_flush and is_continue_label):
8636                if label == code.error_label:
8637                    self.error_label_used = True
8638                    self.fetch_parallel_exception(code)
8639
8640                code.putln("%s = %d;" % (Naming.parallel_why, i + 1))
8641
8642            if (self.breaking_label_used and self.is_prange and not
8643                    is_continue_label):
8644                code.put_goto(save_lastprivates_label)
8645            else:
8646                code.put_goto(dont_return_label)
8647
8648        if self.any_label_used:
8649            if self.is_prange and self.breaking_label_used:
8650                # Don't rely on lastprivate, save our lastprivates
8651                code.put_label(save_lastprivates_label)
8652                self.save_parallel_vars(code)
8653
8654            code.put_label(dont_return_label)
8655
8656            if should_flush and self.breaking_label_used:
8657                code.putln_openmp("#pragma omp flush(%s)" % Naming.parallel_why)
8658
8659    def save_parallel_vars(self, code):
8660        """
8661        The following shenanigans are instated when we break, return or
8662        propagate errors from a prange. In this case we cannot rely on
8663        lastprivate() to do its job, as no iterations may have executed yet
8664        in the last thread, leaving the values undefined. It is most likely
8665        that the breaking thread has well-defined values of the lastprivate
8666        variables, so we keep those values.
8667        """
8668        section_name = "__pyx_parallel_lastprivates%d" % self.critical_section_counter
8669        code.putln_openmp("#pragma omp critical(%s)" % section_name)
8670        ParallelStatNode.critical_section_counter += 1
8671
8672        code.begin_block() # begin critical section
8673
8674        c = self.begin_of_parallel_control_block_point
8675
8676        temp_count = 0
8677        for entry, (op, lastprivate) in sorted(self.privates.items()):
8678            if not lastprivate or entry.type.is_pyobject:
8679                continue
8680
8681            type_decl = entry.type.empty_declaration_code()
8682            temp_cname = "__pyx_parallel_temp%d" % temp_count
8683            private_cname = entry.cname
8684
8685            temp_count += 1
8686
8687            invalid_value = entry.type.invalid_value()
8688            if invalid_value:
8689                init = ' = ' + entry.type.cast_code(invalid_value)
8690            else:
8691                init = ''
8692            # Declare the parallel private in the outer block
8693            c.putln("%s %s%s;" % (type_decl, temp_cname, init))
8694
8695            # Initialize before escaping
8696            code.putln("%s = %s;" % (temp_cname, private_cname))
8697
8698            self.parallel_private_temps.append((temp_cname, private_cname))
8699
8700        code.end_block() # end critical section
8701
8702    def fetch_parallel_exception(self, code):
8703        """
8704        As each OpenMP thread may raise an exception, we need to fetch that
8705        exception from the threadstate and save it for after the parallel
8706        section where it can be re-raised in the master thread.
8707
8708        Although it would seem that __pyx_filename, __pyx_lineno and
8709        __pyx_clineno are only assigned to under exception conditions (i.e.,
8710        when we have the GIL), and thus should be allowed to be shared without
8711        any race condition, they are in fact subject to the same race
8712        conditions that they were previously when they were global variables
8713        and functions were allowed to release the GIL:
8714
8715            thread A                thread B
8716                acquire
8717                set lineno
8718                release
8719                                        acquire
8720                                        set lineno
8721                                        release
8722                acquire
8723                fetch exception
8724                release
8725                                        skip the fetch
8726
8727                deallocate threadstate  deallocate threadstate
8728        """
8729        code.begin_block()
8730        code.put_ensure_gil(declare_gilstate=True)
8731
8732        code.putln_openmp("#pragma omp flush(%s)" % Naming.parallel_exc_type)
8733        code.putln(
8734            "if (!%s) {" % Naming.parallel_exc_type)
8735
8736        code.putln("__Pyx_ErrFetchWithState(&%s, &%s, &%s);" % self.parallel_exc)
8737        pos_info = chain(*zip(self.parallel_pos_info, self.pos_info))
8738        code.funcstate.uses_error_indicator = True
8739        code.putln("%s = %s; %s = %s; %s = %s;" % tuple(pos_info))
8740        code.put_gotref(Naming.parallel_exc_type)
8741
8742        code.putln(
8743            "}")
8744
8745        code.put_release_ensured_gil()
8746        code.end_block()
8747
8748    def restore_parallel_exception(self, code):
8749        "Re-raise a parallel exception"
8750        code.begin_block()
8751        code.put_ensure_gil(declare_gilstate=True)
8752
8753        code.put_giveref(Naming.parallel_exc_type)
8754        code.putln("__Pyx_ErrRestoreWithState(%s, %s, %s);" % self.parallel_exc)
8755        pos_info = chain(*zip(self.pos_info, self.parallel_pos_info))
8756        code.putln("%s = %s; %s = %s; %s = %s;" % tuple(pos_info))
8757
8758        code.put_release_ensured_gil()
8759        code.end_block()
8760
8761    def restore_labels(self, code):
8762        """
8763        Restore all old labels. Call this before the 'else' clause to for
8764        loops and always before ending the parallel control flow block.
8765        """
8766        code.set_all_labels(self.old_loop_labels + (self.old_return_label,
8767                                                    self.old_error_label))
8768
8769    def end_parallel_control_flow_block(
8770            self, code, break_=False, continue_=False, return_=False):
8771        """
8772        This ends the parallel control flow block and based on how the parallel
8773        section was exited, takes the corresponding action. The break_ and
8774        continue_ parameters indicate whether these should be propagated
8775        outwards:
8776
8777            for i in prange(...):
8778                with cython.parallel.parallel():
8779                    continue
8780
8781        Here break should be trapped in the parallel block, and propagated to
8782        the for loop.
8783        """
8784        c = self.begin_of_parallel_control_block_point
8785        self.begin_of_parallel_control_block_point = None
8786        self.begin_of_parallel_control_block_point_after_decls = None
8787
8788        if self.num_threads is not None:
8789            # FIXME: is it the right place? should not normally produce code.
8790            self.num_threads.generate_disposal_code(code)
8791            self.num_threads.free_temps(code)
8792
8793        # Firstly, always prefer errors over returning, continue or break
8794        if self.error_label_used:
8795            c.putln("const char *%s = NULL; int %s = 0, %s = 0;" % self.parallel_pos_info)
8796            c.putln("PyObject *%s = NULL, *%s = NULL, *%s = NULL;" % self.parallel_exc)
8797
8798            code.putln(
8799                "if (%s) {" % Naming.parallel_exc_type)
8800            code.putln("/* This may have been overridden by a continue, "
8801                       "break or return in another thread. Prefer the error. */")
8802            code.putln("%s = 4;" % Naming.parallel_why)
8803            code.putln(
8804                "}")
8805
8806        if continue_:
8807            any_label_used = self.any_label_used
8808        else:
8809            any_label_used = self.breaking_label_used
8810
8811        if any_label_used:
8812            # __pyx_parallel_why is used, declare and initialize
8813            c.putln("int %s;" % Naming.parallel_why)
8814            c.putln("%s = 0;" % Naming.parallel_why)
8815
8816            code.putln(
8817                "if (%s) {" % Naming.parallel_why)
8818
8819            for temp_cname, private_cname in self.parallel_private_temps:
8820                code.putln("%s = %s;" % (private_cname, temp_cname))
8821
8822            code.putln("switch (%s) {" % Naming.parallel_why)
8823            if continue_:
8824                code.put("    case 1: ")
8825                code.put_goto(code.continue_label)
8826
8827            if break_:
8828                code.put("    case 2: ")
8829                code.put_goto(code.break_label)
8830
8831            if return_:
8832                code.put("    case 3: ")
8833                code.put_goto(code.return_label)
8834
8835            if self.error_label_used:
8836                code.globalstate.use_utility_code(restore_exception_utility_code)
8837                code.putln("    case 4:")
8838                self.restore_parallel_exception(code)
8839                code.put_goto(code.error_label)
8840
8841            code.putln("}") # end switch
8842            code.putln(
8843                "}") # end if
8844
8845        code.end_block() # end parallel control flow block
8846        self.redef_builtin_expect_apple_gcc_bug(code)
8847
8848    # FIXME: improve with version number for OS X Lion
8849    buggy_platform_macro_condition = "(defined(__APPLE__) || defined(__OSX__))"
8850    have_expect_condition = "(defined(__GNUC__) && " \
8851                             "(__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))))"
8852    redef_condition = "(%s && %s)" % (buggy_platform_macro_condition, have_expect_condition)
8853
8854    def undef_builtin_expect_apple_gcc_bug(self, code):
8855        """
8856        A bug on OS X Lion disallows __builtin_expect macros. This code avoids them
8857        """
8858        if not self.parent:
8859            code.undef_builtin_expect(self.redef_condition)
8860
8861    def redef_builtin_expect_apple_gcc_bug(self, code):
8862        if not self.parent:
8863            code.redef_builtin_expect(self.redef_condition)
8864
8865
8866class ParallelWithBlockNode(ParallelStatNode):
8867    """
8868    This node represents a 'with cython.parallel.parallel():' block
8869    """
8870
8871    valid_keyword_arguments = ['num_threads']
8872
8873    num_threads = None
8874
8875    def analyse_declarations(self, env):
8876        super(ParallelWithBlockNode, self).analyse_declarations(env)
8877        if self.args:
8878            error(self.pos, "cython.parallel.parallel() does not take "
8879                            "positional arguments")
8880
8881    def generate_execution_code(self, code):
8882        self.declare_closure_privates(code)
8883        self.setup_parallel_control_flow_block(code)
8884
8885        code.putln("#ifdef _OPENMP")
8886        code.put("#pragma omp parallel ")
8887
8888        if self.privates:
8889            privates = [e.cname for e in self.privates
8890                        if not e.type.is_pyobject]
8891            code.put('private(%s)' % ', '.join(sorted(privates)))
8892
8893        self.privatization_insertion_point = code.insertion_point()
8894        self.put_num_threads(code)
8895        code.putln("")
8896
8897        code.putln("#endif /* _OPENMP */")
8898
8899        code.begin_block()  # parallel block
8900        self.begin_parallel_block(code)
8901        self.initialize_privates_to_nan(code)
8902        code.funcstate.start_collecting_temps()
8903        self.body.generate_execution_code(code)
8904        self.trap_parallel_exit(code)
8905        self.privatize_temps(code)
8906        self.end_parallel_block(code)
8907        code.end_block()  # end parallel block
8908
8909        continue_ = code.label_used(code.continue_label)
8910        break_ = code.label_used(code.break_label)
8911        return_ = code.label_used(code.return_label)
8912
8913        self.restore_labels(code)
8914        self.end_parallel_control_flow_block(code, break_=break_,
8915                                             continue_=continue_,
8916                                             return_=return_)
8917        self.release_closure_privates(code)
8918
8919
8920class ParallelRangeNode(ParallelStatNode):
8921    """
8922    This node represents a 'for i in cython.parallel.prange():' construct.
8923
8924    target       NameNode       the target iteration variable
8925    else_clause  Node or None   the else clause of this loop
8926    """
8927
8928    child_attrs = ['body', 'target', 'else_clause', 'args', 'num_threads',
8929                   'chunksize']
8930
8931    body = target = else_clause = args = None
8932
8933    start = stop = step = None
8934
8935    is_prange = True
8936
8937    nogil = None
8938    schedule = None
8939
8940    valid_keyword_arguments = ['schedule', 'nogil', 'num_threads', 'chunksize']
8941
8942    def __init__(self, pos, **kwds):
8943        super(ParallelRangeNode, self).__init__(pos, **kwds)
8944        # Pretend to be a ForInStatNode for control flow analysis
8945        self.iterator = PassStatNode(pos)
8946
8947    def analyse_declarations(self, env):
8948        super(ParallelRangeNode, self).analyse_declarations(env)
8949        self.target.analyse_target_declaration(env)
8950        if self.else_clause is not None:
8951            self.else_clause.analyse_declarations(env)
8952
8953        if not self.args or len(self.args) > 3:
8954            error(self.pos, "Invalid number of positional arguments to prange")
8955            return
8956
8957        if len(self.args) == 1:
8958            self.stop, = self.args
8959        elif len(self.args) == 2:
8960            self.start, self.stop = self.args
8961        else:
8962            self.start, self.stop, self.step = self.args
8963
8964        if hasattr(self.schedule, 'decode'):
8965            self.schedule = self.schedule.decode('ascii')
8966
8967        if self.schedule not in (None, 'static', 'dynamic', 'guided', 'runtime'):
8968            error(self.pos, "Invalid schedule argument to prange: %s" % (self.schedule,))
8969
8970    def analyse_expressions(self, env):
8971        was_nogil = env.nogil
8972        if self.nogil:
8973            env.nogil = True
8974
8975        if self.target is None:
8976            error(self.pos, "prange() can only be used as part of a for loop")
8977            return self
8978
8979        self.target = self.target.analyse_target_types(env)
8980
8981        if not self.target.type.is_numeric:
8982            # Not a valid type, assume one for now anyway
8983
8984            if not self.target.type.is_pyobject:
8985                # nogil_check will catch the is_pyobject case
8986                error(self.target.pos,
8987                      "Must be of numeric type, not %s" % self.target.type)
8988
8989            self.index_type = PyrexTypes.c_py_ssize_t_type
8990        else:
8991            self.index_type = self.target.type
8992            if not self.index_type.signed:
8993                warning(self.target.pos,
8994                        "Unsigned index type not allowed before OpenMP 3.0",
8995                        level=2)
8996
8997        # Setup start, stop and step, allocating temps if needed
8998        self.names = 'start', 'stop', 'step'
8999        start_stop_step = self.start, self.stop, self.step
9000
9001        for node, name in zip(start_stop_step, self.names):
9002            if node is not None:
9003                node.analyse_types(env)
9004                if not node.type.is_numeric:
9005                    error(node.pos, "%s argument must be numeric" % name)
9006                    continue
9007
9008                if not node.is_literal:
9009                    node = node.coerce_to_temp(env)
9010                    setattr(self, name, node)
9011
9012                # As we range from 0 to nsteps, computing the index along the
9013                # way, we need a fitting type for 'i' and 'nsteps'
9014                self.index_type = PyrexTypes.widest_numeric_type(
9015                    self.index_type, node.type)
9016
9017        if self.else_clause is not None:
9018            self.else_clause = self.else_clause.analyse_expressions(env)
9019
9020        # Although not actually an assignment in this scope, it should be
9021        # treated as such to ensure it is unpacked if a closure temp, and to
9022        # ensure lastprivate behaviour and propagation. If the target index is
9023        # not a NameNode, it won't have an entry, and an error was issued by
9024        # ParallelRangeTransform
9025        if hasattr(self.target, 'entry'):
9026            self.assignments[self.target.entry] = self.target.pos, None
9027
9028        node = super(ParallelRangeNode, self).analyse_expressions(env)
9029
9030        if node.chunksize:
9031            if not node.schedule:
9032                error(node.chunksize.pos,
9033                      "Must provide schedule with chunksize")
9034            elif node.schedule == 'runtime':
9035                error(node.chunksize.pos,
9036                      "Chunksize not valid for the schedule runtime")
9037            elif (node.chunksize.type.is_int and
9038                  node.chunksize.is_literal and
9039                  node.chunksize.compile_time_value(env) <= 0):
9040                error(node.chunksize.pos, "Chunksize must not be negative")
9041
9042            node.chunksize = node.chunksize.coerce_to(
9043                PyrexTypes.c_int_type, env).coerce_to_temp(env)
9044
9045        if node.nogil:
9046            env.nogil = was_nogil
9047
9048        node.is_nested_prange = node.parent and node.parent.is_prange
9049        if node.is_nested_prange:
9050            parent = node
9051            while parent.parent and parent.parent.is_prange:
9052                parent = parent.parent
9053
9054            parent.assignments.update(node.assignments)
9055            parent.privates.update(node.privates)
9056            parent.assigned_nodes.extend(node.assigned_nodes)
9057        return node
9058
9059    def nogil_check(self, env):
9060        names = 'start', 'stop', 'step', 'target'
9061        nodes = self.start, self.stop, self.step, self.target
9062        for name, node in zip(names, nodes):
9063            if node is not None and node.type.is_pyobject:
9064                error(node.pos, "%s may not be a Python object "
9065                                "as we don't have the GIL" % name)
9066
9067    def generate_execution_code(self, code):
9068        """
9069        Generate code in the following steps
9070
9071            1)  copy any closure variables determined thread-private
9072                into temporaries
9073
9074            2)  allocate temps for start, stop and step
9075
9076            3)  generate a loop that calculates the total number of steps,
9077                which then computes the target iteration variable for every step:
9078
9079                    for i in prange(start, stop, step):
9080                        ...
9081
9082                becomes
9083
9084                    nsteps = (stop - start) / step;
9085                    i = start;
9086
9087                    #pragma omp parallel for lastprivate(i)
9088                    for (temp = 0; temp < nsteps; temp++) {
9089                        i = start + step * temp;
9090                        ...
9091                    }
9092
9093                Note that accumulation of 'i' would have a data dependency
9094                between iterations.
9095
9096                Also, you can't do this
9097
9098                    for (i = start; i < stop; i += step)
9099                        ...
9100
9101                as the '<' operator should become '>' for descending loops.
9102                'for i from x < i < y:' does not suffer from this problem
9103                as the relational operator is known at compile time!
9104
9105            4) release our temps and write back any private closure variables
9106        """
9107        self.declare_closure_privates(code)
9108
9109        # This can only be a NameNode
9110        target_index_cname = self.target.entry.cname
9111
9112        # This will be used as the dict to format our code strings, holding
9113        # the start, stop , step, temps and target cnames
9114        fmt_dict = {
9115            'target': target_index_cname,
9116            'target_type': self.target.type.empty_declaration_code()
9117        }
9118
9119        # Setup start, stop and step, allocating temps if needed
9120        start_stop_step = self.start, self.stop, self.step
9121        defaults = '0', '0', '1'
9122        for node, name, default in zip(start_stop_step, self.names, defaults):
9123            if node is None:
9124                result = default
9125            elif node.is_literal:
9126                result = node.get_constant_c_result_code()
9127            else:
9128                node.generate_evaluation_code(code)
9129                result = node.result()
9130
9131            fmt_dict[name] = result
9132
9133        fmt_dict['i'] = code.funcstate.allocate_temp(self.index_type, False)
9134        fmt_dict['nsteps'] = code.funcstate.allocate_temp(self.index_type, False)
9135
9136        # TODO: check if the step is 0 and if so, raise an exception in a
9137        # 'with gil' block. For now, just abort
9138        code.putln("if ((%(step)s == 0)) abort();" % fmt_dict)
9139
9140        self.setup_parallel_control_flow_block(code) # parallel control flow block
9141
9142        # Note: nsteps is private in an outer scope if present
9143        code.putln("%(nsteps)s = (%(stop)s - %(start)s + %(step)s - %(step)s/abs(%(step)s)) / %(step)s;" % fmt_dict)
9144
9145        # The target iteration variable might not be initialized, do it only if
9146        # we are executing at least 1 iteration, otherwise we should leave the
9147        # target unaffected. The target iteration variable is firstprivate to
9148        # shut up compiler warnings caused by lastprivate, as the compiler
9149        # erroneously believes that nsteps may be <= 0, leaving the private
9150        # target index uninitialized
9151        code.putln("if (%(nsteps)s > 0)" % fmt_dict)
9152        code.begin_block() # if block
9153        self.generate_loop(code, fmt_dict)
9154        code.end_block() # end if block
9155
9156        self.restore_labels(code)
9157
9158        if self.else_clause:
9159            if self.breaking_label_used:
9160                code.put("if (%s < 2)" % Naming.parallel_why)
9161
9162            code.begin_block() # else block
9163            code.putln("/* else */")
9164            self.else_clause.generate_execution_code(code)
9165            code.end_block() # end else block
9166
9167        # ------ cleanup ------
9168        self.end_parallel_control_flow_block(code) # end parallel control flow block
9169
9170        # And finally, release our privates and write back any closure
9171        # variables
9172        for temp in start_stop_step + (self.chunksize,):
9173            if temp is not None:
9174                temp.generate_disposal_code(code)
9175                temp.free_temps(code)
9176
9177        code.funcstate.release_temp(fmt_dict['i'])
9178        code.funcstate.release_temp(fmt_dict['nsteps'])
9179
9180        self.release_closure_privates(code)
9181
9182    def generate_loop(self, code, fmt_dict):
9183        if self.is_nested_prange:
9184            code.putln("#if 0")
9185        else:
9186            code.putln("#ifdef _OPENMP")
9187
9188        if not self.is_parallel:
9189            code.put("#pragma omp for")
9190            self.privatization_insertion_point = code.insertion_point()
9191            reduction_codepoint = self.parent.privatization_insertion_point
9192        else:
9193            code.put("#pragma omp parallel")
9194            self.privatization_insertion_point = code.insertion_point()
9195            reduction_codepoint = self.privatization_insertion_point
9196            code.putln("")
9197            code.putln("#endif /* _OPENMP */")
9198
9199            code.begin_block() # pragma omp parallel begin block
9200
9201            # Initialize the GIL if needed for this thread
9202            self.begin_parallel_block(code)
9203
9204            if self.is_nested_prange:
9205                code.putln("#if 0")
9206            else:
9207                code.putln("#ifdef _OPENMP")
9208            code.put("#pragma omp for")
9209
9210        for entry, (op, lastprivate) in sorted(self.privates.items()):
9211            # Don't declare the index variable as a reduction
9212            if op and op in "+*-&^|" and entry != self.target.entry:
9213                if entry.type.is_pyobject:
9214                    error(self.pos, "Python objects cannot be reductions")
9215                else:
9216                    #code.put(" reduction(%s:%s)" % (op, entry.cname))
9217                    # This is the only way reductions + nesting works in gcc4.5
9218                    reduction_codepoint.put(
9219                                " reduction(%s:%s)" % (op, entry.cname))
9220            else:
9221                if entry == self.target.entry:
9222                    code.put(" firstprivate(%s)" % entry.cname)
9223                    code.put(" lastprivate(%s)" % entry.cname)
9224                    continue
9225
9226                if not entry.type.is_pyobject:
9227                    if lastprivate:
9228                        private = 'lastprivate'
9229                    else:
9230                        private = 'private'
9231
9232                    code.put(" %s(%s)" % (private, entry.cname))
9233
9234        if self.schedule:
9235            if self.chunksize:
9236                chunksize = ", %s" % self.evaluate_before_block(code, self.chunksize)
9237            else:
9238                chunksize = ""
9239
9240            code.put(" schedule(%s%s)" % (self.schedule, chunksize))
9241
9242        self.put_num_threads(reduction_codepoint)
9243
9244        code.putln("")
9245        code.putln("#endif /* _OPENMP */")
9246
9247        code.put("for (%(i)s = 0; %(i)s < %(nsteps)s; %(i)s++)" % fmt_dict)
9248        code.begin_block()  # for loop block
9249
9250        guard_around_body_codepoint = code.insertion_point()
9251
9252        # Start if guard block around the body. This may be unnecessary, but
9253        # at least it doesn't spoil indentation
9254        code.begin_block()
9255
9256        code.putln("%(target)s = (%(target_type)s)(%(start)s + %(step)s * %(i)s);" % fmt_dict)
9257        self.initialize_privates_to_nan(code, exclude=self.target.entry)
9258
9259        if self.is_parallel and not self.is_nested_prange:
9260            # nested pranges are not omp'ified, temps go to outer loops
9261            code.funcstate.start_collecting_temps()
9262
9263        self.body.generate_execution_code(code)
9264        self.trap_parallel_exit(code, should_flush=True)
9265        if self.is_parallel and not self.is_nested_prange:
9266            # nested pranges are not omp'ified, temps go to outer loops
9267            self.privatize_temps(code)
9268
9269        if self.breaking_label_used:
9270            # Put a guard around the loop body in case return, break or
9271            # exceptions might be used
9272            guard_around_body_codepoint.putln("if (%s < 2)" % Naming.parallel_why)
9273
9274        code.end_block()  # end guard around loop body
9275        code.end_block()  # end for loop block
9276
9277        if self.is_parallel:
9278            # Release the GIL and deallocate the thread state
9279            self.end_parallel_block(code)
9280            code.end_block()  # pragma omp parallel end block
9281
9282
9283class CnameDecoratorNode(StatNode):
9284    """
9285    This node is for the cname decorator in CythonUtilityCode:
9286
9287        @cname('the_cname')
9288        cdef func(...):
9289            ...
9290
9291    In case of a cdef class the cname specifies the objstruct_cname.
9292
9293    node        the node to which the cname decorator is applied
9294    cname       the cname the node should get
9295    """
9296
9297    child_attrs = ['node']
9298
9299    def analyse_declarations(self, env):
9300        self.node.analyse_declarations(env)
9301
9302        node = self.node
9303        if isinstance(node, CompilerDirectivesNode):
9304            node = node.body.stats[0]
9305
9306        self.is_function = isinstance(node, FuncDefNode)
9307        is_struct_or_enum = isinstance(node, (CStructOrUnionDefNode, CEnumDefNode))
9308        e = node.entry
9309
9310        if self.is_function:
9311            e.cname = self.cname
9312            e.func_cname = self.cname
9313            e.used = True
9314            if e.pyfunc_cname and '.' in e.pyfunc_cname:
9315                e.pyfunc_cname = self.mangle(e.pyfunc_cname)
9316        elif is_struct_or_enum:
9317            e.cname = e.type.cname = self.cname
9318        else:
9319            scope = node.scope
9320
9321            e.cname = self.cname
9322            e.type.objstruct_cname = self.cname + '_obj'
9323            e.type.typeobj_cname = Naming.typeobj_prefix + self.cname
9324            e.type.typeptr_cname = self.cname + '_type'
9325            e.type.scope.namespace_cname = e.type.typeptr_cname
9326
9327            e.as_variable.cname = e.type.typeptr_cname
9328
9329            scope.scope_prefix = self.cname + "_"
9330
9331            for name, entry in scope.entries.items():
9332                if entry.func_cname:
9333                    entry.func_cname = self.mangle(entry.cname)
9334                if entry.pyfunc_cname:
9335                    entry.pyfunc_cname = self.mangle(entry.pyfunc_cname)
9336
9337    def mangle(self, cname):
9338        if '.' in cname:
9339            # remove __pyx_base from func_cname
9340            cname = cname.split('.')[-1]
9341        return '%s_%s' % (self.cname, cname)
9342
9343    def analyse_expressions(self, env):
9344        self.node = self.node.analyse_expressions(env)
9345        return self
9346
9347    def generate_function_definitions(self, env, code):
9348        "Ensure a prototype for every @cname method in the right place"
9349        if self.is_function and env.is_c_class_scope:
9350            # method in cdef class, generate a prototype in the header
9351            h_code = code.globalstate['utility_code_proto']
9352
9353            if isinstance(self.node, DefNode):
9354                self.node.generate_function_header(
9355                    h_code, with_pymethdef=False, proto_only=True)
9356            else:
9357                from . import ModuleNode
9358                entry = self.node.entry
9359                cname = entry.cname
9360                entry.cname = entry.func_cname
9361
9362                ModuleNode.generate_cfunction_declaration(
9363                    entry,
9364                    env.global_scope(),
9365                    h_code,
9366                    definition=True)
9367
9368                entry.cname = cname
9369
9370        self.node.generate_function_definitions(env, code)
9371
9372    def generate_execution_code(self, code):
9373        self.node.generate_execution_code(code)
9374
9375
9376#------------------------------------------------------------------------------------
9377#
9378#  Runtime support code
9379#
9380#------------------------------------------------------------------------------------
9381
9382if Options.gcc_branch_hints:
9383    branch_prediction_macros = """
9384/* Test for GCC > 2.95 */
9385#if defined(__GNUC__) \
9386    && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)))
9387  #define likely(x)   __builtin_expect(!!(x), 1)
9388  #define unlikely(x) __builtin_expect(!!(x), 0)
9389#else /* !__GNUC__ or GCC < 2.95 */
9390  #define likely(x)   (x)
9391  #define unlikely(x) (x)
9392#endif /* __GNUC__ */
9393"""
9394else:
9395    branch_prediction_macros = """
9396#define likely(x)   (x)
9397#define unlikely(x) (x)
9398"""
9399
9400#------------------------------------------------------------------------------------
9401
9402printing_utility_code = UtilityCode.load_cached("Print", "Printing.c")
9403printing_one_utility_code = UtilityCode.load_cached("PrintOne", "Printing.c")
9404
9405#------------------------------------------------------------------------------------
9406
9407# Exception raising code
9408#
9409# Exceptions are raised by __Pyx_Raise() and stored as plain
9410# type/value/tb in PyThreadState->curexc_*.  When being caught by an
9411# 'except' statement, curexc_* is moved over to exc_* by
9412# __Pyx_GetException()
9413
9414restore_exception_utility_code = UtilityCode.load_cached("PyErrFetchRestore", "Exceptions.c")
9415raise_utility_code = UtilityCode.load_cached("RaiseException", "Exceptions.c")
9416get_exception_utility_code = UtilityCode.load_cached("GetException", "Exceptions.c")
9417swap_exception_utility_code = UtilityCode.load_cached("SwapException", "Exceptions.c")
9418reset_exception_utility_code = UtilityCode.load_cached("SaveResetException", "Exceptions.c")
9419traceback_utility_code = UtilityCode.load_cached("AddTraceback", "Exceptions.c")
9420
9421#------------------------------------------------------------------------------------
9422
9423get_exception_tuple_utility_code = UtilityCode(
9424    proto="""
9425static PyObject *__Pyx_GetExceptionTuple(PyThreadState *__pyx_tstate); /*proto*/
9426""",
9427    # I doubt that calling __Pyx_GetException() here is correct as it moves
9428    # the exception from tstate->curexc_* to tstate->exc_*, which prevents
9429    # exception handlers later on from receiving it.
9430    # NOTE: "__pyx_tstate" may be used by __Pyx_GetException() macro
9431    impl = """
9432static PyObject *__Pyx_GetExceptionTuple(CYTHON_UNUSED PyThreadState *__pyx_tstate) {
9433    PyObject *type = NULL, *value = NULL, *tb = NULL;
9434    if (__Pyx_GetException(&type, &value, &tb) == 0) {
9435        PyObject* exc_info = PyTuple_New(3);
9436        if (exc_info) {
9437            Py_INCREF(type);
9438            Py_INCREF(value);
9439            Py_INCREF(tb);
9440            PyTuple_SET_ITEM(exc_info, 0, type);
9441            PyTuple_SET_ITEM(exc_info, 1, value);
9442            PyTuple_SET_ITEM(exc_info, 2, tb);
9443            return exc_info;
9444        }
9445    }
9446    return NULL;
9447}
9448""",
9449    requires=[get_exception_utility_code])
9450