Skip to content

Commit 3f62c7e

Browse files
Merge pull request #1433 from jkorous-apple/fix-array-new
PR45350: Handle unsized array CXXConstructExprs in constant evaluation
2 parents 2e659d4 + 779cde1 commit 3f62c7e

File tree

3 files changed

+55
-1
lines changed

3 files changed

+55
-1
lines changed

clang/lib/AST/ExprConstant.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8551,6 +8551,10 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
85518551
static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This,
85528552
APValue &Result, const InitListExpr *ILE,
85538553
QualType AllocType);
8554+
static bool EvaluateArrayNewConstructExpr(EvalInfo &Info, LValue &This,
8555+
APValue &Result,
8556+
const CXXConstructExpr *CCE,
8557+
QualType AllocType);
85548558

85558559
bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
85568560
if (!Info.getLangOpts().CPlusPlus2a)
@@ -8600,6 +8604,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
86008604

86018605
const Expr *Init = E->getInitializer();
86028606
const InitListExpr *ResizedArrayILE = nullptr;
8607+
const CXXConstructExpr *ResizedArrayCCE = nullptr;
86038608

86048609
QualType AllocType = E->getAllocatedType();
86058610
if (Optional<const Expr*> ArraySize = E->getArraySize()) {
@@ -8643,7 +8648,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
86438648
// -- the new-initializer is a braced-init-list and the number of
86448649
// array elements for which initializers are provided [...]
86458650
// exceeds the number of elements to initialize
8646-
if (Init) {
8651+
if (Init && !isa<CXXConstructExpr>(Init)) {
86478652
auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType());
86488653
assert(CAT && "unexpected type for array initializer");
86498654

@@ -8666,6 +8671,8 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
86668671
// special handling for this case when we initialize.
86678672
if (InitBound != AllocBound)
86688673
ResizedArrayILE = cast<InitListExpr>(Init);
8674+
} else if (Init) {
8675+
ResizedArrayCCE = cast<CXXConstructExpr>(Init);
86698676
}
86708677

86718678
AllocType = Info.Ctx.getConstantArrayType(AllocType, ArrayBound, nullptr,
@@ -8730,6 +8737,10 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
87308737
if (!EvaluateArrayNewInitList(Info, Result, *Val, ResizedArrayILE,
87318738
AllocType))
87328739
return false;
8740+
} else if (ResizedArrayCCE) {
8741+
if (!EvaluateArrayNewConstructExpr(Info, Result, *Val, ResizedArrayCCE,
8742+
AllocType))
8743+
return false;
87338744
} else if (Init) {
87348745
if (!EvaluateInPlace(*Val, Info, Result, Init))
87358746
return false;
@@ -9554,6 +9565,16 @@ static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This,
95549565
.VisitInitListExpr(ILE, AllocType);
95559566
}
95569567

9568+
static bool EvaluateArrayNewConstructExpr(EvalInfo &Info, LValue &This,
9569+
APValue &Result,
9570+
const CXXConstructExpr *CCE,
9571+
QualType AllocType) {
9572+
assert(CCE->isRValue() && CCE->getType()->isArrayType() &&
9573+
"not an array rvalue");
9574+
return ArrayExprEvaluator(Info, This, Result)
9575+
.VisitCXXConstructExpr(CCE, This, &Result, AllocType);
9576+
}
9577+
95579578
// Return true iff the given array filler may depend on the element index.
95589579
static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) {
95599580
// For now, just whitelist non-class value-initialization and initialization
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only %s
2+
3+
struct Bar {int a;};
4+
const Bar arr[2] = {{1}};
5+
6+
struct Foo {};
7+
8+
const int b = 2;
9+
10+
void foo(int a) {
11+
Foo *foo_array;
12+
foo_array = new Foo[arr[0].a];
13+
}

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,3 +1333,23 @@ namespace mutable_subobjects {
13331333
auto &zti = typeid(z.y);
13341334
static_assert(&zti == &typeid(Y));
13351335
}
1336+
1337+
namespace PR45350 {
1338+
int q;
1339+
struct V { int n; int *p = &n; constexpr ~V() { *p = *p * 10 + n; }};
1340+
constexpr int f(int n) {
1341+
int k = 0;
1342+
V *p = new V[n];
1343+
for (int i = 0; i != n; ++i) {
1344+
if (p[i].p != &p[i].n) return -1;
1345+
p[i].n = i;
1346+
p[i].p = &k;
1347+
}
1348+
delete[] p;
1349+
return k;
1350+
}
1351+
// [expr.delete]p6:
1352+
// In the case of an array, the elements will be destroyed in order of
1353+
// decreasing address
1354+
static_assert(f(6) == 543210);
1355+
}

0 commit comments

Comments
 (0)