diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 55c6edf6a57cc..fcdbfaf523d5b 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -15682,7 +15682,21 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { return Info.Ctx.getTypeSize(DestType) == Info.Ctx.getTypeSize(SrcType); } - if (Info.Ctx.getLangOpts().CPlusPlus && DestType->isEnumeralType()) { + if (Info.Ctx.getLangOpts().CPlusPlus && Info.InConstantContext && + Info.EvalMode == EvalInfo::EM_ConstantExpression && + DestType->isEnumeralType()) { + + bool ConstexprVar = true; + + // We know if we are here that we are in a context that we might require + // a constant expression or a context that requires a constant + // value. But if we are initializing a value we don't know if it is a + // constexpr variable or not. We can check the EvaluatingDecl to determine + // if it constexpr or not. If not then we don't want to emit a diagnostic. + if (const auto *VD = dyn_cast_or_null( + Info.EvaluatingDecl.dyn_cast())) + ConstexprVar = VD->isConstexpr(); + const EnumType *ET = dyn_cast(DestType.getCanonicalType()); const EnumDecl *ED = ET->getDecl(); // Check that the value is within the range of the enumeration values. @@ -15702,13 +15716,13 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { ED->getValueRange(Max, Min); --Max; - if (ED->getNumNegativeBits() && + if (ED->getNumNegativeBits() && ConstexprVar && (Max.slt(Result.getInt().getSExtValue()) || Min.sgt(Result.getInt().getSExtValue()))) 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() && + else if (!ED->getNumNegativeBits() && ConstexprVar && Max.ult(Result.getInt().getZExtValue())) Info.CCEDiag(E, diag::note_constexpr_unscoped_enum_out_of_range) << llvm::toString(Result.getInt(), 10) << Min.getZExtValue() diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index 935409131e18f..040a4e5ead671 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -2514,9 +2514,6 @@ void testValueInRangeOfEnumerationValues() { // 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(8); // ok, not a constant expression context - static_assert(static_cast(8), ""); - // expected-error@-1 {{static assertion expression is not an integral constant expression}} - // expected-note@-2 {{integer value 8 is outside the valid range of values [-8, 7] for the enumeration type 'E1'}} constexpr E2 x3 = static_cast(-8); // expected-error@-1 {{constexpr variable 'x3' must be initialized by a constant expression}} @@ -2555,10 +2552,6 @@ void testValueInRangeOfEnumerationValues() { // 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 NumberType neg_one_constexpr = neg_one; - // expected-error@-1 {{constexpr variable 'neg_one_constexpr' must be initialized by a constant expression}} - // expected-note@-2 {{initializer of 'neg_one' is not a constant expression}} - // expected-note@-4 {{declared here}} CONSTEXPR_CAST_TO_SYSTEM_ENUM_OUTSIDE_OF_RANGE; // expected-error@-1 {{constexpr variable 'system_enum' must be initialized by a constant expression}}