Skip to content

<algorithm>: /analyze with ranges algorithms emits fatal error C1060: compiler is out of heap space #1030

Open
@StephanTLavavej

Description

@StephanTLavavej

We've been encountering a recurring problem where testing the ranges algorithms with /analyze will fail with fatal error C1060: compiler is out of heap space. Specifically, the trigger seems to be constexpr testing of ranges algorithms with /analyze. Take P0896R4_ranges_alg_move for example:

struct instantiator {
    static constexpr int_wrapper expected_output[3] = {13, 55, 12345};
    static constexpr int_wrapper expected_input[3]  = {-1, -1, -1};

    template <ranges::input_range Read, indirectly_writable<ranges::range_rvalue_reference_t<Read>> Write>
    static constexpr void call() {
#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163
#pragma warning(suppress : 4127) //  conditional expression is constant
        if (!ranges::contiguous_range<Read> || !is_constant_evaluated())
#endif // TRANSITION, VSO-938163
        {
            using ranges::move, ranges::move_result, ranges::equal, ranges::iterator_t;
            {
                int_wrapper input[3]  = {13, 55, 12345};
                int_wrapper output[3] = {-2, -2, -2};
                Read wrapped_input{input};

                auto result = move(wrapped_input, Write{output});
                STATIC_ASSERT(same_as<decltype(result), move_result<iterator_t<Read>, Write>>);
                assert(result.in == wrapped_input.end());
                assert(result.out.peek() == output + 3);
                assert(equal(output, expected_output));
                assert(equal(input, expected_input));
            }
            {
                int_wrapper input[3]  = {13, 55, 12345};
                int_wrapper output[3] = {-2, -2, -2};
                Read wrapped_input{input};

                auto result = move(wrapped_input.begin(), wrapped_input.end(), Write{output});
                STATIC_ASSERT(same_as<decltype(result), move_result<iterator_t<Read>, Write>>);
                assert(result.in == wrapped_input.end());
                assert(result.out.peek() == output + 3);
                assert(equal(output, expected_output));
                assert(equal(input, expected_input));
            }
        }
    }
};

int main() {
    STATIC_ASSERT((test_in_write<instantiator, int_wrapper, int_wrapper>(), true)); // ***CONSTEXPR TEST***
    test_in_write<instantiator, int_wrapper, int_wrapper>();
}

test_in_write<instantiator, int_wrapper, int_wrapper>() calls instantiator::call with 825 different combinations of template arguments to get test coverage of virtually every possible combination of range argument properties. Compiling this test with /analyze exhausts the compiler heap resulting in C1060. It compiles fine if we comment out the // ***CONSTEXPR TEST*** line, but produces the same error if we comment out only the next non-constexpr test line. There's no clear reason why virtually the same code should require vastly more memory to analyze when it happens to be called in a constant expression vs. not. Indeed it's not clear to me why that distinction would affect the static analyzer at all.

We'll work around this for the time being by conditionally compiling the constexpr test only when _PREFAST_ is not defined, which indicates that /analyze is not enabled. @CaseyCarter will try to reduce a simpler test case and submit a static analyzer bug on Developer Community.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions