зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
862ff87c0d
Коммит
dd376cae98
|
@ -1063,7 +1063,7 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
|
||||||
///
|
///
|
||||||
/// \param ctor the constructor to call for each element
|
/// \param ctor the constructor to call for each element
|
||||||
/// \param numElements the number of elements in the array;
|
/// \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
|
/// \param argBegin,argEnd the arguments to evaluate and pass to the
|
||||||
/// constructor
|
/// constructor
|
||||||
/// \param arrayBegin a T*, where T is the type constructed by ctor
|
/// \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 argBegin,
|
||||||
CallExpr::const_arg_iterator argEnd,
|
CallExpr::const_arg_iterator argEnd,
|
||||||
bool zeroInitialize) {
|
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<llvm::ConstantInt>(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.
|
// Find the end of the array.
|
||||||
llvm::Value *arrayEnd = Builder.CreateInBoundsGEP(arrayBegin, numElements,
|
llvm::Value *arrayEnd = Builder.CreateInBoundsGEP(arrayBegin, numElements,
|
||||||
"arrayctor.end");
|
"arrayctor.end");
|
||||||
|
@ -1130,6 +1153,9 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
|
||||||
llvm::BasicBlock *contBB = createBasicBlock("arrayctor.cont");
|
llvm::BasicBlock *contBB = createBasicBlock("arrayctor.cont");
|
||||||
Builder.CreateCondBr(done, contBB, loopBB);
|
Builder.CreateCondBr(done, contBB, loopBB);
|
||||||
|
|
||||||
|
// Patch the earlier check to skip over the loop.
|
||||||
|
if (zeroCheckBranch) zeroCheckBranch->setSuccessor(0, contBB);
|
||||||
|
|
||||||
EmitBlock(contBB);
|
EmitBlock(contBB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -798,36 +798,10 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
|
||||||
RequiresZeroInitialization = true;
|
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<llvm::ConstantInt>(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,
|
CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
|
||||||
E->constructor_arg_begin(),
|
E->constructor_arg_begin(),
|
||||||
E->constructor_arg_end(),
|
E->constructor_arg_end(),
|
||||||
RequiresZeroInitialization);
|
RequiresZeroInitialization);
|
||||||
|
|
||||||
// Patch the earlier check to skip over the loop.
|
|
||||||
if (br) {
|
|
||||||
assert(CGF.Builder.GetInsertBlock()->empty());
|
|
||||||
br->setSuccessor(0, CGF.Builder.GetInsertBlock());
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else if (E->getNumConstructorArgs() == 1 &&
|
} else if (E->getNumConstructorArgs() == 1 &&
|
||||||
isa<ImplicitValueInitExpr>(E->getConstructorArg(0))) {
|
isa<ImplicitValueInitExpr>(E->getConstructorArg(0))) {
|
||||||
|
|
|
@ -104,3 +104,14 @@ namespace test0 {
|
||||||
C tmp = in;
|
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
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче