From: John McCall Date: Sat, 7 Aug 2010 08:21:30 +0000 (+0000) Subject: Inline a special case of EmitAggregateCopy into EmitNullInitialization X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9021718882441dd391a1960084580d3cd19c423a;p=clang Inline a special case of EmitAggregateCopy into EmitNullInitialization to avoid the awesome-but-wrong-in-this-case assertion in the canon EAC. Fixes PR7834. Also fix a subtle address-space bug in the memset path. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110511 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 35664af219..a3cd4f4c29 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -545,21 +545,6 @@ void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type, void CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) { - // If the type contains a pointer to data member we can't memset it to zero. - // Instead, create a null constant and copy it to the destination. - if (CGM.getTypes().ContainsPointerToDataMember(Ty)) { - llvm::Constant *NullConstant = CGM.EmitNullConstant(Ty); - - llvm::GlobalVariable *NullVariable = - new llvm::GlobalVariable(CGM.getModule(), NullConstant->getType(), - /*isConstant=*/true, - llvm::GlobalVariable::PrivateLinkage, - NullConstant, llvm::Twine()); - EmitAggregateCopy(DestPtr, NullVariable, Ty, /*isVolatile=*/false); - return; - } - - // Ignore empty classes in C++. if (getContext().getLangOptions().CPlusPlus) { if (const RecordType *RT = Ty->getAs()) { @@ -567,29 +552,58 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) { return; } } - - // Otherwise, just memset the whole thing to zero. This is legal - // because in LLVM, all default initializers (other than the ones we just - // handled above) are guaranteed to have a bit pattern of all zeros. - const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); + + // Cast the dest ptr to the appropriate i8 pointer type. + unsigned DestAS = + cast(DestPtr->getType())->getAddressSpace(); + const llvm::Type *BP = + llvm::Type::getInt8PtrTy(VMContext, DestAS); if (DestPtr->getType() != BP) DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); // Get size and alignment info for this aggregate. std::pair TypeInfo = getContext().getTypeInfo(Ty); + uint64_t Size = TypeInfo.first; + unsigned Align = TypeInfo.second; // Don't bother emitting a zero-byte memset. - if (TypeInfo.first == 0) + if (Size == 0) return; + llvm::ConstantInt *SizeVal = llvm::ConstantInt::get(IntPtrTy, Size / 8); + llvm::ConstantInt *AlignVal = Builder.getInt32(Align / 8); + + // If the type contains a pointer to data member we can't memset it to zero. + // Instead, create a null constant and copy it to the destination. + if (CGM.getTypes().ContainsPointerToDataMember(Ty)) { + llvm::Constant *NullConstant = CGM.EmitNullConstant(Ty); + + llvm::GlobalVariable *NullVariable = + new llvm::GlobalVariable(CGM.getModule(), NullConstant->getType(), + /*isConstant=*/true, + llvm::GlobalVariable::PrivateLinkage, + NullConstant, llvm::Twine()); + llvm::Value *SrcPtr = + Builder.CreateBitCast(NullVariable, Builder.getInt8PtrTy()); + + // FIXME: variable-size types? + + // Get and call the appropriate llvm.memcpy overload. + llvm::Constant *Memcpy = + CGM.getMemCpyFn(DestPtr->getType(), SrcPtr->getType(), IntPtrTy); + Builder.CreateCall5(Memcpy, DestPtr, SrcPtr, SizeVal, AlignVal, + /*volatile*/ Builder.getFalse()); + return; + } + + // Otherwise, just memset the whole thing to zero. This is legal + // because in LLVM, all default initializers (other than the ones we just + // handled above) are guaranteed to have a bit pattern of all zeros. + // FIXME: Handle variable sized types. Builder.CreateCall5(CGM.getMemSetFn(BP, IntPtrTy), DestPtr, - llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)), - // TypeInfo.first describes size in bits. - llvm::ConstantInt::get(IntPtrTy, TypeInfo.first/8), - llvm::ConstantInt::get(Int32Ty, TypeInfo.second/8), - llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), - 0)); + Builder.getInt8(0), + SizeVal, AlignVal, /*volatile*/ Builder.getFalse()); } llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelStmt *L) { diff --git a/test/CodeGenCXX/value-init.cpp b/test/CodeGenCXX/value-init.cpp index 35be159aac..ec1f8263e4 100644 --- a/test/CodeGenCXX/value-init.cpp +++ b/test/CodeGenCXX/value-init.cpp @@ -49,3 +49,21 @@ void test_enum_holder_and_int() { enum_holder_and_int(); // CHECK-NEXT: ret void } + +// PR7834: don't crash. +namespace test1 { + struct A { + int A::*f; + A(); + A(const A&); + A &operator=(const A &); + }; + + struct B { + A base; + }; + + void foo() { + B(); + } +}