From a9976d3b192690db20f59dc44099ac4ca939bdb7 Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 21 May 2010 01:18:57 +0000 Subject: [PATCH] When emitting an lvalue for an anonymous struct or union member during class initialization, drill down through an arbitrary number of anonymous records. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104310 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGClass.cpp | 6 ++-- lib/CodeGen/CGExpr.cpp | 29 +++++++++++++++++++ lib/CodeGen/CodeGenFunction.h | 3 ++ .../anonymous-union-member-initializer.cpp | 26 +++++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 72d95b8556..82c72288d9 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -446,13 +446,15 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, QualType FieldType = CGF.getContext().getCanonicalType(Field->getType()); llvm::Value *ThisPtr = CGF.LoadCXXThis(); - LValue LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 0); + LValue LHS; // If we are initializing an anonymous union field, drill down to the field. if (MemberInit->getAnonUnionMember()) { Field = MemberInit->getAnonUnionMember(); - LHS = CGF.EmitLValueForField(LHS.getAddress(), Field, 0); + LHS = CGF.EmitLValueForAnonRecordField(ThisPtr, Field, 0); FieldType = Field->getType(); + } else { + LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 0); } // FIXME: If there's no initializer and the CXXBaseOrMemberInitializer diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 80d38f250d..74e64e59a5 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1611,6 +1611,35 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue, Field->getType().getCVRQualifiers()|CVRQualifiers); } +/// EmitLValueForAnonRecordField - Given that the field is a member of +/// an anonymous struct or union buried inside a record, and given +/// that the base value is a pointer to the enclosing record, derive +/// an lvalue for the ultimate field. +LValue CodeGenFunction::EmitLValueForAnonRecordField(llvm::Value *BaseValue, + const FieldDecl *Field, + unsigned CVRQualifiers) { + llvm::SmallVector Path; + Path.push_back(Field); + + while (Field->getParent()->isAnonymousStructOrUnion()) { + const ValueDecl *VD = Field->getParent()->getAnonymousStructOrUnionObject(); + if (!isa(VD)) break; + Field = cast(VD); + Path.push_back(Field); + } + + llvm::SmallVectorImpl::reverse_iterator + I = Path.rbegin(), E = Path.rend(); + while (true) { + LValue LV = EmitLValueForField(BaseValue, *I, CVRQualifiers); + if (++I == E) return LV; + + assert(LV.isSimple()); + BaseValue = LV.getAddress(); + CVRQualifiers |= LV.getVRQualifiers(); + } +} + LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue, const FieldDecl* Field, unsigned CVRQualifiers) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 077b8169f1..048bd0918a 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1052,6 +1052,9 @@ public: llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); + LValue EmitLValueForAnonRecordField(llvm::Value* Base, + const FieldDecl* Field, + unsigned CVRQualifiers); LValue EmitLValueForField(llvm::Value* Base, const FieldDecl* Field, unsigned CVRQualifiers); diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp index bd816a4a44..a4da2c04fd 100644 --- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp +++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp @@ -52,3 +52,29 @@ namespace test2 { // CHECK: store i32 10 // CHECK: } } + +namespace test3 { + struct A { + union { + mutable char fibers[100]; + struct { + void (*callback)(void*); + void *callback_value; + }; + }; + + A(); + }; + + A::A() : callback(0), callback_value(0) {} + // CHECK: define void @ZN5test31AC2Ev( + // CHECK: [[THIS:%.*]] = load + // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0 + // CHECK-NEXT: [[STRUCT:%.*]] = getelementptr inbounds {{.*}} [[UNION]], i32 0, i32 0 + // CHECK-NEXT: [[CALLBACK:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 0 + // CHECK-NEXT: store void (i8*)* null, void (i8*)** [[CALLBACK]] + // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0 + // CHECK-NEXT: [[STRUCT:%.*]] = getelementptr inbounds {{.*}} [[UNION]], i32 0, i32 0 + // CHECK-NEXT: [[CVALUE:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 0 + // CHECK-NEXT: store i8* null, void i8** [[CVALUE]] +} -- 2.40.0