snitch-org / snitch

Lightweight C++20 testing framework.
Boost Software License 1.0
252 stars 7 forks source link

Compilation error with MSVC 19.37 #140

Closed cschreib closed 8 months ago

cschreib commented 8 months ago

From https://github.com/snitch-org/snitch/actions/runs/6781475887/job/18431859675.

The Windows pipeline worked fine last week, with MSVC 19.35.32217.1. Now, running the CI pipeline with MSVC 19.37.32825.0, we get this:

D:\a\snitch\snitch\include\snitch/snitch_expression.hpp(36,1): error C7595: 'std::_Literal_zero::_Literal_zero': call to immediate function is not a constant expression [D:\a\snitch\snitch\build\tests\snitch_runtime_tests.vcxproj]
D:\a\snitch\snitch\include\snitch/snitch_expression.hpp(36,1): message : failure was caused by a read of a variable outside its lifetime [D:\a\snitch\snitch\build\tests\snitch_runtime_tests.vcxproj]
D:\a\snitch\snitch\include\snitch/snitch_expression.hpp(36,1): message : see usage of 'rhs' [D:\a\snitch\snitch\build\tests\snitch_runtime_tests.vcxproj]
D:\a\snitch\snitch\include\snitch/snitch_expression.hpp(156,30): message : see reference to function template instantiation 'bool snitch::impl::operator_not_equal::operator ()<T,U>(const T &,const U &) noexcept const' being compiled [D:\a\snitch\snitch\build\tests\snitch_runtime_tests.vcxproj]
          with
          [
              T=std::strong_ordering,
              U=int
          ]
D:\a\snitch\snitch\include\snitch/snitch_expression.hpp(151,26): message : while compiling class template member function 'snitch::impl::expression snitch::impl::extracted_binary_expression<true,T,snitch::impl::operator_not_equal,int>::to_expression(void) noexcept const' [D:\a\snitch\snitch\build\tests\snitch_runtime_tests.vcxproj]
          with
          [
              T=std::strong_ordering
          ]
D:\a\snitch\snitch\tests\runtime_tests\check.cpp(544,13): message : see the first reference to 'snitch::impl::extracted_binary_expression<true,T,snitch::impl::operator_not_equal,int>::to_expression' in 'DOCTEST_ANON_FUNC_81' [D:\a\snitch\snitch\build\tests\snitch_runtime_tests.vcxproj]
          with
          [
              T=std::strong_ordering
          ]
D:\a\snitch\snitch\tests\runtime_tests\check.cpp(544,13): message : see reference to class template instantiation 'snitch::impl::extracted_binary_expression<true,T,snitch::impl::operator_not_equal,int>' being compiled [D:\a\snitch\snitch\build\tests\snitch_runtime_tests.vcxproj]
          with
          [
              T=std::strong_ordering
          ]
  cli.cpp
D:\a\snitch\snitch\include\snitch/snitch_expression.hpp(36,1): error C7595: 'std::_Literal_zero::_Literal_zero': call to immediate function is not a constant expression [D:\a\snitch\snitch\build\tests\snitch_runtime_tests_self.vcxproj]
D:\a\snitch\snitch\include\snitch/snitch_expression.hpp(36,1): message : failure was caused by a read of a variable outside its lifetime [D:\a\snitch\snitch\build\tests\snitch_runtime_tests_self.vcxproj]
D:\a\snitch\snitch\include\snitch/snitch_expression.hpp(36,1): message : see usage of 'rhs' [D:\a\snitch\snitch\build\tests\snitch_runtime_tests_self.vcxproj]
D:\a\snitch\snitch\include\snitch/snitch_expression.hpp(156,30): message : see reference to function template instantiation 'bool snitch::impl::operator_not_equal::operator ()<T,U>(const T &,const U &) noexcept const' being compiled [D:\a\snitch\snitch\build\tests\snitch_runtime_tests_self.vcxproj]
          with
          [
              T=std::strong_ordering,
              U=int
          ]
D:\a\snitch\snitch\include\snitch/snitch_expression.hpp(151,26): message : while compiling class template member function 'snitch::impl::expression snitch::impl::extracted_binary_expression<true,T,snitch::impl::operator_not_equal,int>::to_expression(void) noexcept const' [D:\a\snitch\snitch\build\tests\snitch_runtime_tests_self.vcxproj]
          with
          [
              T=std::strong_ordering
          ]
