Author: Carlos Galvez Date: 2024-08-14T20:51:45+02:00 New Revision: 2dec83cc8e21a72e8718b5b3f009a19d6634fad3
URL: https://github.com/llvm/llvm-project/commit/2dec83cc8e21a72e8718b5b3f009a19d6634fad3 DIFF: https://github.com/llvm/llvm-project/commit/2dec83cc8e21a72e8718b5b3f009a19d6634fad3.diff LOG: [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 Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticASTKinds.td clang/lib/AST/ExprConstant.cpp clang/lib/AST/Interp/Interp.cpp clang/test/AST/Interp/cxx11.cpp clang/test/SemaCXX/Inputs/enum-constexpr-conversion-system-header.h clang/test/SemaCXX/constant-expression-cxx11.cpp clang/test/SemaCXX/cxx2a-consteval.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9f8d6e7e5eec50..1541b0cbf4875c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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 -------------------------- diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index eb82e0159b56ed..f317c5ac44f32b 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -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 diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 4d2d05307a6de9..09edbb6641650a 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -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; } diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 94d613352ba227..a0571728570d3f 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@-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 { 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@-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 } 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@-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'}} 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@-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}} } } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits