From: Aaron Ballman Date: Tue, 27 Aug 2019 12:42:45 +0000 (+0000) Subject: Implement codegen for MSVC unions with reference members. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=61f045413ff9744bf1871cf9f02af17c1425115b;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@370052 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 86ef0b8cdb..6cabfccf3a 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -4056,7 +4056,6 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, 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::EmitLValueForField(LValue base, 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); - - // Qualifiers on the struct don't apply to the referencee. - RecordCVR = 0; - FieldType = FieldType->getPointeeType(); - } + // 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(); } // Make sure that the address is pointing to the right type. This is critical diff --git a/test/CodeGenCXX/ms-union-member-ref.cpp b/test/CodeGenCXX/ms-union-member-ref.cpp new file mode 100644 index 0000000000..658cfba937 --- /dev/null +++ b/test/CodeGenCXX/ms-union-member-ref.cpp @@ -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]]