mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 09:06:43 +00:00
[clang] Turn -Wenum-constexpr-conversion into a hard error (#102364)
The warning has been active for a few releases now, first only in user code, later in system headers, and finally as an error by default. Therefore, we believe it is now time to transition into a hard error, as required by the C++ Standard. The main affected C++ projects have by now fixed the error, or there's a pending patch for review that does it. Fixes #59036
This commit is contained in:
parent
9e87061404
commit
2dec83cc8e
@ -49,6 +49,22 @@ C++ Specific Potentially Breaking Changes
|
||||
few users and can be written as ``__is_same(__remove_cv(T), decltype(nullptr))``,
|
||||
which GCC supports as well.
|
||||
|
||||
- Clang will now correctly diagnose as ill-formed a constant expression where an
|
||||
enum without a fixed underlying type is set to a value outside the range of
|
||||
the enumeration's values.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
enum E { Zero, One, Two, Three, Four };
|
||||
constexpr E Val1 = (E)3; // Ok
|
||||
constexpr E Val2 = (E)7; // Ok
|
||||
constexpr E Val3 = (E)8; // Now ill-formed, out of the range [0, 7]
|
||||
constexpr E Val4 = (E)-1; // Now ill-formed, out of the range [0, 7]
|
||||
|
||||
Since Clang 16, it has been possible to suppress the diagnostic via
|
||||
`-Wno-enum-constexpr-conversion`, to allow for a transition period for users.
|
||||
Now, in Clang 20, **it is no longer possible to suppress the diagnostic**.
|
||||
|
||||
ABI Changes in This Version
|
||||
---------------------------
|
||||
|
||||
@ -143,6 +159,11 @@ Modified Compiler Flags
|
||||
Removed Compiler Flags
|
||||
-------------------------
|
||||
|
||||
- The compiler flag `-Wenum-constexpr-conversion` (and the `Wno-`, `Wno-error-`
|
||||
derivatives) is now removed, since it's no longer possible to suppress the
|
||||
diagnostic (see above). Users can expect an `unknown warning` diagnostic if
|
||||
it's still in use.
|
||||
|
||||
Attribute Changes in Clang
|
||||
--------------------------
|
||||
|
||||
|
@ -394,10 +394,9 @@ def warn_integer_constant_overflow : Warning<
|
||||
def warn_fixedpoint_constant_overflow : Warning<
|
||||
"overflow in expression; result is %0 with type %1">,
|
||||
InGroup<DiagGroup<"fixed-point-overflow">>;
|
||||
def warn_constexpr_unscoped_enum_out_of_range : Warning<
|
||||
def note_constexpr_unscoped_enum_out_of_range : Note<
|
||||
"integer value %0 is outside the valid range of values [%1, %2] for the "
|
||||
"enumeration type %3">, DefaultError, ShowInSystemHeader, ShowInSystemMacro,
|
||||
InGroup<DiagGroup<"enum-constexpr-conversion">>;
|
||||
"enumeration type %3">;
|
||||
|
||||
// This is a temporary diagnostic, and shall be removed once our
|
||||
// implementation is complete, and like the preceding constexpr notes belongs
|
||||
|
@ -14508,14 +14508,12 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
||||
if (ED->getNumNegativeBits() && ConstexprVar &&
|
||||
(Max.slt(Result.getInt().getSExtValue()) ||
|
||||
Min.sgt(Result.getInt().getSExtValue())))
|
||||
Info.Ctx.getDiagnostics().Report(
|
||||
E->getExprLoc(), diag::warn_constexpr_unscoped_enum_out_of_range)
|
||||
Info.CCEDiag(E, diag::note_constexpr_unscoped_enum_out_of_range)
|
||||
<< llvm::toString(Result.getInt(), 10) << Min.getSExtValue()
|
||||
<< Max.getSExtValue() << ED;
|
||||
else if (!ED->getNumNegativeBits() && ConstexprVar &&
|
||||
Max.ult(Result.getInt().getZExtValue()))
|
||||
Info.Ctx.getDiagnostics().Report(
|
||||
E->getExprLoc(), diag::warn_constexpr_unscoped_enum_out_of_range)
|
||||
Info.CCEDiag(E, diag::note_constexpr_unscoped_enum_out_of_range)
|
||||
<< llvm::toString(Result.getInt(), 10) << Min.getZExtValue()
|
||||
<< Max.getZExtValue() << ED;
|
||||
}
|
||||
|
@ -924,12 +924,12 @@ void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
|
||||
if (ED->getNumNegativeBits() &&
|
||||
(Max.slt(Value.getSExtValue()) || Min.sgt(Value.getSExtValue()))) {
|
||||
const SourceLocation &Loc = S.Current->getLocation(OpPC);
|
||||
S.report(Loc, diag::warn_constexpr_unscoped_enum_out_of_range)
|
||||
S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)
|
||||
<< llvm::toString(Value, 10) << Min.getSExtValue() << Max.getSExtValue()
|
||||
<< ED;
|
||||
} else if (!ED->getNumNegativeBits() && Max.ult(Value.getZExtValue())) {
|
||||
const SourceLocation &Loc = S.Current->getLocation(OpPC);
|
||||
S.report(Loc, diag::warn_constexpr_unscoped_enum_out_of_range)
|
||||
S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)
|
||||
<< llvm::toString(Value, 10) << Min.getZExtValue() << Max.getZExtValue()
|
||||
<< ED;
|
||||
}
|
||||
|
@ -93,49 +93,58 @@ E2 testDefaultArgForParam(E2 e2Param = (E2)-1) { // ok, not a constant expressio
|
||||
void testValueInRangeOfEnumerationValues() {
|
||||
constexpr E1 x1 = static_cast<E1>(-8);
|
||||
constexpr E1 x2 = static_cast<E1>(8);
|
||||
// both-error@-1 {{integer value 8 is outside the valid range of values [-8, 7] for the enumeration type 'E1'}}
|
||||
// both-error@-1 {{constexpr variable 'x2' must be initialized by a constant expression}}
|
||||
// both-note@-2 {{integer value 8 is outside the valid range of values [-8, 7] for the enumeration type 'E1'}}
|
||||
E1 x2b = static_cast<E1>(8); // ok, not a constant expression context
|
||||
|
||||
constexpr E2 x3 = static_cast<E2>(-8);
|
||||
// both-error@-1 {{integer value -8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
// both-error@-1 {{constexpr variable 'x3' must be initialized by a constant expression}}
|
||||
// both-note@-2 {{integer value -8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
constexpr E2 x4 = static_cast<E2>(0);
|
||||
constexpr E2 x5 = static_cast<E2>(8);
|
||||
// both-error@-1 {{integer value 8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
// both-error@-1 {{constexpr variable 'x5' must be initialized by a constant expression}}
|
||||
// both-note@-2 {{integer value 8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
|
||||
constexpr E3 x6 = static_cast<E3>(-2048);
|
||||
constexpr E3 x7 = static_cast<E3>(-8);
|
||||
constexpr E3 x8 = static_cast<E3>(0);
|
||||
constexpr E3 x9 = static_cast<E3>(8);
|
||||
constexpr E3 x10 = static_cast<E3>(2048);
|
||||
// both-error@-1 {{integer value 2048 is outside the valid range of values [-2048, 2047] for the enumeration type 'E3'}}
|
||||
// both-error@-1 {{constexpr variable 'x10' must be initialized by a constant expression}}
|
||||
// both-note@-2 {{integer value 2048 is outside the valid range of values [-2048, 2047] for the enumeration type 'E3'}}
|
||||
|
||||
constexpr E4 x11 = static_cast<E4>(0);
|
||||
constexpr E4 x12 = static_cast<E4>(1);
|
||||
constexpr E4 x13 = static_cast<E4>(2);
|
||||
// both-error@-1 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'E4'}}
|
||||
// both-error@-1 {{constexpr variable 'x13' must be initialized by a constant expression}}
|
||||
// both-note@-2 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'E4'}}
|
||||
|
||||
constexpr EEmpty x14 = static_cast<EEmpty>(0);
|
||||
constexpr EEmpty x15 = static_cast<EEmpty>(1);
|
||||
constexpr EEmpty x16 = static_cast<EEmpty>(2);
|
||||
// both-error@-1 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'EEmpty'}}
|
||||
// both-error@-1 {{constexpr variable 'x16' must be initialized by a constant expression}}
|
||||
// both-note@-2 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'EEmpty'}}
|
||||
|
||||
constexpr EFixed x17 = static_cast<EFixed>(100);
|
||||
constexpr EScoped x18 = static_cast<EScoped>(100);
|
||||
|
||||
constexpr EMaxInt x19 = static_cast<EMaxInt>(__INT_MAX__-1);
|
||||
constexpr EMaxInt x20 = static_cast<EMaxInt>((long)__INT_MAX__+1);
|
||||
// both-error@-1 {{integer value 2147483648 is outside the valid range of values [-2147483648, 2147483647] for the enumeration type 'EMaxInt'}}
|
||||
// both-error@-1 {{constexpr variable 'x20' must be initialized by a constant expression}}
|
||||
// both-note@-2 {{integer value 2147483648 is outside the valid range of values [-2147483648, 2147483647] for the enumeration type 'EMaxInt'}}
|
||||
|
||||
const NumberType neg_one = (NumberType) ((NumberType) 0 - (NumberType) 1); // ok, not a constant expression context
|
||||
}
|
||||
|
||||
template<class T, unsigned size> struct Bitfield {
|
||||
static constexpr T max = static_cast<T>((1 << size) - 1); // #enum
|
||||
static constexpr T max = static_cast<T>((1 << size) - 1);
|
||||
// both-error@-1 {{constexpr variable 'max' must be initialized by a constant expression}}
|
||||
// both-note@-2 {{integer value 15 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
};
|
||||
|
||||
void testValueInRangeOfEnumerationValuesViaTemplate() {
|
||||
Bitfield<E2, 3> good;
|
||||
Bitfield<E2, 4> bad; // both-error@#enum {{integer value 15 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
Bitfield<E2, 4> bad; // both-note {{in instantiation}}
|
||||
}
|
||||
|
||||
enum SortOrder {
|
||||
|
@ -10,7 +10,8 @@ enum SystemEnum
|
||||
void testValueInRangeOfEnumerationValuesInSystemHeader()
|
||||
{
|
||||
constexpr SystemEnum x1 = static_cast<SystemEnum>(123);
|
||||
// expected-error@-1 {{integer value 123 is outside the valid range of values [0, 1] for the enumeration type 'SystemEnum'}}
|
||||
// expected-error@-1 {{constexpr variable 'x1' must be initialized by a constant expression}}
|
||||
// expected-note@-2 {{integer value 123 is outside the valid range of values [0, 1] for the enumeration type 'SystemEnum'}}
|
||||
|
||||
const SystemEnum x2 = static_cast<SystemEnum>(123); // ok, not a constant expression context
|
||||
}
|
||||
|
@ -2460,52 +2460,62 @@ E2 testDefaultArgForParam(E2 e2Param = (E2)-1) { // ok, not a constant expressio
|
||||
void testValueInRangeOfEnumerationValues() {
|
||||
constexpr E1 x1 = static_cast<E1>(-8);
|
||||
constexpr E1 x2 = static_cast<E1>(8);
|
||||
// expected-error@-1 {{integer value 8 is outside the valid range of values [-8, 7] for the enumeration type 'E1'}}
|
||||
// expected-error@-1 {{constexpr variable 'x2' must be initialized by a constant expression}}
|
||||
// expected-note@-2 {{integer value 8 is outside the valid range of values [-8, 7] for the enumeration type 'E1'}}
|
||||
E1 x2b = static_cast<E1>(8); // ok, not a constant expression context
|
||||
|
||||
constexpr E2 x3 = static_cast<E2>(-8);
|
||||
// expected-error@-1 {{integer value -8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
// expected-error@-1 {{constexpr variable 'x3' must be initialized by a constant expression}}
|
||||
// expected-note@-2 {{integer value -8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
constexpr E2 x4 = static_cast<E2>(0);
|
||||
constexpr E2 x5 = static_cast<E2>(8);
|
||||
// expected-error@-1 {{integer value 8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
// expected-error@-1 {{constexpr variable 'x5' must be initialized by a constant expression}}
|
||||
// expected-note@-2 {{integer value 8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
|
||||
constexpr E3 x6 = static_cast<E3>(-2048);
|
||||
constexpr E3 x7 = static_cast<E3>(-8);
|
||||
constexpr E3 x8 = static_cast<E3>(0);
|
||||
constexpr E3 x9 = static_cast<E3>(8);
|
||||
constexpr E3 x10 = static_cast<E3>(2048);
|
||||
// expected-error@-1 {{integer value 2048 is outside the valid range of values [-2048, 2047] for the enumeration type 'E3'}}
|
||||
// expected-error@-1 {{constexpr variable 'x10' must be initialized by a constant expression}}
|
||||
// expected-note@-2 {{integer value 2048 is outside the valid range of values [-2048, 2047] for the enumeration type 'E3'}}
|
||||
|
||||
constexpr E4 x11 = static_cast<E4>(0);
|
||||
constexpr E4 x12 = static_cast<E4>(1);
|
||||
constexpr E4 x13 = static_cast<E4>(2);
|
||||
// expected-error@-1 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'E4'}}
|
||||
// expected-error@-1 {{constexpr variable 'x13' must be initialized by a constant expression}}
|
||||
// expected-note@-2 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'E4'}}
|
||||
|
||||
constexpr EEmpty x14 = static_cast<EEmpty>(0);
|
||||
constexpr EEmpty x15 = static_cast<EEmpty>(1);
|
||||
constexpr EEmpty x16 = static_cast<EEmpty>(2);
|
||||
// expected-error@-1 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'EEmpty'}}
|
||||
// expected-error@-1 {{constexpr variable 'x16' must be initialized by a constant expression}}
|
||||
// expected-note@-2 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'EEmpty'}}
|
||||
|
||||
constexpr EFixed x17 = static_cast<EFixed>(100);
|
||||
constexpr EScoped x18 = static_cast<EScoped>(100);
|
||||
|
||||
constexpr EMaxInt x19 = static_cast<EMaxInt>(__INT_MAX__-1);
|
||||
constexpr EMaxInt x20 = static_cast<EMaxInt>((long)__INT_MAX__+1);
|
||||
// expected-error@-1 {{integer value 2147483648 is outside the valid range of values [-2147483648, 2147483647] for the enumeration type 'EMaxInt'}}
|
||||
// expected-error@-1 {{constexpr variable 'x20' must be initialized by a constant expression}}
|
||||
// expected-note@-2 {{integer value 2147483648 is outside the valid range of values [-2147483648, 2147483647] for the enumeration type 'EMaxInt'}}
|
||||
|
||||
const NumberType neg_one = (NumberType) ((NumberType) 0 - (NumberType) 1); // ok, not a constant expression context
|
||||
|
||||
CONSTEXPR_CAST_TO_SYSTEM_ENUM_OUTSIDE_OF_RANGE;
|
||||
// expected-error@-1 {{integer value 123 is outside the valid range of values [0, 1] for the enumeration type 'SystemEnum'}}
|
||||
// expected-error@-1 {{constexpr variable 'system_enum' must be initialized by a constant expression}}
|
||||
// expected-note@-2 {{integer value 123 is outside the valid range of values [0, 1] for the enumeration type 'SystemEnum'}}
|
||||
}
|
||||
|
||||
template<class T, unsigned size> struct Bitfield {
|
||||
static constexpr T max = static_cast<T>((1 << size) - 1); // #enum
|
||||
static constexpr T max = static_cast<T>((1 << size) - 1);
|
||||
// cxx11-error@-1 {{constexpr variable 'max' must be initialized by a constant expression}}
|
||||
// cxx11-note@-2 {{integer value 15 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
};
|
||||
|
||||
void testValueInRangeOfEnumerationValuesViaTemplate() {
|
||||
Bitfield<E2, 3> good;
|
||||
Bitfield<E2, 4> bad; // cxx11-error@#enum {{integer value 15 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
Bitfield<E2, 4> bad; // cxx11-note {{in instantiation}}
|
||||
}
|
||||
|
||||
enum SortOrder {
|
||||
@ -2526,4 +2536,5 @@ void A::f(SortOrder order) {
|
||||
GH50055::E2 GlobalInitNotCE1 = (GH50055::E2)-1; // ok, not a constant expression context
|
||||
GH50055::E2 GlobalInitNotCE2 = GH50055::testDefaultArgForParam(); // ok, not a constant expression context
|
||||
constexpr GH50055::E2 GlobalInitCE = (GH50055::E2)-1;
|
||||
// expected-error@-1 {{integer value -1 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
// expected-error@-1 {{constexpr variable 'GlobalInitCE' must be initialized by a constant expression}}
|
||||
// expected-note@-2 {{integer value -1 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
|
||||
|
@ -920,12 +920,13 @@ consteval int aConstevalFunction() { // expected-error {{consteval function neve
|
||||
namespace GH50055 {
|
||||
enum E {e1=0, e2=1};
|
||||
consteval int testDefaultArgForParam(E eParam = (E)-1) {
|
||||
// expected-error@-1 {{integer value -1 is outside the valid range of values [0, 1] for the enumeration type 'E'}}
|
||||
// expected-note@-1 {{integer value -1 is outside the valid range of values [0, 1] for the enumeration type 'E'}}
|
||||
return (int)eParam;
|
||||
}
|
||||
|
||||
int test() {
|
||||
return testDefaultArgForParam() + testDefaultArgForParam((E)1);
|
||||
// expected-error@-1 {{call to consteval function 'GH50055::testDefaultArgForParam' is not a constant expression}}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user