I'm using g++ for an embedded system, and as is common with such things, hardware addresses are provided as hex constants. I want to create pointers from them, using constexpr because they are known at compile time. Now the C++ Standard forbids reinterpret_cast<> or the equivalent in a constexpr so it can't be done directly, which is annoying but that's the Standard. However, with older versions of g++, one could solve this with the magic use of __builtin_constant_p() in a ternary expression. Thus: test.cpp: #define CONST(x) (__builtin_constant_p(x) ? x : x) constexpr void *phardware {CONST ((void *) 0x1000)}; (This is sufficient for a complete test program, BTW) This use appears to be documented, although it's not 100% clear. It's certainly very desirable. My cross-development system recently upgraded from 4.9.2 to 6.2.1 and the magic has stopped working. The loss of magic holds in other 6.x versions I've tried, but still works in clang 3.8.1 which is the latest version in my distro (Fedora 24) Compilation results: $ <4.9.2>-g++ -c -std=c++14 test.cpp $ $ <6.2.1>-g++ -c -std=c++14 test.cpp test.cpp:4:28: error: reinterpret_cast from integer to pointer constexpr void *phardware {CONST ((void *) 0x1000)}; ^~~~~~~~~~ test.cpp:2:45: note: in definition of macro 'CONST' #define CONST(x) (__builtin_constant_p(x) ? x : x) $ Has this behaviour changed deliberately? As I say, it is contrary to the Standard, but it would be disappointing to lose such a useful extension.
I can't reproduce this with GCC 6, but can with GCC 7: un.cc:3:55: error: value '4096' of type 'void*' is not a constant expression constexpr void *phardware {CONST ((void *) 0x1000)}; ^ and with trunk: un.cc:3:39: error: reinterpret_cast from integer to pointer constexpr void *phardware {CONST ((void *) 0x1000)}; ^~~~~~~~~~~~~~~ un.cc:1:45: note: in definition of macro 'CONST' #define CONST(x) (__builtin_constant_p(x) ? x : x) ^
This has nothing to do with __builtin_constant_p really. Just GCC started to rejecting: constexpr void *phardware {((void *) 0x1000)}; Starting in GCC 7; it was accepted before. What is interesting is the __builtin_constant_p makes clang accept it but that is a clang bug. >This use appears to be documented I don't think it was ever documented to be accepted this way but I could be wrong.
(In reply to steveren from comment #0) > Has this behaviour changed deliberately? Yes, because the standard forbids it. As Andrew said, the __builtin_constant_p part (and what the docs say about it) is irrelevant because the (void *) 0x1000 expression is what gives an error. > As I say, it is contrary to the > Standard, but it would be disappointing to lose such a useful extension. I think it would be better to add support to C++ for "pointer literals", I've been talking with a few people about proposing that for the standard. That would allow you to create constexpr pointers from literal integers, but still disallow arbitrary reinterpret casts between them. Closing as G++ is correct to disallow this.