You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Microsoft VSO-1284799 - constexpr ICE: binding a reference to a temporary emits Assertion failed: Nerrors > 0 - not blocking for MSVC, have workaround ⚠️
📑 Compiler Approaches to constexpr Dynamic Allocation
(from @cdacamar in #1532) Note that [expr.const]/5 states that an expression E is a core constant expression unless the evaluation of E would [...] would evaluate one of the following:
a new-expression ([expr.new]), unless the the selected allocation function is a replaceable global allocation function ([new.delete.single], [new.delete.array]) and the allocated storage is deallocated within the evaluation of E;
a delete-expression ([expr.delete]), unless it deallocates a region of storage allocated within the evaluation of E;
a call to an instance of std::allocator::allocate ([allocator.members]), unless the allocated storage is deallocated within the evaluation of E;
a call to an instance of std::allocator::deallocate ([allocator.members]), unless it deallocates a region of storage allocated within the evaluation of E;
[...]
So, the expression ::operator new is not a new expression, it is a function call to a global operator new() which is not a constexpr function.
Clang has chosen to allow ::operator new in a constexpr function if it is reached transitively from an evaluation of std::allocator::allocate.
MSVC has chosen to do "fairy magic" (🧚) when it sees std::allocator::allocate, std::allocator::deallocate, but does not allow ::operator new.
EDG (Intellisense) appears to allow ::operator new, but we choose to have the EDG logical paths mirror those for MSVC so they work in tandem.
Development notes, preserved for history
👣 Next Steps (as of Jan 2021)
After getting the bug fixes in 16.9 Preview 3, @miscco discovered several new bugs in MSVC FE and BE and EDG (see Active C1XX Bugs, Active MSVC Back-End Bugs, and Active EDG Bugs).
This bug is blocking in our iterator debug machinery, see further discussion here. In particular, we need to make some members of our debug iterators mutable, but Clang currently does not allow this due to this bug.
More background on the use case:
Because global vector variables can exist, we need to enable situations where a variable is constant initialized (so std::is_constant_evaluated() evaluates to true in the constructor), but not necessarily constant evaluated (so std::is_constant_evaluated() evaluates to false in subsequent calls to other member functions). You can see the discussion here.
This means that we cannot simply disable all iterator debugging machinery if std::is_constant_evaluated() is true in these containers in general. Hopefully, a fix for Bug 48606: Clang rejects creation of struct with mutable member during constant evaluation can be forthcoming soon, in which case we will be able to move forward with a Clang-facing implementation.
If a Clang dev determines that the reported bug is not valid and their behavior is Standards-conforming, we should (1) fix the Standard to allow mutable in this context, or (2) investigate whether requested an additional built-in to detect whether we are in a "constant initialization" context vs. "constant evaluation" context could also help us mitigate the debug iterators issue.
NOTE: More discussion and clarification here. Any global string variable will end up using a dynamic initializer as constant initializers will be off-limits. This is because we don't have non-transient allocations and all constant initializers for string now do constant-time allocation (since SSO is turned off if is_constant_evaluated()). So, the motivating argument for keeping the debug iterator proxy machinery active during constant evaluation does not apply to string, but the same iterator logic is used by many of the containers. Only disabling the proxy iterator things for string would require duplication of a lot of code. Given that there are plans to update our debug iterator machinery in vNext anyway, the effort required to disable debug iterators during constant-time for string does not seem worthwhile.
🖥️ Testing (as of Jan 2021)
Since there have been a number of compiler issues discovered through the implementation of these features, we are going to enable testing the features' implementation in the internal test harness (via #ifdef MSVC_INTERNAL_TESTING) so as to discover and fix compiler issues more quickly.
As we are able to consume the compiler fixes in public previews, we will be able to enable full testing and remove the dependency on MSVC_INTERNAL_TESTING.
Current status:
P1004R2_constexpr_vector tests are passing internally with the updated compiler -- Enable constexpr vector internal tests #1690 enables the tests internally. When we consume the updated compiler with test fixes, we will be able to remove the defined(MSVC_INTERNAL_TESTING) entirely.
P1004R2_constexpr_vector_bool tests have all compiler bugs fixed internally, but there is a pre-existing issue in the debug iterator machinery that needs investigation before we can enable these tests.
P0980R1_constexpr_string tests have all compiler bugs fixed internally, and will already have defined(MSVC_INTERNAL_TESTING) throughout test code to enable these tests internally as soon as we merge.
Last updated 1/11/2022
📄 Relevant Papers
constexprContainersconstexpr std::stringconstexpr std::vector🚧 Status
The various papers involved in this broader feature are in various stages of completion:
🎈 Fixed Clang Bugs
Resolved in Clang 12
is_constant_evaluated()can incorrectly evaluate to true in the destructor of a non-constexpr variableResolved in Clang 13
-Wdangling-gslincorrect warns on return by value ofstd::string::iterator() -= n- workaround applied ⚠🐞 Active C1XX Bugs (MSVC Front-End)
constexprevaluation - not blocking for MSVC, found workaroundnext = &(*next)->s.p;-->U* temp = *next; next = &temp->s.p;constvariables during constant evaluation - not blocking 🟢clpermits copying into memory before object lifetimes have begun - not blocking 🟢constexprICE: binding a reference to a temporary emitsAssertion failed: Nerrors > 0- not blocking for MSVC, have workaround_INLINE_VAR constexpr _Fake_allocator _Fake_alloc{};constexprdynamic allocation doesn't properly understandstd::construct_at()"vector<Base*>, no workarounds in STL product/test code.std::{ranges::}construct_atwhen passed a string literal as argument"<memory>:std::construct_at(s, " ")did not evaluate to a constant #2467🎉 Fixed C1XX Bugs (MSVC Front-End)
constexprdestructors disallowed in literal types in parameters, return typesconstexprdoes not evaluate explicit dtor callconstexprdoes not respect lvalue reference to class temporariesconstexprtostd::stringin Back-Endusingconstexpr std::stringstd::construct_atrequires a copy constructorclerrors onconstexprarray ofstd::stringcl constexprtemporary passing issueprotectedstd::optionalwith RapidJSON which contains this code pattern).cldoes not make special member functions implicitlyconstexpr- not blocking for MSVC, have workaround from @cdacamar🦗 Active EDG Bugs
_wassertnotconstexpr- large portions of tests disabled for EDG 😢constexprfunction🥳 Fixed EDG Bugs
/BE- related tostd::destroyclIncorrectly rejects class with destructor for constant evaluation with/BEconstexpr std::stringindo_constexpr_std_construct_at__builtin_memcmpemits bogus errors with move-constructed strings and constexpr dynamic allocations📑 Compiler Approaches to
constexprDynamic Allocation(from @cdacamar in #1532) Note that [expr.const]/5 states that an expression E is a core constant expression unless the evaluation of E would [...] would evaluate one of the following:
std::allocator::allocate([allocator.members]), unless the allocated storage is deallocated within the evaluation of E;std::allocator::deallocate([allocator.members]), unless it deallocates a region of storage allocated within the evaluation of E;So, the expression
::operator newis not anewexpression, it is a function call to a globaloperator new()which is not aconstexprfunction.::operator newin aconstexprfunction if it is reached transitively from an evaluation ofstd::allocator::allocate.std::allocator::allocate,std::allocator::deallocate, but does not allow::operator new.::operator new, but we choose to have the EDG logical paths mirror those for MSVC so they work in tandem.Development notes, preserved for history
👣 Next Steps (as of Jan 2021)
mutable, but Clang currently does not allow this due to this bug.vectorvariables can exist, we need to enable situations where a variable is constant initialized (sostd::is_constant_evaluated()evaluates totruein the constructor), but not necessarily constant evaluated (sostd::is_constant_evaluated()evaluates tofalsein subsequent calls to other member functions). You can see the discussion here.std::is_constant_evaluated()istruein these containers in general. Hopefully, a fix for Bug 48606: Clang rejects creation of struct with mutable member during constant evaluation can be forthcoming soon, in which case we will be able to move forward with a Clang-facing implementation.mutablein this context, or (2) investigate whether requested an additional built-in to detect whether we are in a "constant initialization" context vs. "constant evaluation" context could also help us mitigate the debug iterators issue.stringvariable will end up using a dynamic initializer as constant initializers will be off-limits. This is because we don't have non-transient allocations and all constant initializers forstringnow do constant-time allocation (since SSO is turned off ifis_constant_evaluated()). So, the motivating argument for keeping the debug iterator proxy machinery active during constant evaluation does not apply tostring, but the same iterator logic is used by many of the containers. Only disabling the proxy iterator things forstringwould require duplication of a lot of code. Given that there are plans to update our debug iterator machinery in vNext anyway, the effort required to disable debug iterators during constant-time forstringdoes not seem worthwhile.🖥️ Testing (as of Jan 2021)
#ifdef MSVC_INTERNAL_TESTING) so as to discover and fix compiler issues more quickly.MSVC_INTERNAL_TESTING.P1004R2_constexpr_vectortests are passing internally with the updated compiler -- Enable constexpr vector internal tests #1690 enables the tests internally. When we consume the updated compiler with test fixes, we will be able to remove thedefined(MSVC_INTERNAL_TESTING)entirely.P1004R2_constexpr_vector_booltests have all compiler bugs fixed internally, but there is a pre-existing issue in the debug iterator machinery that needs investigation before we can enable these tests.P0980R1_constexpr_stringtests have all compiler bugs fixed internally, and will already havedefined(MSVC_INTERNAL_TESTING)throughout test code to enable these tests internally as soon as we merge.