MSVC 2017 violating static initialization order wi

2019-02-25 07:42发布

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条回答
Viruses.
2楼-- · 2019-02-25 08:31

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.

查看更多
登录 后发表回答