llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
27.95k stars 11.53k forks source link

[clang] Range of empty enumeration without fixed underlying type is incorrect. #106815

Open keinflue opened 2 weeks ago

keinflue commented 2 weeks ago

The following currently compiles without diagnostic for C++11 and later:

enum E {};
constexpr auto x = static_cast<E>(1);

This should be ill-formed, clearly in C++17 and earlier, and also intended in C++20 and later.

According to [dcl.enum]/8 the set of values of E is only {0} and therefore the cast has undefined behavior.

In C++20 the wording of [dcl.enum]/8 changed and now isn't clear any more, but presumably there was no intent to change the behavior. See https://github.com/cplusplus/CWG/issues/604.

llvmbot commented 2 weeks ago

@llvm/issue-subscribers-clang-frontend

Author: None (keinflue)

The following currently compiles without diagnostic for C++11 and later: ``` enum E {}; constexpr auto x = static_cast<E>(1); ``` This should be ill-formed, clearly in C++17 and earlier, and also intended in C++20 and later. According to [[dcl.enum]/8](https://timsong-cpp.github.io/cppwp/n4659/dcl.enum#8) the set of values of `E` is only `{0}` and therefore the cast has undefined behavior. In C++20 the wording of [dcl.enum]/8 changed and now isn't clear any more, but presumably there was no intent to change the behavior. See https://github.com/cplusplus/CWG/issues/604.
keinflue commented 2 weeks ago

I just realized too late that the range of these enumerations was intentionally extended to include 1 with https://reviews.llvm.org/D130301 in commit https://github.com/llvm/llvm-project/commit/aea82d4551139ded0290afab739f0b367d055628 for Clang 15.

It seems to me that that commit was based on the new C++20 wording of [dcl.enum]/8 which seemingly doesn't permit width 0 (since integer types can't have width 0) and is furthermore ambiguous between the ranges [0, 1] and [-1, 0].

At least for C++17 the wording is clear that the range should be [0, 0].

cor3ntin commented 1 week ago

@shafik

shafik commented 1 week ago

This is CWG628, I think we should probably support this backwards as well since have empty objects is probably not desirable.

keinflue commented 1 week ago

@shafik

Even if the enumeration is enum E { A = 0 };, then its value range is still [0,0], at least in pre-P1236, post-CWG628 wording.

CWG628 is based on the comment https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3086.html#UK96 which also seems to state the intention for the range to include only 0.

If there is no agreement on the intended range, then this issue should probably be suspended until the new CWG 2932 is resolved.