diff options
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 35 | ||||
-rw-r--r-- | test/CodeGen/union-init.c | 31 |
2 files changed, 57 insertions, 9 deletions
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 1144cf1c91..4cb3c7bb2a 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -92,15 +92,26 @@ public: // Copy initializer elements. unsigned i = 0; + bool RewriteType = false; for (; i < NumInitableElts; ++i) { llvm::Constant *C = Visit(ILE->getInit(i)); + RewriteType |= (C->getType() != ElemTy); Elts.push_back(C); } - + // Initialize remaining array elements. for (; i < NumElements; ++i) Elts.push_back(llvm::Constant::getNullValue(ElemTy)); + if (RewriteType) { + // FIXME: Try to avoid packing the array + std::vector<const llvm::Type*> Types; + for (unsigned i = 0; i < Elts.size(); ++i) + Types.push_back(Elts[i]->getType()); + const llvm::StructType *SType = llvm::StructType::get(Types, true); + return llvm::ConstantStruct::get(SType, Elts); + } + return llvm::ConstantArray::get(AType, Elts); } @@ -166,6 +177,7 @@ public: // Copy initializer elements. Skip padding fields. unsigned EltNo = 0; // Element no in ILE int FieldNo = 0; // Field no in RecordDecl + bool RewriteType = false; while (EltNo < ILE->getNumInits() && FieldNo < RD->getNumMembers()) { FieldDecl* curField = RD->getMember(FieldNo); FieldNo++; @@ -175,22 +187,27 @@ public: if (curField->isBitField()) { InsertBitfieldIntoStruct(Elts, curField, ILE->getInit(EltNo)); } else { - Elts[CGM.getTypes().getLLVMFieldNo(curField)] = - Visit(ILE->getInit(EltNo)); + unsigned FieldNo = CGM.getTypes().getLLVMFieldNo(curField); + llvm::Constant* C = Visit(ILE->getInit(EltNo)); + RewriteType |= (C->getType() != Elts[FieldNo]->getType()); + Elts[FieldNo] = C; } EltNo++; } + if (RewriteType) { + // FIXME: Make this work for non-packed structs + assert(SType->isPacked() && "Cannot recreate unpacked structs"); + std::vector<const llvm::Type*> Types; + for (unsigned i = 0; i < Elts.size(); ++i) + Types.push_back(Elts[i]->getType()); + SType = llvm::StructType::get(Types, true); + } + return llvm::ConstantStruct::get(SType, Elts); } llvm::Constant *EmitUnionInitialization(InitListExpr *ILE) { - // FIXME: Need to make this work correctly for unions in structs/arrays - CGM.WarnUnsupported(ILE, "bitfield initialization"); - return llvm::UndefValue::get(CGM.getTypes().ConvertType(ILE->getType())); - - // Following is a partial implementation; it doesn't work correctly - // because the parent struct/arrays don't adapt their type yet, though RecordDecl *RD = ILE->getType()->getAsRecordType()->getDecl(); const llvm::Type *Ty = ConvertType(ILE->getType()); diff --git a/test/CodeGen/union-init.c b/test/CodeGen/union-init.c new file mode 100644 index 0000000000..9a515a72d9 --- /dev/null +++ b/test/CodeGen/union-init.c @@ -0,0 +1,31 @@ +// RUN: clang -emit-llvm < %s -o - + +// A nice and complicated initialization example with unions from Python +typedef int Py_ssize_t; + +typedef union _gc_head { + struct { + union _gc_head *gc_next; + union _gc_head *gc_prev; + Py_ssize_t gc_refs; + } gc; + long double dummy; /* force worst-case alignment */ +} PyGC_Head; + +struct gc_generation { + PyGC_Head head; + int threshold; /* collection threshold */ + int count; /* count of allocations or collections of younger + generations */ +}; + +#define NUM_GENERATIONS 3 +#define GEN_HEAD(n) (&generations[n].head) + +/* linked lists of container objects */ +struct gc_generation generations[NUM_GENERATIONS] = { + /* PyGC_Head, threshold, count */ + {{{GEN_HEAD(0), GEN_HEAD(0), 0}}, 700, 0}, + {{{GEN_HEAD(1), GEN_HEAD(1), 0}}, 10, 0}, + {{{GEN_HEAD(2), GEN_HEAD(2), 0}}, 10, 0}, +}; |