build/moz.configure/compilers-util.configure
author Iain Ireland <iireland@mozilla.com>
Fri, 11 Jan 2019 18:05:36 +0000
changeset 453523 025feea5945bffc625e9cca2e23be51ee8670315
parent 451417 f9f9a274668228b922c21866353bce5c7dec955b
child 466661 a5b86fb8a24a8162e1d824c7c55edb81f36f0445
permissions -rw-r--r--
Bug 1480390: Move ForOfIterClose logic inside TryNoteIter r=tcampbell This patch was intended to be a pure refactoring of existing code with no side-effects, moving the logic for handling for-of/for-of-iterclose trynotes inside TryNoteIter to avoid duplicating logic in all users of TryNoteIter. However, it turns out that there was a subtle preexisting bug in TryNoteIter that is fixed by the refactoring. Specifically, the logic to skip from a for-of-iterclose to its enclosing for-of must run before the logic to skip trynotes based on stack depth. Otherwise, the stack depth code may filter out the enclosing for-of (see the attached test case for an example) and we will skip too many try-notes. Differential Revision: https://phabricator.services.mozilla.com/D14783

# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.


@template
@imports('textwrap')
@imports(_from='mozbuild.configure', _import='SandboxDependsFunction')
def compiler_class(compiler, host_or_target):
    is_target = host_or_target is target

    class Compiler(SandboxDependsFunction):
        # Generates a test program and attempts to compile it. In case of
        # failure, the resulting check will return None. If the test program
        # succeeds, it will return the output of the test program.
        # - `includes` are the includes (as file names) that will appear at the
        #   top of the generated test program.
        # - `body` is the code that will appear in the main function of the
        #   generated test program. `return 0;` is appended to the function
        #   body automatically.
        # - `flags` are the flags to be passed to the compiler, in addition to
        #   `-c`.
        # - `check_msg` is the message to be printed to accompany compiling the
        #   test program.
        def try_compile(self, includes=None, body='', flags=None,
                        check_msg=None, when=None, onerror=lambda: None):
            @depends(dependable(flags))
            def flags(flags):
                flags = list(flags or [])
                flags.append('-c')
                return flags

            @depends(dependable(includes))
            def header(includes):
                includes = includes or []
                return ['#include <%s>' % f for f in includes]

            return self.try_run(
                header=header, body=body, flags=flags, check_msg=check_msg,
                when=when, onerror=onerror)

        # Generates a test program and run the compiler against it. In case of
        # failure, the resulting check will return None.
        # - `header` is code that will appear at the top of the generated test
        #   program.
        # - `body` is the code that will appear in the main function of the
        #   generated test program. `return 0;` is appended to the function
        #   body automatically.
        # - `flags` are the flags to be passed to the compiler.
        # - `check_msg` is the message to be printed to accompany compiling the
        #   test program.
        # - `onerror` is a function called when the check fails.
        def try_run(self, header=None, body='', flags=None,
                    check_msg=None, when=None, onerror=lambda: None):
            source = textwrap.dedent('''\
                int
                main(void)
                {
                %s
                  ;
                  return 0;
                }
            ''' % body)

            if check_msg:
                def checking_fn(fn):
                    return checking(check_msg)(fn)
            else:
                def checking_fn(fn):
                    return fn

            @depends(self, dependable(flags), extra_toolchain_flags, dependable(header), when=when)
            @checking_fn
            def func(compiler, flags, extra_flags, header):
                flags = list(flags or [])
                if is_target:
                    flags += extra_flags or []
                header = header or ''
                if isinstance(header, (list, tuple)):
                    header = '\n'.join(header)
                if header:
                    header += '\n'

                if try_invoke_compiler(
                        compiler.wrapper +
                        [compiler.compiler] + compiler.flags,
                        compiler.language, header + source, flags,
                        onerror=onerror) is not None:
                    return True

            return func

    compiler.__class__ = Compiler
    return compiler