@@ -456,49 +456,7 @@ namespace {
456
456
void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E,
457
457
const APSInt &N);
458
458
/// Add N to the address of this subobject.
459
- void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N) {
460
- if (Invalid || !N) return;
461
- uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue();
462
- if (isMostDerivedAnUnsizedArray()) {
463
- diagnoseUnsizedArrayPointerArithmetic(Info, E);
464
- // Can't verify -- trust that the user is doing the right thing (or if
465
- // not, trust that the caller will catch the bad behavior).
466
- // FIXME: Should we reject if this overflows, at least?
467
- Entries.back() = PathEntry::ArrayIndex(
468
- Entries.back().getAsArrayIndex() + TruncatedN);
469
- return;
470
- }
471
-
472
- // [expr.add]p4: For the purposes of these operators, a pointer to a
473
- // nonarray object behaves the same as a pointer to the first element of
474
- // an array of length one with the type of the object as its element type.
475
- bool IsArray = MostDerivedPathLength == Entries.size() &&
476
- MostDerivedIsArrayElement;
477
- uint64_t ArrayIndex = IsArray ? Entries.back().getAsArrayIndex()
478
- : (uint64_t)IsOnePastTheEnd;
479
- uint64_t ArraySize =
480
- IsArray ? getMostDerivedArraySize() : (uint64_t)1;
481
-
482
- if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) {
483
- // Calculate the actual index in a wide enough type, so we can include
484
- // it in the note.
485
- N = N.extend(std::max<unsigned>(N.getBitWidth() + 1, 65));
486
- (llvm::APInt&)N += ArrayIndex;
487
- assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index");
488
- diagnosePointerArithmetic(Info, E, N);
489
- setInvalid();
490
- return;
491
- }
492
-
493
- ArrayIndex += TruncatedN;
494
- assert(ArrayIndex <= ArraySize &&
495
- "bounds check succeeded for out-of-bounds index");
496
-
497
- if (IsArray)
498
- Entries.back() = PathEntry::ArrayIndex(ArrayIndex);
499
- else
500
- IsOnePastTheEnd = (ArrayIndex != 0);
501
- }
459
+ void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N, const LValue &LV);
502
460
};
503
461
504
462
/// A scope at the end of which an object can need to be destroyed.
@@ -1795,7 +1753,7 @@ namespace {
1795
1753
Offset = CharUnits::fromQuantity(Offset64 + ElemSize64 * Index64);
1796
1754
1797
1755
if (checkNullPointer(Info, E, CSK_ArrayIndex))
1798
- Designator.adjustIndex(Info, E, Index);
1756
+ Designator.adjustIndex(Info, E, Index, *this );
1799
1757
clearIsNullPointer();
1800
1758
}
1801
1759
void adjustOffset(CharUnits N) {
@@ -1903,6 +1861,54 @@ namespace {
1903
1861
}
1904
1862
}
1905
1863
1864
+ void SubobjectDesignator::adjustIndex(EvalInfo &Info, const Expr *E, APSInt N,
1865
+ const LValue &LV) {
1866
+ if (Invalid || !N)
1867
+ return;
1868
+ uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue();
1869
+ if (isMostDerivedAnUnsizedArray()) {
1870
+ diagnoseUnsizedArrayPointerArithmetic(Info, E);
1871
+ // Can't verify -- trust that the user is doing the right thing (or if
1872
+ // not, trust that the caller will catch the bad behavior).
1873
+ // FIXME: Should we reject if this overflows, at least?
1874
+ Entries.back() =
1875
+ PathEntry::ArrayIndex(Entries.back().getAsArrayIndex() + TruncatedN);
1876
+ return;
1877
+ }
1878
+
1879
+ // [expr.add]p4: For the purposes of these operators, a pointer to a
1880
+ // nonarray object behaves the same as a pointer to the first element of
1881
+ // an array of length one with the type of the object as its element type.
1882
+ bool IsArray =
1883
+ MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement;
1884
+ uint64_t ArrayIndex =
1885
+ IsArray ? Entries.back().getAsArrayIndex() : (uint64_t)IsOnePastTheEnd;
1886
+ uint64_t ArraySize = IsArray ? getMostDerivedArraySize() : (uint64_t)1;
1887
+
1888
+ if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) {
1889
+ if (!Info.checkingPotentialConstantExpression() ||
1890
+ !LV.AllowConstexprUnknown) {
1891
+ // Calculate the actual index in a wide enough type, so we can include
1892
+ // it in the note.
1893
+ N = N.extend(std::max<unsigned>(N.getBitWidth() + 1, 65));
1894
+ (llvm::APInt &)N += ArrayIndex;
1895
+ assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index");
1896
+ diagnosePointerArithmetic(Info, E, N);
1897
+ }
1898
+ setInvalid();
1899
+ return;
1900
+ }
1901
+
1902
+ ArrayIndex += TruncatedN;
1903
+ assert(ArrayIndex <= ArraySize &&
1904
+ "bounds check succeeded for out-of-bounds index");
1905
+
1906
+ if (IsArray)
1907
+ Entries.back() = PathEntry::ArrayIndex(ArrayIndex);
1908
+ else
1909
+ IsOnePastTheEnd = (ArrayIndex != 0);
1910
+ }
1911
+
1906
1912
static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E);
1907
1913
static bool EvaluateInPlace(APValue &Result, EvalInfo &Info,
1908
1914
const LValue &This, const Expr *E,
@@ -5144,12 +5150,18 @@ static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
5144
5150
if (const PointerType *PT = TargetQT->getAs<PointerType>())
5145
5151
TargetQT = PT->getPointeeType();
5146
5152
5147
- // Check this cast lands within the final derived-to-base subobject path.
5148
- if (D.MostDerivedPathLength + E->path_size() > D.Entries.size()) {
5149
- Info.CCEDiag(E, diag::note_constexpr_invalid_downcast)
5150
- << D.MostDerivedType << TargetQT;
5153
+ auto InvalidCast = [&]() {
5154
+ if (!Info.checkingPotentialConstantExpression() ||
5155
+ !Result.AllowConstexprUnknown) {
5156
+ Info.CCEDiag(E, diag::note_constexpr_invalid_downcast)
5157
+ << D.MostDerivedType << TargetQT;
5158
+ }
5151
5159
return false;
5152
- }
5160
+ };
5161
+
5162
+ // Check this cast lands within the final derived-to-base subobject path.
5163
+ if (D.MostDerivedPathLength + E->path_size() > D.Entries.size())
5164
+ return InvalidCast();
5153
5165
5154
5166
// Check the type of the final cast. We don't need to check the path,
5155
5167
// since a cast can only be formed if the path is unique.
@@ -5160,11 +5172,8 @@ static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
5160
5172
FinalType = D.MostDerivedType->getAsCXXRecordDecl();
5161
5173
else
5162
5174
FinalType = getAsBaseClass(D.Entries[NewEntriesSize - 1]);
5163
- if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl()) {
5164
- Info.CCEDiag(E, diag::note_constexpr_invalid_downcast)
5165
- << D.MostDerivedType << TargetQT;
5166
- return false;
5167
- }
5175
+ if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl())
5176
+ return InvalidCast();
5168
5177
5169
5178
// Truncate the lvalue to the appropriate derived class.
5170
5179
return CastToDerivedClass(Info, E, Result, TargetType, NewEntriesSize);
@@ -6165,12 +6174,15 @@ static bool checkDynamicType(EvalInfo &Info, const Expr *E, const LValue &This,
6165
6174
} else if (Polymorphic) {
6166
6175
// Conservatively refuse to perform a polymorphic operation if we would
6167
6176
// not be able to read a notional 'vptr' value.
6168
- APValue Val;
6169
- This.moveInto(Val);
6170
- QualType StarThisType =
6171
- Info.Ctx.getLValueReferenceType(This.Designator.getType(Info.Ctx));
6172
- Info.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
6173
- << AK << Val.getAsString(Info.Ctx, StarThisType);
6177
+ if (!Info.checkingPotentialConstantExpression() ||
6178
+ !This.AllowConstexprUnknown) {
6179
+ APValue Val;
6180
+ This.moveInto(Val);
6181
+ QualType StarThisType =
6182
+ Info.Ctx.getLValueReferenceType(This.Designator.getType(Info.Ctx));
6183
+ Info.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
6184
+ << AK << Val.getAsString(Info.Ctx, StarThisType);
6185
+ }
6174
6186
return false;
6175
6187
}
6176
6188
return true;
@@ -15075,6 +15087,11 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
15075
15087
// Reject differing bases from the normal codepath; we special-case
15076
15088
// comparisons to null.
15077
15089
if (!HasSameBase(LHSValue, RHSValue)) {
15090
+ // Bail out early if we're checking potential constant expression.
15091
+ // Otherwise, prefer to diagnose other issues.
15092
+ if (Info.checkingPotentialConstantExpression() &&
15093
+ (LHSValue.AllowConstexprUnknown || RHSValue.AllowConstexprUnknown))
15094
+ return false;
15078
15095
auto DiagComparison = [&] (unsigned DiagID, bool Reversed = false) {
15079
15096
std::string LHS = LHSValue.toString(Info.Ctx, E->getLHS()->getType());
15080
15097
std::string RHS = RHSValue.toString(Info.Ctx, E->getRHS()->getType());
@@ -15395,6 +15412,10 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
15395
15412
// Reject differing bases from the normal codepath; we special-case
15396
15413
// comparisons to null.
15397
15414
if (!HasSameBase(LHSValue, RHSValue)) {
15415
+ if (Info.checkingPotentialConstantExpression() &&
15416
+ (LHSValue.AllowConstexprUnknown || RHSValue.AllowConstexprUnknown))
15417
+ return false;
15418
+
15398
15419
const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr *>();
15399
15420
const Expr *RHSExpr = RHSValue.Base.dyn_cast<const Expr *>();
15400
15421
0 commit comments