Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -4057,7 +4057,6 @@ 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 @@ -4074,27 +4073,30 @@ 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 Index: clang/test/CodeGenCXX/ms-union-member-ref.cpp =================================================================== --- /dev/null +++ clang/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]]