I've been experimenting with different forms of UB in order to better understand the current compiler inadequacies using constexpr
evaluations to detect UB.
Note: There is normally no compiler requirement to emit diagnostics when UB occurs. However, this is not the case when executing compile time code such as consteval
functions as shown here. Even there, there is an exception for library code where compilers are not required to emit diagnostics for UB. The question here does not use library code and compilers should emit diagnostics when encountering UB executing code at compile time.
I ran across an odd situation where modifying the underlying memory of an const int
in automatic storage (aka stack) results in no warnings with CLANG, GCC, and MSVC but when evaluated in a constexpr
function CLANG and GCC elicit the expected error while MSVC gives no error.
The function being evaluated casts a const int to a non const through it's address to attempt to change it's value from 1 to 2. Afterwards, the const value is added to that returned from a function called with a const int&
that simply returns the argument value.
This is all UB, of course. However, all three compilers happily compile and run when not in a constexpr
function. While UB, they are not required to emit diagnostics. And they interpret the result as the original const value when the variable is used directly but as the modified value when accessed through a reference.
But when running in compile time code, GCC and CLANG identify the UB as, for example:
modification of object of const-qualified type 'const int' is not allowed in a constant expression
MSVC produces no error or warning.
Since this uses no library code in the constexpr evaluation, I believe MSVC is in error not reporting the UB. Is this correct?
#include <iostream>
// un-comment out the next line to evaluate at runtime
// #define consteval
consteval int ret_arg(const int& v) { return v; }
consteval int f()
{
const int i{ 1 };
*const_cast<int*>(&i) = 2;
return i + ret_arg(i);
}
int main()
{
std::cout << f() << "\n";
}
Run time UB w/o compiler errors for all compilers can be seen by commenting the "#define consteval" line at the top.