]> granicus.if.org Git - clang/commitdiff
CodeGen: Use the initing member's type for a union's storage type more often
authorDavid Majnemer <david.majnemer@gmail.com>
Wed, 15 Oct 2014 07:57:41 +0000 (07:57 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Wed, 15 Oct 2014 07:57:41 +0000 (07:57 +0000)
Unions are initialized with the default initialization of their first
named member.  If that member is not zero initialized, then we should
prefer that member's type.  Otherwise, we might try to make an otherwise
unsuitable type (like an array) which we cannot easily initialize with a
pointer to member.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219781 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGRecordLayoutBuilder.cpp
test/CodeGenCXX/pointers-to-data-members.cpp

index 9e7efa083aef9fc3203623839243e2e3792d642a..8084532e4cbca231c17c0a915d1d6472f22da6f1 100644 (file)
@@ -279,6 +279,8 @@ void CGRecordLowering::lower(bool NVBaseType) {
 void CGRecordLowering::lowerUnion() {
   CharUnits LayoutSize = Layout.getSize();
   llvm::Type *StorageType = nullptr;
+  bool SeenNamedMember = false;
+  bool InitializingMemberIsNonZero = false;
   // Compute zero-initializable status.
   if (!D->field_empty() && !isZeroInitializable(*D->field_begin()))
     IsZeroInitializable = IsZeroInitializableAsBase = false;
@@ -299,12 +301,25 @@ void CGRecordLowering::lowerUnion() {
     }
     Fields[Field->getCanonicalDecl()] = 0;
     llvm::Type *FieldType = getStorageType(Field);
+    // This union might not be zero initialized: it may contain a pointer to
+    // data member which might have some exotic initialization sequence.
+    // If this is the case, then we aught not to try and come up with a "better"
+    // type, it might not be very easy to come up with a Constant which
+    // correctly initializes it.
+    if (!SeenNamedMember && Field->getDeclName()) {
+      SeenNamedMember = true;
+      if (!isZeroInitializable(Field)) {
+        InitializingMemberIsNonZero = true;
+        StorageType = FieldType;
+      }
+    }
     // Conditionally update our storage type if we've got a new "better" one.
     if (!StorageType ||
         getAlignment(FieldType) >  getAlignment(StorageType) ||
         (getAlignment(FieldType) == getAlignment(StorageType) &&
         getSize(FieldType) > getSize(StorageType)))
-      StorageType = FieldType;
+      if (!InitializingMemberIsNonZero)
+        StorageType = FieldType;
   }
   // If we have no storage type just pad to the appropriate size and return.
   if (!StorageType)
index e011c2dc55f4ce290cd02d1b6155eed713898aa8..0b99fea8fc572cc7394eb2d99394cf85bb5b0e89 100644 (file)
@@ -268,4 +268,13 @@ B b;
 // CHECK-GLOBAL: @_ZN7PR210891bE = global %"struct.PR21089::B" { %"struct.PR21089::A.base" <{ i8 0, [7 x i8] zeroinitializer, i64 -1, i8 0 }>, [7 x i8] zeroinitializer }, align 8
 }
 
+namespace PR21282 {
+union U {
+  int U::*x;
+  long y[2];
+};
+U u;
+// CHECK-GLOBAL: @_ZN7PR212821uE = global %"union.PR21282::U" { i64 -1, [8 x i8] zeroinitializer }, align 8
+}
+
 // CHECK-O3: attributes [[NUW]] = { nounwind readnone{{.*}} }