diff options
| author | Aaron Ballman <aaron@aaronballman.com> | 2019-08-27 12:42:45 +0000 | 
|---|---|---|
| committer | Aaron Ballman <aaron@aaronballman.com> | 2019-08-27 12:42:45 +0000 | 
| commit | 0299dbd2ae89e81584cf95571ef0549862e10fea (patch) | |
| tree | 4614255dd5d0f969838b949cb979fb8bb4a297ae | |
| parent | d0698b67e89236d887b28be3a5ce3f7cce6c54de (diff) | |
| download | bcm5719-llvm-0299dbd2ae89e81584cf95571ef0549862e10fea.tar.gz bcm5719-llvm-0299dbd2ae89e81584cf95571ef0549862e10fea.zip  | |
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.
llvm-svn: 370052
| -rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 30 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/ms-union-member-ref.cpp | 34 | 
2 files changed, 50 insertions, 14 deletions
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 86ef0b8cdb9..6cabfccf3a1 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/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/clang/test/CodeGenCXX/ms-union-member-ref.cpp b/clang/test/CodeGenCXX/ms-union-member-ref.cpp new file mode 100644 index 00000000000..658cfba9378 --- /dev/null +++ b/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]]  | 

