r370052 - Implement codegen for MSVC unions with reference members.

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 27 05:42:45 PDT 2019


Author: aaronballman
Date: Tue Aug 27 05:42:45 2019
New Revision: 370052

URL: http://llvm.org/viewvc/llvm-project?rev=370052&view=rev
Log:
Implement codegen for MSVC unions with reference members.

Currently, clang accepts a union with a reference member when given the -fms-extensions flag. This change fixes the codegen for this case.

Patch by Dominic Ferreira.

Added:
    cfe/trunk/test/CodeGenCXX/ms-union-member-ref.cpp
Modified:
    cfe/trunk/lib/CodeGen/CGExpr.cpp

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=370052&r1=370051&r2=370052&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Tue Aug 27 05:42:45 2019
@@ -4056,7 +4056,6 @@ LValue CodeGenFunction::EmitLValueForFie
   unsigned RecordCVR = base.getVRQualifiers();
   if (rec->isUnion()) {
     // For unions, there is no pointer adjustment.
-    assert(!FieldType->isReferenceType() && "union has reference member");
     if (CGM.getCodeGenOpts().StrictVTablePointers &&
         hasAnyVptr(FieldType, getContext()))
       // Because unions can easily skip invariant.barriers, we need to add
@@ -4073,27 +4072,30 @@ LValue CodeGenFunction::EmitLValueForFie
               addr.getPointer(), getDebugInfoFIndex(rec, field->getFieldIndex()), DbgInfo),
           addr.getAlignment());
     }
-  } else {
 
+    if (FieldType->isReferenceType())
+      addr = Builder.CreateElementBitCast(
+          addr, CGM.getTypes().ConvertTypeForMem(FieldType), field->getName());
+  } else {
     if (!IsInPreservedAIRegion)
       // For structs, we GEP to the field that the record layout suggests.
       addr = emitAddrOfFieldStorage(*this, addr, field);
     else
       // Remember the original struct field index
       addr = emitPreserveStructAccess(*this, addr, field);
+  }
 
-    // If this is a reference field, load the reference right now.
-    if (FieldType->isReferenceType()) {
-      LValue RefLVal = MakeAddrLValue(addr, FieldType, FieldBaseInfo,
-                                      FieldTBAAInfo);
-      if (RecordCVR & Qualifiers::Volatile)
-        RefLVal.getQuals().addVolatile();
-      addr = EmitLoadOfReference(RefLVal, &FieldBaseInfo, &FieldTBAAInfo);
+  // If this is a reference field, load the reference right now.
+  if (FieldType->isReferenceType()) {
+    LValue RefLVal =
+        MakeAddrLValue(addr, FieldType, FieldBaseInfo, FieldTBAAInfo);
+    if (RecordCVR & Qualifiers::Volatile)
+      RefLVal.getQuals().addVolatile();
+    addr = EmitLoadOfReference(RefLVal, &FieldBaseInfo, &FieldTBAAInfo);
 
-      // Qualifiers on the struct don't apply to the referencee.
-      RecordCVR = 0;
-      FieldType = FieldType->getPointeeType();
-    }
+    // Qualifiers on the struct don't apply to the referencee.
+    RecordCVR = 0;
+    FieldType = FieldType->getPointeeType();
   }
 
   // Make sure that the address is pointing to the right type.  This is critical

Added: cfe/trunk/test/CodeGenCXX/ms-union-member-ref.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/ms-union-member-ref.cpp?rev=370052&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/ms-union-member-ref.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/ms-union-member-ref.cpp Tue Aug 27 05:42:45 2019
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fms-extensions %s -emit-llvm -o- | FileCheck %s
+
+union A {
+  int *&ref;
+  int **ptr;
+};
+
+int *f1(A *a) {
+  return a->ref;
+}
+// CHECK-LABEL: define {{.*}}i32* @_Z2f1P1A(%union.A* %a)
+// CHECK:       [[REF:%[^[:space:]]+]] = bitcast %union.A* %{{.*}} to i32***
+// CHECK:       [[IPP:%[^[:space:]]+]] = load i32**, i32*** [[REF]]
+// CHECK:       [[IP:%[^[:space:]]+]]  = load i32*, i32** [[IPP]]
+// CHECK:       ret i32* [[IP]]
+
+void f2(A *a) {
+  *a->ref = 1;
+}
+// CHECK-LABEL: define {{.*}}void @_Z2f2P1A(%union.A* %a)
+// CHECK:       [[REF:%[^[:space:]]+]] = bitcast %union.A* %{{.*}} to i32***
+// CHECK:       [[IPP:%[^[:space:]]+]] = load i32**, i32*** [[REF]]
+// CHECK:       [[IP:%[^[:space:]]+]]  = load i32*, i32** [[IPP]]
+// CHECK:       store i32 1, i32* [[IP]]
+
+bool f3(A *a, int *b) {
+  return a->ref != b;
+}
+// CHECK-LABEL: define {{.*}}i1 @_Z2f3P1APi(%union.A* %a, i32* %b)
+// CHECK:       [[REF:%[^[:space:]]+]] = bitcast %union.A* %{{.*}} to i32***
+// CHECK:       [[IPP:%[^[:space:]]+]] = load i32**, i32*** [[REF]]
+// CHECK:       [[IP:%[^[:space:]]+]]  = load i32*, i32** [[IPP]]
+// CHECK:       [[IP2:%[^[:space:]]+]]  = load i32*, i32** %b.addr
+// CHECK:       icmp ne i32* [[IP]], [[IP2]]




More information about the cfe-commits mailing list