PR12571: Objects of type clang::ConstantArrayType aren't always emitted with
type llvm::ArrayType -- sometimes we emit them as packed structs. Don't assert
if such a global array has an element type with a non-trivial destructor.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155305 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 2939062..fd78739 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -881,33 +881,49 @@
   llvm::ConstantInt *zero = Builder.getInt32(0);
   gepIndices.push_back(zero);
 
-  // It's more efficient to calculate the count from the LLVM
-  // constant-length arrays than to re-evaluate the array bounds.
   uint64_t countFromCLAs = 1;
+  QualType eltType;
 
   llvm::ArrayType *llvmArrayType =
-    cast<llvm::ArrayType>(
+    dyn_cast<llvm::ArrayType>(
       cast<llvm::PointerType>(addr->getType())->getElementType());
-  while (true) {
+  while (llvmArrayType) {
     assert(isa<ConstantArrayType>(arrayType));
     assert(cast<ConstantArrayType>(arrayType)->getSize().getZExtValue()
              == llvmArrayType->getNumElements());
 
     gepIndices.push_back(zero);
     countFromCLAs *= llvmArrayType->getNumElements();
+    eltType = arrayType->getElementType();
 
     llvmArrayType =
       dyn_cast<llvm::ArrayType>(llvmArrayType->getElementType());
-    if (!llvmArrayType) break;
-
     arrayType = getContext().getAsArrayType(arrayType->getElementType());
-    assert(arrayType && "LLVM and Clang types are out-of-synch");
+    assert((!llvmArrayType || arrayType) &&
+           "LLVM and Clang types are out-of-synch");
   }
 
-  baseType = arrayType->getElementType();
+  if (arrayType) {
+    // From this point onwards, the Clang array type has been emitted
+    // as some other type (probably a packed struct). Compute the array
+    // size, and just emit the 'begin' expression as a bitcast.
+    while (arrayType) {
+      countFromCLAs *=
+          cast<ConstantArrayType>(arrayType)->getSize().getZExtValue();
+      eltType = arrayType->getElementType();
+      arrayType = getContext().getAsArrayType(eltType);
+    }
 
-  // Create the actual GEP.
-  addr = Builder.CreateInBoundsGEP(addr, gepIndices, "array.begin");
+    unsigned AddressSpace =
+        cast<llvm::PointerType>(addr->getType())->getAddressSpace();
+    llvm::Type *BaseType = ConvertType(eltType)->getPointerTo(AddressSpace);
+    addr = Builder.CreateBitCast(addr, BaseType, "array.begin");
+  } else {
+    // Create the actual GEP.
+    addr = Builder.CreateInBoundsGEP(addr, gepIndices, "array.begin");
+  }
+
+  baseType = eltType;
 
   llvm::Value *numElements
     = llvm::ConstantInt::get(SizeTy, countFromCLAs);
diff --git a/test/CodeGenCXX/global-array-destruction.cpp b/test/CodeGenCXX/global-array-destruction.cpp
index 5b5dfac..076ef94 100644
--- a/test/CodeGenCXX/global-array-destruction.cpp
+++ b/test/CodeGenCXX/global-array-destruction.cpp
@@ -1,6 +1,4 @@
-// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm %s -o - | FileCheck %s
 
 extern "C" int printf(...);
 
@@ -24,11 +22,24 @@
 S s2;
 S arr3[3];
 
-// CHECK-LP64: callq    ___cxa_atexit
-// CHECK-LP64: callq    ___cxa_atexit
-// CHECK-LP64: callq    ___cxa_atexit
-// CHECK-LP64: callq    ___cxa_atexit
-// CHECK-LP64: callq    ___cxa_atexit
-// CHECK-LP64: callq    ___cxa_atexit
-// CHECK-LP64: callq    ___cxa_atexit
-// CHECK-LP64: callq    ___cxa_atexit
+// CHECK: call {{.*}} @__cxa_atexit
+// CHECK: call {{.*}} @__cxa_atexit
+// CHECK: call {{.*}} @__cxa_atexit
+// CHECK: call {{.*}} @__cxa_atexit
+// CHECK: call {{.*}} @__cxa_atexit
+// CHECK: call {{.*}} @__cxa_atexit
+// CHECK: call {{.*}} @__cxa_atexit
+// CHECK: call {{.*}} @__cxa_atexit
+
+struct T {
+  double d;
+  int n;
+  ~T();
+};
+T t[2][3] = { 1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10, 11.0, 12 };
+
+// CHECK: call {{.*}} @__cxa_atexit
+// CHECK: getelementptr inbounds ({{.*}} bitcast {{.*}}* @t to %struct.T*), i64 6
+// CHECK: call void @_ZN1TD1Ev
+// CHECK: icmp eq {{.*}} @t
+// CHECK: br i1 {{.*}}