From dd376cae98ce4d0ab92c90d3e9c01ee19e919f44 Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 13 Jul 2011 07:37:11 +0000 Subject: [PATCH] Arrays are permitted to be zero-length in some situations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135036 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGClass.cpp | 28 +++++++++++++++++++++++++++- lib/CodeGen/CGExprCXX.cpp | 26 -------------------------- test/CodeGenCXX/constructors.cpp | 11 +++++++++++ 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 47d4fcbae3..7dbaaf8529 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -1063,7 +1063,7 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor, /// /// \param ctor the constructor to call for each element /// \param numElements the number of elements in the array; -/// assumed to be non-zero +/// may be zero /// \param argBegin,argEnd the arguments to evaluate and pass to the /// constructor /// \param arrayBegin a T*, where T is the type constructed by ctor @@ -1076,6 +1076,29 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor, CallExpr::const_arg_iterator argBegin, CallExpr::const_arg_iterator argEnd, bool zeroInitialize) { + + // It's legal for numElements to be zero. This can happen both + // dynamically, because x can be zero in 'new A[x]', and statically, + // because of GCC extensions that permit zero-length arrays. There + // are probably legitimate places where we could assume that this + // doesn't happen, but it's not clear that it's worth it. + llvm::BranchInst *zeroCheckBranch = 0; + + // Optimize for a constant count. + llvm::ConstantInt *constantCount + = dyn_cast(numElements); + if (constantCount) { + // Just skip out if the constant count is zero. + if (constantCount->isZero()) return; + + // Otherwise, emit the check. + } else { + llvm::BasicBlock *loopBB = createBasicBlock("new.ctorloop"); + llvm::Value *iszero = Builder.CreateIsNull(numElements, "isempty"); + zeroCheckBranch = Builder.CreateCondBr(iszero, loopBB, loopBB); + EmitBlock(loopBB); + } + // Find the end of the array. llvm::Value *arrayEnd = Builder.CreateInBoundsGEP(arrayBegin, numElements, "arrayctor.end"); @@ -1130,6 +1153,9 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor, llvm::BasicBlock *contBB = createBasicBlock("arrayctor.cont"); Builder.CreateCondBr(done, contBB, loopBB); + // Patch the earlier check to skip over the loop. + if (zeroCheckBranch) zeroCheckBranch->setSuccessor(0, contBB); + EmitBlock(contBB); } diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 49aab66268..e3c6a8f978 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -798,36 +798,10 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, RequiresZeroInitialization = true; } - // It's legal for NumElements to be zero, but - // EmitCXXAggrConstructorCall doesn't handle that, so we need to. - llvm::BranchInst *br = 0; - - // Optimize for a constant count. - llvm::ConstantInt *constantCount - = dyn_cast(NumElements); - if (constantCount) { - // Just skip out if the constant count is zero. - if (constantCount->isZero()) return; - - // Otherwise, emit the check. - } else { - llvm::BasicBlock *loopBB = CGF.createBasicBlock("new.ctorloop"); - llvm::Value *iszero = CGF.Builder.CreateIsNull(NumElements, "isempty"); - br = CGF.Builder.CreateCondBr(iszero, loopBB, loopBB); - CGF.EmitBlock(loopBB); - } - CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr, E->constructor_arg_begin(), E->constructor_arg_end(), RequiresZeroInitialization); - - // Patch the earlier check to skip over the loop. - if (br) { - assert(CGF.Builder.GetInsertBlock()->empty()); - br->setSuccessor(0, CGF.Builder.GetInsertBlock()); - } - return; } else if (E->getNumConstructorArgs() == 1 && isa(E->getConstructorArg(0))) { diff --git a/test/CodeGenCXX/constructors.cpp b/test/CodeGenCXX/constructors.cpp index 9e09099ba4..ec7f06c868 100644 --- a/test/CodeGenCXX/constructors.cpp +++ b/test/CodeGenCXX/constructors.cpp @@ -104,3 +104,14 @@ namespace test0 { C tmp = in; } } + +namespace test1 { + struct A { A(); void *ptr; }; + struct B { B(); int x; A a[0]; }; + B::B() {} + // CHECK: define void @_ZN5test11BC2Ev( + // CHECK: [[THIS:%.*]] = load [[B:%.*]]** + // CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[B:%.*]]* [[THIS]], i32 0, i32 1 + // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [0 x {{%.*}}]* [[A]], i32 0, i32 0 + // CHECK-NEXT: ret void +}