Skip to content

Commit 8de5137

Browse files
committed
[Clang] Tighten restrictions on enum out of range diagnostic to avoid constant initialization
The restrictions added in D131704 were not sufficient to avoid all non-constant expression contexts. In particular constant initialization cases. We need to check EvaluatingDecl to detect if the variable we are initializing is constexpr or not. At this point it looks like this is the remaining case affecting various projects with this diagnostic. Differential Revision: https://reviews.llvm.org/D131874
1 parent aa41fe6 commit 8de5137

File tree

3 files changed

+44
-5
lines changed

3 files changed

+44
-5
lines changed

clang/lib/AST/ExprConstant.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13536,6 +13536,18 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
1353613536
if (Info.Ctx.getLangOpts().CPlusPlus && Info.InConstantContext &&
1353713537
Info.EvalMode == EvalInfo::EM_ConstantExpression &&
1353813538
DestType->isEnumeralType()) {
13539+
13540+
bool ConstexprVar = true;
13541+
13542+
// We know if we are here that we are in a context that we might require
13543+
// a constant expression or a context that requires a constant
13544+
// value. But if we are initializing a value we don't know if it is a
13545+
// constexpr variable or not. We can check the EvaluatingDecl to determine
13546+
// if it constexpr or not. If not then we don't want to emit a diagnostic.
13547+
if (const auto *VD = dyn_cast_or_null<VarDecl>(
13548+
Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()))
13549+
ConstexprVar = VD->isConstexpr();
13550+
1353913551
const EnumType *ET = dyn_cast<EnumType>(DestType.getCanonicalType());
1354013552
const EnumDecl *ED = ET->getDecl();
1354113553
// Check that the value is within the range of the enumeration values.
@@ -13555,13 +13567,14 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
1355513567
ED->getValueRange(Max, Min);
1355613568
--Max;
1355713569

13558-
if (ED->getNumNegativeBits() &&
13570+
if (ED->getNumNegativeBits() && ConstexprVar &&
1355913571
(Max.slt(Result.getInt().getSExtValue()) ||
1356013572
Min.sgt(Result.getInt().getSExtValue())))
13561-
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
13562-
diag::warn_constexpr_unscoped_enum_out_of_range)
13563-
<< llvm::toString(Result.getInt(),10) << Min.getSExtValue() << Max.getSExtValue();
13564-
else if (!ED->getNumNegativeBits() &&
13573+
Info.Ctx.getDiagnostics().Report(
13574+
E->getExprLoc(), diag::warn_constexpr_unscoped_enum_out_of_range)
13575+
<< llvm::toString(Result.getInt(), 10) << Min.getSExtValue()
13576+
<< Max.getSExtValue();
13577+
else if (!ED->getNumNegativeBits() && ConstexprVar &&
1356513578
Max.ult(Result.getInt().getZExtValue()))
1356613579
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
1356713580
diag::warn_constexpr_unscoped_enum_out_of_range)

clang/test/SemaCXX/constant-expression-cxx11.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2419,6 +2419,13 @@ enum class EScoped {escoped1=-4, escoped2=4};
24192419

24202420
enum EMaxInt {emaxint1=-1, emaxint2=__INT_MAX__};
24212421

2422+
enum NumberType {};
2423+
2424+
E2 testDefaultArgForParam(E2 e2Param = (E2)-1) { // ok, not a constant expression context
2425+
E2 e2LocalInit = e2Param; // ok, not a constant expression context
2426+
return e2LocalInit;
2427+
}
2428+
24222429
void testValueInRangeOfEnumerationValues() {
24232430
constexpr E1 x1 = static_cast<E1>(-8);
24242431
constexpr E1 x2 = static_cast<E1>(8);
@@ -2454,6 +2461,8 @@ void testValueInRangeOfEnumerationValues() {
24542461
constexpr EMaxInt x19 = static_cast<EMaxInt>(__INT_MAX__-1);
24552462
constexpr EMaxInt x20 = static_cast<EMaxInt>((long)__INT_MAX__+1);
24562463
// expected-error@-1 {{integer value 2147483648 is outside the valid range of values [-2147483648, 2147483647] for this enumeration type}}
2464+
2465+
const NumberType neg_one = (NumberType) ((NumberType) 0 - (NumberType) 1); // ok, not a constant expression context
24572466
}
24582467

24592468
enum SortOrder {
@@ -2470,3 +2479,8 @@ void A::f(SortOrder order) {
24702479
return;
24712480
}
24722481
}
2482+
2483+
GH50055::E2 GlobalInitNotCE1 = (GH50055::E2)-1; // ok, not a constant expression context
2484+
GH50055::E2 GlobalInitNotCE2 = GH50055::testDefaultArgForParam(); // ok, not a constant expression context
2485+
constexpr GH50055::E2 GlobalInitCE = (GH50055::E2)-1;
2486+
// expected-error@-1 {{integer value -1 is outside the valid range of values [0, 7] for this enumeration type}}

clang/test/SemaCXX/cxx2a-consteval.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,3 +865,15 @@ consteval int aConstevalFunction() { // expected-error {{consteval function neve
865865
}
866866

867867
} // namespace multiple_default_constructors
868+
869+
namespace GH50055 {
870+
enum E {e1=0, e2=1};
871+
consteval int testDefaultArgForParam(E eParam = (E)-1) {
872+
// expected-error@-1 {{integer value -1 is outside the valid range of values [0, 1] for this enumeration type}}
873+
return (int)eParam;
874+
}
875+
876+
int test() {
877+
return testDefaultArgForParam() + testDefaultArgForParam((E)1);
878+
}
879+
}

0 commit comments

Comments
 (0)