Index: clang/include/clang/Basic/DiagnosticASTKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticASTKinds.td +++ clang/include/clang/Basic/DiagnosticASTKinds.td @@ -366,6 +366,8 @@ "type %0 has unexpected layout">; def note_constexpr_unsupported_flexible_array : Note< "flexible array initialization is not yet supported">; +def note_constexpr_unscoped_enum_out_of_range : Note< + "store of value outside of the range of unscoped enum, valid values %0 to %1">; def err_experimental_clang_interp_failed : Error< "the experimental clang interpreter failed to evaluate an expression">; Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -13509,6 +13509,46 @@ return Info.Ctx.getTypeSize(DestType) == Info.Ctx.getTypeSize(SrcType); } + if (Info.Ctx.getLangOpts().CPlusPlus20) + if (const EnumType *ET = dyn_cast(DestType)) { + const EnumDecl *ED = ET->getDecl(); + // Check that the value is within the range of the enumeration values. + // + // This corressponds to [expr.static.cast]p10 which says: + // A value of integral or enumeration type can be explicitly converted + // to a complete enumeration type ... If the enumeration type does not + // have a fixed underlying type, the value is unchanged if the original + // value is within the range of the enumeration values ([dcl.enum]), and + // otherwise, the behavior is undefined. + // + // This was resolved as part of DR2338 which has CD5 status. + if (!ED->isFixed()) { + llvm::APInt Min; + llvm::APInt End; + + unsigned Bitwidth = Info.Ctx.getIntWidth(DestType); + unsigned NumNegativeBits = ED->getNumNegativeBits(); + unsigned NumPositiveBits = ED->getNumPositiveBits(); + + if (NumNegativeBits) { + unsigned NumBits = std::max(NumNegativeBits, NumPositiveBits + 1); + End = llvm::APInt(Bitwidth, 1) << (NumBits - 1); + Min = -End; + } else { + End = llvm::APInt(Bitwidth, 1) << NumPositiveBits; + Min = llvm::APInt::getZero(Bitwidth); + } + + if (NumNegativeBits && + (End.sle(Result.getInt()) || Min.sgt(Result.getInt()))) + CCEDiag(E, diag::note_constexpr_unscoped_enum_out_of_range) + << Min.getSExtValue() << (End.getSExtValue() - 1); + else if (!NumNegativeBits && End.ule(Result.getInt())) + CCEDiag(E, diag::note_constexpr_unscoped_enum_out_of_range) + << Min.getZExtValue() << (End.getZExtValue() - 1); + } + } + return Success(HandleIntToIntCast(Info, E, DestType, SrcType, Result.getInt()), E); } Index: clang/test/SemaCXX/constant-expression-cxx2a.cpp =================================================================== --- clang/test/SemaCXX/constant-expression-cxx2a.cpp +++ clang/test/SemaCXX/constant-expression-cxx2a.cpp @@ -1473,3 +1473,10 @@ } static_assert(g()); // expected-error {{constant expression}} expected-note {{in call}} } + +enum E { e1=-4, e2=4}; +void testValueInRangeOfEnumerationValues() { + constexpr E x1 = static_cast(8); // expected-error {{must be initialized by a constant expression}} + // expected-note@-1 {{store of value outside of the range of unscoped enum, valid values -8 to 7}} + constexpr E x2 = static_cast(-8); +}