D:\a\snitch\snitch\tests\runtime_tests\check.cpp(544,13): message : see the first reference to 'snitch::impl::extracted_binary_expression<true,T,snitch::impl::operator_not_equal,int>::to_expression' in 'test_fun_34' [D:\a\snitch\snitch\build\tests\snitch_runtime_tests_self.vcxproj]
          with
          [
              T=std::strong_ordering
          ]
D:\a\snitch\snitch\tests\runtime_tests\check.cpp(544,13): message : see reference to class template instantiation 'snitch::impl::extracted_binary_expression<true,T,snitch::impl::operator_not_equal,int>' being compiled [D:\a\snitch\snitch\build\tests\snitch_runtime_tests_self.vcxproj]
          with
          [
              T=std::strong_ordering
          ]
cschreib commented 8 months ago

Minimal reproduction of the issue:

#include <compare>

struct operator_not_equal {
    template<typename T, typename U>
    constexpr bool operator()(const T& lhs, const U& rhs) const noexcept(noexcept(lhs != rhs))
        requires(requires(const T& lhs, const U& rhs) { lhs != rhs; })
    {
        return lhs != rhs;
    }
};

int main() {
    operator_not_equal{}(1 <=> 1, 0);
    return 0;
}

Yields:

<source>(9): error C7595: 'std::_Literal_zero::_Literal_zero': call to immediate function is not a constant expression
<source>(9): note: failure was caused by a read of a variable outside its lifetime
<source>(9): note: see usage of 'rhs'
<source>(14): note: see reference to function template instantiation 'bool operator_not_equal::operator ()<std::strong_ordering,int>(const T &,const U &) noexcept const' being compiled
        with
        [
            T=std::strong_ordering,
            U=int
        ]

Seems like a compiler bug:

  1. The error message is incorrect; there is no lifetime issue.
  2. If there was really a problem compiling the != expression, the requires() should have prevented instantiation of the function. Instead it passed, and the error occurred on instantiation.

Reported here: https://developercommunity.visualstudio.com/t/Regression:-False-positive-C7595:-std::/10509214

NB: The expected behavior here is still a compilation error, but only as a "no matching call found for operator()". The expected error enables conditional decomposition; while we cannot decompose 1 <=> 1 != 0, snitch contains code to recover from this. This compiler bug is preventing the recovery from doing its job.

cschreib commented 8 months ago

I will tag this as "not our bug" since the ball is in the camp of the MSVC team now. In https://github.com/snitch-org/snitch/pull/144 the offending test is disabled specifically for the affected MSVC compiler version.

horenmar commented 6 months ago

This is not actually bug, but rather consequence of an intended change.

cschreib commented 6 months ago

Thanks for the link! That's unfortunate, although it still seems to me that, as you put it, "requires lying" should really be seen as a bug.

horenmar commented 6 months ago

I agree, but some people don't 🤷

I am currently trying to convince libc++ maintainers not to make the same change.

CrustyAuklet commented 3 months ago

In testing the other branches I am working on I am hitting this failure with MSVC2022 build tools Microsoft (R) C/C++ Optimizing Compiler Version 19.39.33523 for x64

Just FYI. Maybe best to just remove the upper limit on MSVC version?

cschreib commented 3 months ago

Thanks. I guess that'll keep failing until the bug report is addressed... I had left an explicit upper limit to avoid the risk of forgetting that the test is disabled. My hope was that it would be fixed quickly, but if not, as it appears, this may prove indeed to be a nuisance.

Next time GitHub bump the compiler version, we can remove the upper limit. Perhaps also reopen this ticket as a reminder that the problem still exists.

horenmar commented 3 months ago

For the test/bug to be fixed, MSVC has to implement P2564 which was a late DR against C++20. Supposedly it was pretty hard to implement for Clang, and MSVC's constexpr engine is much more of a mess, so it might take a long while.

For the compilation check, you probably want to guard the test on __cpp_consteval >= 202211L, rather than MSVC version.


MS STL refuses to back out the change, because the issue is in the compiler and e.g. clang-cl does have the required behaviour. libc++ followed MS STL, but they also use an interesting clang extension that means you can still sfinae on the behaviour (as long as you use Clang as the compiler).