From ec789163a42a7be654ac34aadb750b508954d53c Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 12 Jan 2012 18:54:33 +0000 Subject: [PATCH] constexpr: initialization of a union from an empty initializer-list should zero-initialize the first union member. Also fix a bug where initializing an array of types compatible with wchar_t from a wide string literal failed in C, and fortify the C++ tests in this area. This part can't be tested without a code change to enable array evaluation in C (where an existing test fails). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148035 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ExprConstant.cpp | 31 ++++++++++++++----- .../dcl.decl/dcl.init/dcl.init.string/p1.cpp | 12 +++++++ test/SemaCXX/constant-expression-cxx11.cpp | 14 +++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 9df53cd5bf..0cae13850d 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -3015,14 +3015,20 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); if (RD->isUnion()) { - Result = APValue(E->getInitializedFieldInUnion()); - if (!E->getNumInits()) + const FieldDecl *Field = E->getInitializedFieldInUnion(); + Result = APValue(Field); + if (!Field) return true; + + // If the initializer list for a union does not contain any elements, the + // first element of the union is value-initialized. + ImplicitValueInitExpr VIE(Field->getType()); + const Expr *InitExpr = E->getNumInits() ? E->getInit(0) : &VIE; + LValue Subobject = This; - HandleLValueMember(Info, E->getInit(0), Subobject, - E->getInitializedFieldInUnion(), &Layout); + HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout); return EvaluateConstantExpression(Result.getUnionValue(), Info, - Subobject, E->getInit(0)); + Subobject, InitExpr); } assert((!isa(RD) || !cast(RD)->getNumBases()) && @@ -3065,6 +3071,10 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { const CXXConstructorDecl *FD = E->getConstructor(); bool ZeroInit = E->requiresZeroInitialization(); if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) { + // If we've already performed zero-initialization, we're already done. + if (!Result.isUninit()) + return true; + if (ZeroInit) return ZeroInitialization(E); @@ -3391,7 +3401,7 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // C++11 [dcl.init.string]p1: A char array [...] can be initialized by [...] // an appropriately-typed string literal enclosed in braces. - if (E->getNumInits() == 1 && CAT->getElementType()->isAnyCharacterType() && + if (E->getNumInits() == 1 && E->getInit(0)->isGLValue() && Info.Ctx.hasSameUnqualifiedType(E->getType(), E->getInit(0)->getType())) { LValue LV; if (!EvaluateLValue(E->getInit(0), LV, Info)) @@ -3446,7 +3456,9 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { if (!CAT) return Error(E); - Result = APValue(APValue::UninitArray(), 0, CAT->getSize().getZExtValue()); + bool HadZeroInit = !Result.isUninit(); + if (!HadZeroInit) + Result = APValue(APValue::UninitArray(), 0, CAT->getSize().getZExtValue()); if (!Result.hasArrayFiller()) return true; @@ -3454,6 +3466,9 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { bool ZeroInit = E->requiresZeroInitialization(); if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) { + if (HadZeroInit) + return true; + if (ZeroInit) { LValue Subobject = This; Subobject.addArray(Info, E, CAT); @@ -3485,7 +3500,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { LValue Subobject = This; Subobject.addArray(Info, E, CAT); - if (ZeroInit) { + if (ZeroInit && !HadZeroInit) { ImplicitValueInitExpr VIE(CAT->getElementType()); if (!EvaluateConstantExpression(Result.getArrayFiller(), Info, Subobject, &VIE)) diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp index 07a5cef304..3631af1b7f 100644 --- a/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp +++ b/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp @@ -5,3 +5,15 @@ extern char x1[6]; char x2[] = "hello"; extern char x2[6]; + +char x3[] = { "hello" }; +extern char x3[6]; + +wchar_t x4[](L"hello"); +extern wchar_t x4[6]; + +wchar_t x5[] = L"hello"; +extern wchar_t x5[6]; + +wchar_t x6[] = { L"hello" }; +extern wchar_t x6[6]; diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 86a326a283..71ce75887b 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -357,6 +357,8 @@ constexpr int MangleChars(const Char *p) { } static_assert(MangleChars("constexpr!") == 1768383, ""); +static_assert(MangleChars(u8"constexpr!") == 1768383, ""); +static_assert(MangleChars(L"constexpr!") == 1768383, ""); static_assert(MangleChars(u"constexpr!") == 1768383, ""); static_assert(MangleChars(U"constexpr!") == 1768383, ""); @@ -404,6 +406,12 @@ static_assert(t.c[4] == 0, ""); static_assert(t.c[5] == 0, ""); static_assert(t.c[6] == 0, ""); // expected-error {{constant expression}} expected-note {{one-past-the-end}} +struct U { + wchar_t chars[6]; + int n; +} constexpr u = { { L"test" }, 0 }; +static_assert(u.chars[2] == L's', ""); + } namespace Array { @@ -726,6 +734,12 @@ static_assert((&u[1].b)[1] == 2, ""); // expected-error {{constant expression}} static_assert(*(&(u[1].b) + 1 + 1) == 3, ""); // expected-error {{constant expression}} expected-note {{cannot refer to element 2 of non-array object}} static_assert((&(u[1]) + 1 + 1)->b == 3, ""); +constexpr U v = {}; +static_assert(v.a == 0, ""); + +union Empty {}; +constexpr Empty e = {}; + // Make sure we handle trivial copy constructors for unions. constexpr U x = {42}; constexpr U y = x; -- 2.50.1