constexpr: add support for anonymous struct and union members in literal types.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148987 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index bdedb16..1c0d9ea 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -1188,6 +1188,15 @@
   LVal.addDecl(Info, E, FD);
 }
 
+/// Update LVal to refer to the given indirect field.
+static void HandleLValueIndirectMember(EvalInfo &Info, const Expr *E,
+                                       LValue &LVal,
+                                       const IndirectFieldDecl *IFD) {
+  for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(),
+                                         CE = IFD->chain_end(); C != CE; ++C)
+    HandleLValueMember(Info, E, LVal, cast<FieldDecl>(*C));
+}
+
 /// Get the size of the given type in char units.
 static bool HandleSizeof(EvalInfo &Info, QualType Type, CharUnits &Size) {
   // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
@@ -1654,10 +1663,13 @@
 
   // Add the member. Note that we cannot build bound member functions here.
   if (IncludeMember) {
-    // FIXME: Deal with IndirectFieldDecls.
-    const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl());
-    if (!FD) return 0;
-    HandleLValueMember(Info, BO, LV, FD);
+    if (const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl()))
+      HandleLValueMember(Info, BO, LV, FD);
+    else if (const IndirectFieldDecl *IFD =
+               dyn_cast<IndirectFieldDecl>(MemPtr.getDecl()))
+      HandleLValueIndirectMember(Info, BO, LV, IFD);
+    else
+      llvm_unreachable("can't construct reference to bound member function");
   }
 
   return MemPtr.getDecl();
@@ -1904,11 +1916,40 @@
                    Result.getStructField(FD->getFieldIndex()),
                    Info, Subobject, (*I)->getInit(), CCEK_MemberInit))
         return false;
+    } else if (IndirectFieldDecl *IFD = (*I)->getIndirectMember()) {
+      LValue Subobject = This;
+      APValue *Value = &Result;
+      // Walk the indirect field decl's chain to find the object to initialize,
+      // and make sure we've initialized every step along it.
+      for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(),
+                                             CE = IFD->chain_end();
+           C != CE; ++C) {
+        FieldDecl *FD = cast<FieldDecl>(*C);
+        CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent());
+        // Switch the union field if it differs. This happens if we had
+        // preceding zero-initialization, and we're now initializing a union
+        // subobject other than the first.
+        // FIXME: In this case, the values of the other subobjects are
+        // specified, since zero-initialization sets all padding bits to zero.
+        if (Value->isUninit() ||
+            (Value->isUnion() && Value->getUnionField() != FD)) {
+          if (CD->isUnion())
+            *Value = APValue(FD);
+          else
+            *Value = APValue(APValue::UninitStruct(), CD->getNumBases(),
+                             std::distance(CD->field_begin(), CD->field_end()));
+        }
+        if (CD->isUnion())
+          Value = &Value->getUnionValue();
+        else
+          Value = &Value->getStructField(FD->getFieldIndex());
+        HandleLValueMember(Info, (*I)->getInit(), Subobject, FD);
+      }
+      if (!EvaluateConstantExpression(*Value, Info, Subobject, (*I)->getInit(),
+                                      CCEK_MemberInit))
+        return false;
     } else {
-      // FIXME: handle indirect field initializers
-      Info.Diag((*I)->getInit()->getExprLoc(),
-                diag::note_invalid_subexpr_in_const_expr);
-      return false;
+      llvm_unreachable("unknown base initializer kind");
     }
   }
 
@@ -2349,18 +2390,20 @@
       BaseTy = E->getBase()->getType();
     }
 
-    const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
-    // FIXME: Handle IndirectFieldDecls
-    if (!FD) return this->Error(E);
-    assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
-           FD->getParent()->getCanonicalDecl() && "record / field mismatch");
-    (void)BaseTy;
+    const ValueDecl *MD = E->getMemberDecl();
+    if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) {
+      assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
+             FD->getParent()->getCanonicalDecl() && "record / field mismatch");
+      (void)BaseTy;
+      HandleLValueMember(this->Info, E, Result, FD);
+    } else if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(MD)) {
+      HandleLValueIndirectMember(this->Info, E, Result, IFD);
+    } else
+      return this->Error(E);
 
-    HandleLValueMember(this->Info, E, Result, FD);
-
-    if (FD->getType()->isReferenceType()) {
+    if (MD->getType()->isReferenceType()) {
       CCValue RefValue;
-      if (!HandleLValueToRValueConversion(this->Info, E, FD->getType(), Result,
+      if (!HandleLValueToRValueConversion(this->Info, E, MD->getType(), Result,
                                           RefValue))
         return false;
       return Success(RefValue, E);
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index 21c2cb2..af66acd 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1046,3 +1046,43 @@
     eq = reinterpret_cast<int>((int*)0) // expected-error {{not a constant expression}} expected-note {{reinterpret_cast}}
   };
 }
+
+namespace IndirectField {
+  struct S {
+    struct { // expected-warning {{GNU extension}}
+      union {
+        struct { // expected-warning {{GNU extension}}
+          int a;
+          int b;
+        };
+        int c;
+      };
+      int d;
+    };
+    union {
+      int e;
+      int f;
+    };
+    constexpr S(int a, int b, int d, int e) : a(a), b(b), d(d), e(e) {}
+    constexpr S(int c, int d, int f) : c(c), d(d), f(f) {}
+  };
+
+  constexpr S s1(1, 2, 3, 4);
+  constexpr S s2(5, 6, 7);
+
+  // FIXME: The diagnostics here do a very poor job of explaining which unnamed
+  // member is active and which is requested.
+  static_assert(s1.a == 1, "");
+  static_assert(s1.b == 2, "");
+  static_assert(s1.c == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}}
+  static_assert(s1.d == 3, "");
+  static_assert(s1.e == 4, "");
+  static_assert(s1.f == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}}
+
+  static_assert(s2.a == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}}
+  static_assert(s2.b == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}}
+  static_assert(s2.c == 5, "");
+  static_assert(s2.d == 6, "");
+  static_assert(s2.e == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}}
+  static_assert(s2.f == 7, "");
+}