From: Richard Smith Date: Sat, 7 Jul 2012 22:48:24 +0000 (+0000) Subject: PR13290: Constant-evaluation support for CXXConstructExprs which construct a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=de31aa7f0ef71f5c162372e319cbc03c0924f074;p=clang 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). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159904 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index f92639f914..f9583deadc 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -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 Args(E->getArgs(), E->getNumArgs()); return HandleConstructorCall(E->getExprLoc(), Subobject, Args, cast(Definition), - Info, Result.getArrayFiller()); + Info, *Value); } //===----------------------------------------------------------------------===// diff --git a/test/CodeGenCXX/const-init-cxx11.cpp b/test/CodeGenCXX/const-init-cxx11.cpp index 07385eedba..d2504d78cd 100644 --- a/test/CodeGenCXX/const-init-cxx11.cpp +++ b/test/CodeGenCXX/const-init-cxx11.cpp @@ -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 { diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 2cd66b6f62..f576dfa32f 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -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 {