Repository: xtensor-stack/xtensor (language: python)

Issue:
argmax crashes when compiled using Visual Studio compiler with O1/O2 optimizations
This issue was observed when running cmake unit tests on Windows platform: in debug mode all tests were passed, in release mode it tests were failed with `unknown file: error: SEH exception with code 0xc0000005 thrown in the test body.`

Here is sample code to reproduce this issue:

```
#include <xtensor.hpp>

int main() {
    xt::xarray<double> a = {0, 1, 0};
    auto max = xt::argmax(a);
    std::cout << max << std::endl;
    return 0;
}
```

`cl /I xtensor-0.24.2\include /I xtl-0.7.4\include argmax.cpp` produces exe which doesn't crash

`cl /I xtensor-0.24.2\include /I xtl-0.7.4\include /O1 argmax.cpp` produces exe which crashes

Compiler information:

```
where cl
C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.33.31629\bin\Hostx86\x86\cl.exe
cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.33.31629 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

usage: cl [ option... ] filename... [ /link linkoption... ]
```
Segmentation fault 0-size xtensor on Windows
I consistently get a segmentation fault on Windows with 0-size xtensor. The source is to be further investigated but I am getting this consistently on Windows on GH Action in a Python module. 

I have found this issue in several operations, but most notably `xt::argmax(e)` segmentation faults whereas `std::distance(e.begin(), std::max_element(e.begin(), e.end()))` does not. 

Note that this has use implication for me. Default functions segmentation faulting:
* argmax
* mean
* amin
* ....


Discussion / hints:
Probably it hase the same root cause: #2551 
Thanks for reporting. I don't have easy access to Visual Studio. Would you be willing to debug this a bit? Could you tell us which part of the implementation works and which does not?
This does have the same root at #2551.

This happens only with MSVC > v19.31 

A second, minimal reproduction, found in return of [argmax](https://github.com/xtensor-stack/xtensor/blob/master/include/xtensor/xsort.hpp#L871)

```c++
#include <xtensor.hpp>

int main() {
    xt::xtensor<std::size_t, 0> a{5};
    return 0;
}
```

It looks like there is an issue with 0 dimension xtensors / std::array<size_t, 0>. 

During construction, the call to `xt::resize(shape, true)` fails somewhere in the inlined `computed_strides()`

<details>

<summary> makeshift printf stacktrace </summary>

```
xt::xtensor_container<class xt::uvector<unsigned __int64,class std::allocator<unsigned __int64> >,0,1,struct xt::xtensor_expression_tag>::xtensor_container
  xt::shape
  R: class std::array<unsigned __int64,0>
  T: unsigned __int64
    xt::detail::initializer_shape
    R: class std::array<unsigned __int64,0>
    U: unsigned __int64
    size_type: unsigned __int64
xt::xtensor_container<class xt::uvector<unsigned __int64,class std::allocator<unsigned __int64> >,0,1,struct xt::xtensor_expression_tag>::xtensor_container
  xt::xstrided_container<class xt::xtensor_container<class xt::uvector<unsigned __int64,class std::allocator<unsigned __int64> >,0,1,struct xt::xtensor_expression_tag> >::resize
  D: class xt::xtensor_container<class xt::uvector<unsigned __int64,class std::allocator<unsigned __int64> >,0,1,struct xt::xtensor_expression_tag>
  S: class std::array<unsigned __int64,0>
  dim: 0
  before compute_strides
    xt::compute_strides
    L: 1
    shape_type: class std::array<unsigned __int64,0>
    layout_type: enum xt::layout_type l: 1
    strides_type: class std::array<__int64,0>
    backstrides_type: class std::array<__int64,0>
      xt::detail::compute_strides
      L: 1
      shape_type: class std::array<unsigned __int64,0>
      layout_type: enum xt::layout_type l: 1
      strides_type: class std::array<__int64,0>
      bs_ptr: class std::array<__int64,0> * __ptr64
      strides_value_type: __int64
      data_size: 1
      is_row_major
      size: 0
```

</details>

I copied the relevant xtensor functions out into a minimal reproduction on [godbolt](https://godbolt.org/z/5Gbo75Tb3).

I'm leaning towards MSVC compiler bug at this point

upstream bug report: https://developercommunity.visualstudio.com/t/Runtime-Crash-msvc--1931-with-optimiz/10134617


Thanks @sg-james !! I guess would should consider adding the workaround proposed upstream for this specific compiler version?
related: https://github.com/xtensor-stack/xtensor/issues/2568

in the linked issue, I created a minimal reproduction of the issue on godbolt.

I also filed an MSVC bug (link also in issue), which appears to be an incorrect optimization. I wasn't able to follow the advice to fix the problem however

Fix patch:
diff --git a/docs/source/compilers.rst b/docs/source/compilers.rst
index 1bd009809..69673031e 100644
--- a/docs/source/compilers.rst
+++ b/docs/source/compilers.rst
@@ -50,6 +50,15 @@ In ``xfixed.hpp`` we add a level of indirection to expand one parameter pack bef
 Not doing this results in VS2017 complaining about a parameter pack that needs to be expanded in this
 context while it actually is.
 
+Visual Studio 2022 (19.31+) workaround inline compiler optimization bug
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In ``xstrides.hpp``, added an early return inside ``compute_strides`` when ``shape.size() == 0`` to
+prevent a run time crash from occuring. Without this guard statement, instructions from inside the
+for loop were somehow being reached, despite being logically unreachable.
+Original issue  `here. <https://github.com/xtensor-stack/xtensor/issues/2568>`_
+Upstream issue `here. <https://developercommunity.visualstudio.com/t/Runtime-Crash-msvc--1931-with-optimiz/10134617>`_
+
 GCC-4.9 and Clang < 3.8 and constexpr ``std::min`` and ``std::max``
 -------------------------------------------------------------------
 
diff --git a/include/xtensor/xstrides.hpp b/include/xtensor/xstrides.hpp
index 1a322cfbe..954039131 100644
--- a/include/xtensor/xstrides.hpp
+++ b/include/xtensor/xstrides.hpp
@@ -456,6 +456,14 @@ namespace xt
         {
             using strides_value_type = typename std::decay_t<strides_type>::value_type;
             strides_value_type data_size = 1;
+
+        #if defined(_MSC_VER) && (1931 <= _MSC_VER)
+            // Workaround MSVC compiler optimization bug, xtensor#2568
+            if (0 == shape.size()) {
+                return static_cast<std::size_t>(data_size);
+            }
+        #endif
+
             if (L == layout_type::row_major || l == layout_type::row_major)
             {
                 for (std::size_t i = shape.size(); i != 0; --i)


Test patch:
diff --git a/test/test_xsort.cpp b/test/test_xsort.cpp
index 2b0853bcf..2146888c3 100644
--- a/test/test_xsort.cpp
+++ b/test/test_xsort.cpp
@@ -218,6 +218,12 @@ namespace xt
 
         xtensor<std::size_t, 2> ex_6 = {{0, 0, 0, 0}, {0, 0, 0, 0}};
         EXPECT_EQ(ex_6, argmax(c, 1));
+
+        // xtensor#2568
+        xarray<double> d = {0, 1, 0};
+        xtensor<size_t, 0> d_ex_1 = { 1 };
+        EXPECT_EQ(d_ex_1, argmax(d));
+        EXPECT_EQ(1, argmax(d)(0));
     }
 
     TEST(xsort, sort_large_prob)