Open languagelawyer opened 4 years ago
- there is implementation divergence: GCC and MSVC accept the code (however, their constexpr evaluator is known to be not strict enough in more unambiguous cases)
GCC and MSVC (and also EDG, which likewise doesn't diagnose this even in strict mode) apparently don't implement the "comparison with unspecified result is not constant" rule in general, not only in this case. For example, they all accept:
struct Base { int i; }; struct S : Base { int j; }; constexpr S s {}; static_assert(&s.i < &s.j, "");
... even though the rules are clear that this comparison is non-constant because its result is unspecified.
don't you think this worths a core issue?
I've mailed the core reflector (and CC'd you). We'll see how that goes.
Well, ok. In C++14, "pointers to objects" could prolly only mean "pointers to object types", but in C++17/C++20, "pointers to objects" could be read as meaning pointer values [1].
Given that:
don't you think this worths a core issue?
[1] https://timsong-cpp.github.io/cppwp/n4659/basic.compound#def:pointer_to
I don't see where [expr.rel] says that pointers must be pointers to object types.
It says "pointers to objects", but this means pointer values, not types: pointers need to point to objects, but not to functions. Cast to pointer to void doesn't change a pointer value.
After N3624, the rule for when one pointer compares greater than another is defined only for pointer to object types. 'void*' is not a pointer to object type because 'void' is not an object type, so it is never the case that one pointer to void compares greater than another; consequently, unequal pointers to void always fall through to the "Otherwise, the result of each of the [relational comparison] operators is unspecified." wording.
So while N3624 did remove the explicit handling of 'void', it didn't change the behavior of relational comparisons of unequal 'void' pointers: their results are still unspecified.
@llvm/issue-subscribers-clang-frontend
Extended Description
About the following program:
struct S { int i; int j; };
constexpr S s {};
static_assert(&s.i < (void*)&s.j);
clang in C++14, C++17 and C++2a modes says that the expression in static_assert is not a constant expression:
$ clang++ prog.cc -std=c++14 prog.cc:9:15: error: static_assert expression is not an integral constant expression static_assert(&s.i < (void)&s.j, ""); ^
~~~~~ prog.cc:9:20: note: comparison between unequal pointers to void has unspecified result static_assert(&s.i < (void)&s.j, ""); ^(https://wandbox.org/permlink/IXwrV0M75To3wUUB)
However, the special handling of pointers to void has been removed from [expr.rel] by http://wg21.link/n3624 (applied in [1]), so the result of comparing unequal pointers to void is no longer unspecified, so the expression is a constant expression.
[1] https://github.com/cplusplus/draft/commit/89281b5795f47b9196c37ce8008b4873a76e90ef#diff-64a673ab7a20068092a4cf86b36f4334L3647-L3650