]> granicus.if.org Git - clang/commitdiff
constexpr: initialization of a union from an empty initializer-list should
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 12 Jan 2012 18:54:33 +0000 (18:54 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 12 Jan 2012 18:54:33 +0000 (18:54 +0000)
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
test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp
test/SemaCXX/constant-expression-cxx11.cpp

index 9df53cd5bf0d3803b7d0b81a5887904a8f13fcb0..0cae13850d601529866b0f006c7cae5229c587dc 100644 (file)
@@ -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<CXXRecordDecl>(RD) || !cast<CXXRecordDecl>(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))
index 07a5cef30478245931618bc5781cb0c873db01ef..3631af1b7fd2fa6f67d2c4caf703a3ceb71944e1 100644 (file)
@@ -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];
index 86a326a283d38e85f4ecaf95f8681a114cf49c37..71ce75887ba7390b2bd5737cd90f50c1edb1e5db 100644 (file)
@@ -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;