[clang] [clang] Turn -Wenum-constexpr-conversion into a hard error (PR #102364)
Carlos Galvez via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 8 11:04:05 PDT 2024
https://github.com/carlosgalvezp updated https://github.com/llvm/llvm-project/pull/102364
>From 88f1a873d6c6ef06ad9a1847d098d65845cf1469 Mon Sep 17 00:00:00 2001
From: Carlos Galvez <carlosgalvezp at gmail.com>
Date: Tue, 6 Aug 2024 22:50:10 +0200
Subject: [PATCH 1/2] [clang] Turn -Wenum-constexpr-conversion into a hard
error
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
---
clang/docs/ReleaseNotes.rst | 3 ++
.../include/clang/Basic/DiagnosticASTKinds.td | 5 ++-
clang/lib/AST/ExprConstant.cpp | 6 ++--
clang/lib/AST/Interp/Interp.cpp | 4 +--
clang/test/AST/Interp/cxx11.cpp | 27 ++++++++++-----
.../enum-constexpr-conversion-system-header.h | 3 +-
.../SemaCXX/constant-expression-cxx11.cpp | 33 ++++++++++++-------
clang/test/SemaCXX/cxx2a-consteval.cpp | 3 +-
8 files changed, 53 insertions(+), 31 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d322da81723a5f..18e20d04298ae2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -49,6 +49,9 @@ C++ Specific Potentially Breaking Changes
few users and can be written as ``__is_same(__remove_cv(T), decltype(nullptr))``,
which GCC supports as well.
+- The warning `-Wenum-constexpr-conversion` has been upgraded into a hard
+ compiler error that cannot be suppressed, as required by the C++ Standard.
+
ABI Changes in This Version
---------------------------
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index a024f9b2a9f8c0..af53cf651e51ab 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -410,10 +410,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
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index d4b9095c7509b3..f2b8161f4a9014 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14406,14 +14406,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;
}
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 0f72b860ddad77..f2440f698b22b2 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -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;
}
diff --git a/clang/test/AST/Interp/cxx11.cpp b/clang/test/AST/Interp/cxx11.cpp
index cf2dfba079ef7e..481e3da9289efa 100644
--- a/clang/test/AST/Interp/cxx11.cpp
+++ b/clang/test/AST/Interp/cxx11.cpp
@@ -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 at -1 {{integer value 8 is outside the valid range of values [-8, 7] for the enumeration type 'E1'}}
+ // both-error at -1 {{constexpr variable 'x2' must be initialized by a constant expression}}
+ // both-note at -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 at -1 {{integer value -8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
+ // both-error at -1 {{constexpr variable 'x3' must be initialized by a constant expression}}
+ // both-note at -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 at -1 {{integer value 8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
+ // both-error at -1 {{constexpr variable 'x5' must be initialized by a constant expression}}
+ // both-note at -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 at -1 {{integer value 2048 is outside the valid range of values [-2048, 2047] for the enumeration type 'E3'}}
+ // both-error at -1 {{constexpr variable 'x10' must be initialized by a constant expression}}
+ // both-note at -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 at -1 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'E4'}}
+ // both-error at -1 {{constexpr variable 'x13' must be initialized by a constant expression}}
+ // both-note at -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 at -1 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'EEmpty'}}
+ // both-error at -1 {{constexpr variable 'x16' must be initialized by a constant expression}}
+ // both-note at -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 at -1 {{integer value 2147483648 is outside the valid range of values [-2147483648, 2147483647] for the enumeration type 'EMaxInt'}}
+ // both-error at -1 {{constexpr variable 'x20' must be initialized by a constant expression}}
+ // both-note at -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 at -1 {{constexpr variable 'max' must be initialized by a constant expression}}
+ // both-note at -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 {
diff --git a/clang/test/SemaCXX/Inputs/enum-constexpr-conversion-system-header.h b/clang/test/SemaCXX/Inputs/enum-constexpr-conversion-system-header.h
index 0850f3405eed3a..7d35d5b71d1dfe 100644
--- a/clang/test/SemaCXX/Inputs/enum-constexpr-conversion-system-header.h
+++ b/clang/test/SemaCXX/Inputs/enum-constexpr-conversion-system-header.h
@@ -10,7 +10,8 @@ enum SystemEnum
void testValueInRangeOfEnumerationValuesInSystemHeader()
{
constexpr SystemEnum x1 = static_cast<SystemEnum>(123);
- // expected-error at -1 {{integer value 123 is outside the valid range of values [0, 1] for the enumeration type 'SystemEnum'}}
+ // expected-error at -1 {{constexpr variable 'x1' must be initialized by a constant expression}}
+ // expected-note at -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
}
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 6df8a4740d6ccc..d888887bd8c6f3 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -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 at -1 {{integer value 8 is outside the valid range of values [-8, 7] for the enumeration type 'E1'}}
+ // expected-error at -1 {{constexpr variable 'x2' must be initialized by a constant expression}}
+ // expected-note at -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 at -1 {{integer value -8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
+ // expected-error at -1 {{constexpr variable 'x3' must be initialized by a constant expression}}
+ // expected-note at -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 at -1 {{integer value 8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
+ // expected-error at -1 {{constexpr variable 'x5' must be initialized by a constant expression}}
+ // expected-note at -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 at -1 {{integer value 2048 is outside the valid range of values [-2048, 2047] for the enumeration type 'E3'}}
+ // expected-error at -1 {{constexpr variable 'x10' must be initialized by a constant expression}}
+ // expected-note at -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 at -1 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'E4'}}
+ // expected-error at -1 {{constexpr variable 'x13' must be initialized by a constant expression}}
+ // expected-note at -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 at -1 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'EEmpty'}}
+ // expected-error at -1 {{constexpr variable 'x16' must be initialized by a constant expression}}
+ // expected-note at -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 at -1 {{integer value 2147483648 is outside the valid range of values [-2147483648, 2147483647] for the enumeration type 'EMaxInt'}}
+ // expected-error at -1 {{constexpr variable 'x20' must be initialized by a constant expression}}
+ // expected-note at -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 at -1 {{integer value 123 is outside the valid range of values [0, 1] for the enumeration type 'SystemEnum'}}
+ // expected-error at -1 {{constexpr variable 'system_enum' must be initialized by a constant expression}}
+ // expected-note at -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 at -1 {{constexpr variable 'max' must be initialized by a constant expression}}
+ // cxx11-note at -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 at -1 {{integer value -1 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
+// expected-error at -1 {{constexpr variable 'GlobalInitCE' must be initialized by a constant expression}}
+// expected-note at -2 {{integer value -1 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp
index ba80e57f814244..6b0609a26c5882 100644
--- a/clang/test/SemaCXX/cxx2a-consteval.cpp
+++ b/clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -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 at -1 {{integer value -1 is outside the valid range of values [0, 1] for the enumeration type 'E'}}
+// expected-note at -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 at -1 {{call to consteval function 'GH50055::testDefaultArgForParam' is not a constant expression}}
}
}
>From d854f012dc955158949d39c15e8ea44c825549ed Mon Sep 17 00:00:00 2001
From: Carlos Galvez <carlosgalvezp at gmail.com>
Date: Thu, 8 Aug 2024 20:03:53 +0200
Subject: [PATCH 2/2] Improve release notes
---
clang/docs/ReleaseNotes.rst | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 18e20d04298ae2..32f159f2b0f35b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -49,8 +49,21 @@ C++ Specific Potentially Breaking Changes
few users and can be written as ``__is_same(__remove_cv(T), decltype(nullptr))``,
which GCC supports as well.
-- The warning `-Wenum-constexpr-conversion` has been upgraded into a hard
- compiler error that cannot be suppressed, as required by the C++ Standard.
+- 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
---------------------------
@@ -122,6 +135,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
--------------------------
More information about the cfe-commits
mailing list