diff options
author | Shafik Yaghmour <shafik.yaghmour@intel.com> | 2022-07-27 14:59:35 -0700 |
---|---|---|
committer | Shafik Yaghmour <shafik.yaghmour@intel.com> | 2022-07-27 14:59:35 -0700 |
commit | a3710589f285de0bb22ff92b1fc24df9411e986f (patch) | |
tree | 38a26f49798373c5cbcc68d2312d000a26fe0925 /clang/lib/AST/ExprConstant.cpp | |
parent | a35596675b75154d9af037d4d761f97b7707ad97 (diff) | |
download | llvm-a3710589f285de0bb22ff92b1fc24df9411e986f.zip llvm-a3710589f285de0bb22ff92b1fc24df9411e986f.tar.gz llvm-a3710589f285de0bb22ff92b1fc24df9411e986f.tar.bz2 |
[Clang] Diagnose ill-formed constant expression when setting a non fixed enum to a value outside the range of the enumeration values
DR2338 clarified that it was undefined behavior to set the value outside the
range of the enumerations values for an enum without a fixed underlying type.
We should diagnose this with a constant expression context.
Differential Revision: https://reviews.llvm.org/D130058
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 9d92c84..0f15859 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -13519,6 +13519,34 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { return Info.Ctx.getTypeSize(DestType) == Info.Ctx.getTypeSize(SrcType); } + if (const EnumType *ET = dyn_cast<EnumType>(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 Max; + + ED->getValueRange(Max, Min); + + if (ED->getNumNegativeBits() && + (Max.sle(Result.getInt()) || Min.sgt(Result.getInt()))) + CCEDiag(E, diag::note_constexpr_unscoped_enum_out_of_range) + << Result.getInt() << Min.getSExtValue() << Max.getSExtValue(); + else if (!ED->getNumNegativeBits() && Max.ule(Result.getInt())) + CCEDiag(E, diag::note_constexpr_unscoped_enum_out_of_range) + << Result.getInt() << Min.getZExtValue() << Max.getZExtValue(); + } + } + return Success(HandleIntToIntCast(Info, E, DestType, SrcType, Result.getInt()), E); } |