Skip to content

Commit 9a7eda1

Browse files
committed
PR45350: Handle unsized array CXXConstructExprs in constant evaluation
of array new expressions with runtime bound.
1 parent 31a1d85 commit 9a7eda1

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

clang/lib/AST/ExprConstant.cpp

+22-1
Original file line numberDiff line numberDiff line change
@@ -8677,6 +8677,10 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
86778677
static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This,
86788678
APValue &Result, const InitListExpr *ILE,
86798679
QualType AllocType);
8680+
static bool EvaluateArrayNewConstructExpr(EvalInfo &Info, LValue &This,
8681+
APValue &Result,
8682+
const CXXConstructExpr *CCE,
8683+
QualType AllocType);
86808684

86818685
bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
86828686
if (!Info.getLangOpts().CPlusPlus2a)
@@ -8726,6 +8730,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
87268730

87278731
const Expr *Init = E->getInitializer();
87288732
const InitListExpr *ResizedArrayILE = nullptr;
8733+
const CXXConstructExpr *ResizedArrayCCE = nullptr;
87298734

87308735
QualType AllocType = E->getAllocatedType();
87318736
if (Optional<const Expr*> ArraySize = E->getArraySize()) {
@@ -8769,7 +8774,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
87698774
// -- the new-initializer is a braced-init-list and the number of
87708775
// array elements for which initializers are provided [...]
87718776
// exceeds the number of elements to initialize
8772-
if (Init) {
8777+
if (Init && !isa<CXXConstructExpr>(Init)) {
87738778
auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType());
87748779
assert(CAT && "unexpected type for array initializer");
87758780

@@ -8792,6 +8797,8 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
87928797
// special handling for this case when we initialize.
87938798
if (InitBound != AllocBound)
87948799
ResizedArrayILE = cast<InitListExpr>(Init);
8800+
} else if (Init) {
8801+
ResizedArrayCCE = cast<CXXConstructExpr>(Init);
87958802
}
87968803

87978804
AllocType = Info.Ctx.getConstantArrayType(AllocType, ArrayBound, nullptr,
@@ -8856,6 +8863,10 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
88568863
if (!EvaluateArrayNewInitList(Info, Result, *Val, ResizedArrayILE,
88578864
AllocType))
88588865
return false;
8866+
} else if (ResizedArrayCCE) {
8867+
if (!EvaluateArrayNewConstructExpr(Info, Result, *Val, ResizedArrayCCE,
8868+
AllocType))
8869+
return false;
88598870
} else if (Init) {
88608871
if (!EvaluateInPlace(*Val, Info, Result, Init))
88618872
return false;
@@ -9683,6 +9694,16 @@ static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This,
96839694
.VisitInitListExpr(ILE, AllocType);
96849695
}
96859696

9697+
static bool EvaluateArrayNewConstructExpr(EvalInfo &Info, LValue &This,
9698+
APValue &Result,
9699+
const CXXConstructExpr *CCE,
9700+
QualType AllocType) {
9701+
assert(CCE->isRValue() && CCE->getType()->isArrayType() &&
9702+
"not an array rvalue");
9703+
return ArrayExprEvaluator(Info, This, Result)
9704+
.VisitCXXConstructExpr(CCE, This, &Result, AllocType);
9705+
}
9706+
96869707
// Return true iff the given array filler may depend on the element index.
96879708
static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) {
96889709
// For now, just whitelist non-class value-initialization and initialization

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

+20
Original file line numberDiff line numberDiff line change
@@ -1381,3 +1381,23 @@ namespace PR45133 {
13811381
constinit V v2 = X<2>();
13821382
constinit V v3 = X<3>(); // expected-error {{constant init}} expected-note {{constinit}} expected-note {{in call}}
13831383
}
1384+
1385+
namespace PR45350 {
1386+
int q;
1387+
struct V { int n; int *p = &n; constexpr ~V() { *p = *p * 10 + n; }};
1388+
constexpr int f(int n) {
1389+
int k = 0;
1390+
V *p = new V[n];
1391+
for (int i = 0; i != n; ++i) {
1392+
if (p[i].p != &p[i].n) return -1;
1393+
p[i].n = i;
1394+
p[i].p = &k;
1395+
}
1396+
delete[] p;
1397+
return k;
1398+
}
1399+
// [expr.delete]p6:
1400+
// In the case of an array, the elements will be destroyed in order of
1401+
// decreasing address
1402+
static_assert(f(6) == 543210);
1403+
}

0 commit comments

Comments
 (0)