Skip to content

P1004R2_constexpr_vector: Report MSVC constexpr error affecting std::construct_at array support #6155

@StephanTLavavej

Description

@StephanTLavavej

Followup to #5110 and #5920.

After fixing DevCom-10798069 "Placement operator new[] in <vcruntime.h> should be marked _MSVC_CONSTEXPR", I'm removing our workarounds, including but not limited to:

STL/stl/inc/xutility

Lines 610 to 636 in 26b7ca5

_EXPORT_STD template <class _Ty, class... _Types>
requires (!is_unbounded_array_v<_Ty>) && requires(_Ty* _Location, _Types&&... _Args) {
::new (static_cast<void*>(_Location)) _Ty(_STD forward<_Types>(_Args)...); // per LWG-3888
}
constexpr _Ty* construct_at(_Ty* const _Location, _Types&&... _Args)
noexcept(noexcept(::new (static_cast<void*>(_Location)) _Ty(_STD forward<_Types>(_Args)...))) /* strengthened */ {
if constexpr (is_array_v<_Ty>) {
static_assert(sizeof...(_Types) == 0, "The array is only allowed to be value-initialized by std::construct_at. "
"(N5032 [specialized.construct]/2)");
#if defined(__clang__) || defined(__EDG__) // TRANSITION, LLVM-117294, DevCom-10798145
::new (static_cast<void*>(_Location)) _Ty();
return __builtin_launder(_Location); // per old resolution of LWG-3436
#elif defined(_MSC_VER) // TRANSITION, DevCom-10798069
if constexpr (is_trivially_destructible_v<_Ty>) {
_MSVC_CONSTEXPR return ::new (_Secret_placement_new_tag{}, static_cast<void*>(_Location)) _Ty[1]();
} else {
// For non-trivially-destructible types, the workaround doesn't work
// because additional space is required to record the number of class objects to destroy.
return ::new (static_cast<void*>(_Location)) _Ty[1]();
}
#else // ^^^ workaround / no workaround vvv
_MSVC_CONSTEXPR return ::new (static_cast<void*>(_Location)) _Ty[1]();
#endif // ^^^ no workaround ^^^
} else {
_MSVC_CONSTEXPR return ::new (static_cast<void*>(_Location)) _Ty(_STD forward<_Types>(_Args)...);
}
}

However, a couple of the tests in P1004R2_constexpr_vector are still failing. Somewhat reduced:

C:\Temp>type meow.cpp
#include <cassert>
#include <vector>
using namespace std;

struct Udt {
    int x{1729};
};

constexpr bool test_vector_of_array_impl() {
    vector<Udt[3]> vec(5);

    for (const auto& arr : vec) {
        for (const auto& elem : arr) {
            assert(elem.x == 1729);
        }
    }

    return true;
}

int main() {
    static_assert(test_vector_of_array_impl());
}
C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /MT /c meow.cpp
meow.cpp
meow.cpp(22): error C2131: expression did not evaluate to a constant
meow.cpp(14): note: failure was caused by accessing a data member of pointer past the end of object
meow.cpp(22): note: the call stack of the evaluation (the oldest call first) is
meow.cpp(22): note: while evaluating function 'bool test_vector_of_array_impl(void)'

I'm guessing this is an MSVC compiler bug that needs to be reported, possibly after being further reduced. (These are typically easier to report to the compiler devs after merging any STL product code changes, such as the workaround removals here.) I'm filing this as a tracking issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    compilerCompiler work involvedtestRelated to test code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions