MSVC 2017 violating static initialization order within single translation unit

岁酱吖の 提交于 2019-12-04 04:03:33

问题


MSVC 2017 Community with -std=c++17 chokes on the following example:

#include <iostream>

struct TC
{
    static TC const values[];
    static TC const& A;
    static TC const& B;
    static TC const& C;

    int const _value;
};

inline constexpr TC const TC::values[]{ { 42 }, { 43 }, { 44 } };
inline constexpr TC const& TC::A{ values[0U] };
inline constexpr TC const& TC::B{ values[1U] };
inline constexpr TC const& TC::C{ values[2U] };

int main(int, char**) noexcept
{
    std::cout << std::boolalpha
        << "&A == &values[0]? " << (&TC::A == &TC::values[0U]) << "\n" 
        << "&B == &values[1]? " << (&TC::B == &TC::values[1U]) << "\n"
        << "&C == &values[2]? " << (&TC::C == &TC::values[2U]) << "\n";
    return 0;
}

The expected output is:

&A == &values[0]? true
&B == &values[1]? true
&C == &values[2]? true

Which is what both gcc and clang produce, but MSVC gives:

&A == &values[0]? true
&B == &values[1]? false
&C == &values[2]? false

MSVC does give the correct results if the _value member is removed and there is no user-defined constructor.

As all of this is within a single translation unit, my understanding is that this falls under Partially-ordered dynamic initialization:

2) Partially-ordered dynamic initialization, which applies to all inline variables that are not an implicitly or explicitly instantiated specialization. If a partially-ordered V is defined before ordered or partially-ordered W in every translation unit, the initialization of V is sequenced before the initialization of W (or happens-before, if the program starts a thread)

I cannot use a function to ensure initialization order as I require constexpr values and constexpr references to them.

So the question is, MSVC is in violation of the standard* here, correct?

*Of course cppreference.com isn't "the standard", but I'm assuming that the information there is correctly sourced.


回答1:


I isolate the same problem to this simpler example:

#include <iostream>

int values[3];
constexpr int& v{ values[1] };

int main()
{
    std::cout << &v << ", " << &values[1] << "\n";
    return 0;
}

which, using latest MSVC 2017 Community, gives output of:

0119D035, 0119D038

The problem does not happen if constexpr is removed.

So I think this is a compiler bug with constexpr reference initialization. The reference was initialized to &values[0] + 1 byte, not &values[1] as it should be.

NB. If anyone is not familiar with constexpr reference definitions, see here or here. constexpr enforces that the initializer is an object with static storage duration.



来源:https://stackoverflow.com/questions/50402741/msvc-2017-violating-static-initialization-order-within-single-translation-unit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!