PR13290: Constant-evaluation support for CXXConstructExprs which construct a

multidimensional array of class type. Also, preserve zero-initialization when
evaluating an initializer list for an array, in case the initializers refer to
later elements (which have preceding zero-initialization).

llvm-svn: 159904
This commit is contained in:
Richard Smith 2012-07-07 22:48:24 +00:00
parent c0937e8add
commit 1b9f2eb76b
3 changed files with 59 additions and 19 deletions

View File

@ -3867,8 +3867,24 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
bool Success = true;
assert((!Result.isArray() || Result.getArrayInitializedElts() == 0) &&
"zero-initialized array shouldn't have any initialized elts");
APValue Filler;
if (Result.isArray() && Result.hasArrayFiller())
Filler = Result.getArrayFiller();
Result = APValue(APValue::UninitArray(), E->getNumInits(),
CAT->getSize().getZExtValue());
// If the array was previously zero-initialized, preserve the
// zero-initialized values.
if (!Filler.isUninit()) {
for (unsigned I = 0, E = Result.getArrayInitializedElts(); I != E; ++I)
Result.getArrayInitializedElt(I) = Filler;
if (Result.hasArrayFiller())
Result.getArrayFiller() = Filler;
}
LValue Subobject = This;
Subobject.addArray(Info, E, CAT);
unsigned Index = 0;
@ -3899,11 +3915,24 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
if (!CAT)
return Error(E);
bool HadZeroInit = !Result.isUninit();
if (!HadZeroInit)
Result = APValue(APValue::UninitArray(), 0, CAT->getSize().getZExtValue());
if (!Result.hasArrayFiller())
return true;
// FIXME: The Subobject here isn't necessarily right. This rarely matters,
// but sometimes does:
// struct S { constexpr S() : p(&p) {} void *p; };
// S s[10];
LValue Subobject = This;
APValue *Value = &Result;
bool HadZeroInit = true;
while (CAT) {
Subobject.addArray(Info, E, CAT);
HadZeroInit &= !Value->isUninit();
if (!HadZeroInit)
*Value = APValue(APValue::UninitArray(), 0, CAT->getSize().getZExtValue());
if (!Value->hasArrayFiller())
return true;
CAT = Info.Ctx.getAsConstantArrayType(CAT->getElementType());
Value = &Value->getArrayFiller();
}
const CXXConstructorDecl *FD = E->getConstructor();
@ -3913,17 +3942,15 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
return true;
if (ZeroInit) {
LValue Subobject = This;
Subobject.addArray(Info, E, CAT);
ImplicitValueInitExpr VIE(CAT->getElementType());
return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE);
return EvaluateInPlace(*Value, Info, Subobject, &VIE);
}
const CXXRecordDecl *RD = FD->getParent();
if (RD->isUnion())
Result.getArrayFiller() = APValue((FieldDecl*)0);
*Value = APValue((FieldDecl*)0);
else
Result.getArrayFiller() =
*Value =
APValue(APValue::UninitStruct(), RD->getNumBases(),
std::distance(RD->field_begin(), RD->field_end()));
return true;
@ -3935,23 +3962,16 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition))
return false;
// FIXME: The Subobject here isn't necessarily right. This rarely matters,
// but sometimes does:
// struct S { constexpr S() : p(&p) {} void *p; };
// S s[10];
LValue Subobject = This;
Subobject.addArray(Info, E, CAT);
if (ZeroInit && !HadZeroInit) {
ImplicitValueInitExpr VIE(CAT->getElementType());
if (!EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE))
if (!EvaluateInPlace(*Value, Info, Subobject, &VIE))
return false;
}
llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
return HandleConstructorCall(E->getExprLoc(), Subobject, Args,
cast<CXXConstructorDecl>(Definition),
Info, Result.getArrayFiller());
Info, *Value);
}
//===----------------------------------------------------------------------===//

View File

@ -121,6 +121,13 @@ namespace Array {
};
// CHECK: @_ZN5Array1eE = constant {{.*}} { [4 x i8] c"foo\00", [4 x i8] c"x\00\00\00" }
extern constexpr E e = E();
// PR13290
struct F { constexpr F() : n(4) {} int n; };
// CHECK: @_ZN5Array2f1E = global {{.*}} zeroinitializer
F f1[1][1][0] = { };
// CHECK: @_ZN5Array2f2E = global {{.* i32 4 .* i32 4 .* i32 4 .* i32 4 .* i32 4 .* i32 4 .* i32 4 .* i32 4}}
F f2[2][2][2] = { };
}
namespace MemberPtr {

View File

@ -494,6 +494,19 @@ struct ArrayRVal {
};
static_assert(ArrayRVal().elems[3].f() == 0, "");
constexpr int selfref[2][2][2] = {
selfref[1][1][1] + 1, selfref[0][0][0] + 1,
selfref[1][0][1] + 1, selfref[0][1][0] + 1,
selfref[1][0][0] + 1, selfref[0][1][1] + 1 };
static_assert(selfref[0][0][0] == 1, "");
static_assert(selfref[0][0][1] == 2, "");
static_assert(selfref[0][1][0] == 1, "");
static_assert(selfref[0][1][1] == 2, "");
static_assert(selfref[1][0][0] == 1, "");
static_assert(selfref[1][0][1] == 3, "");
static_assert(selfref[1][1][0] == 0, "");
static_assert(selfref[1][1][1] == 0, "");
}
namespace DependentValues {