From a7f633f522af786e80dc08dbd63e222c9414095b Mon Sep 17 00:00:00 2001 From: John McCall Date: Mon, 7 Mar 2011 01:52:56 +0000 Subject: [PATCH] An operator new with an empty exception specifier returns null on a bad allocation and therefore requires a null-check. We were doing that, but we weren't treating the new-initializer as being conditionally executed, which means it was possible to get ill-formed IR as in PR9298. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127147 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGExprCXX.cpp | 8 ++++++++ test/CodeGenCXX/exceptions.cpp | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index bba7864bff..2b8efa0e39 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -993,6 +993,10 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { llvm::Value *NewPtr = RV.getScalarVal(); unsigned AS = cast(NewPtr->getType())->getAddressSpace(); + // The null-check means that the initializer is conditionally + // evaluated. + ConditionalEvaluation conditional(*this); + if (NullCheckResult) { NullCheckSource = Builder.GetInsertBlock(); NewNotNull = createBasicBlock("new.notnull"); @@ -1001,6 +1005,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { llvm::Value *IsNull = Builder.CreateIsNull(NewPtr, "new.isnull"); Builder.CreateCondBr(IsNull, NewEnd, NewNotNull); EmitBlock(NewNotNull); + + conditional.begin(*this); } assert((AllocSize == AllocSizeWithoutCookie) == @@ -1042,6 +1048,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { DeactivateCleanupBlock(CallOperatorDelete); if (NullCheckResult) { + conditional.end(*this); + Builder.CreateBr(NewEnd); llvm::BasicBlock *NotNullSource = Builder.GetInsertBlock(); EmitBlock(NewEnd); diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp index e7231cc7d3..5c38f01309 100644 --- a/test/CodeGenCXX/exceptions.cpp +++ b/test/CodeGenCXX/exceptions.cpp @@ -305,3 +305,21 @@ namespace test6 { } } } + +// PR9298 +namespace test7 { + struct A { A(); ~A(); }; + struct B { + // The throw() operator means that a bad allocation is signalled + // with a null return, which means that the initializer is + // evaluated conditionally. + static void *operator new(size_t size) throw(); + B(const A&, B*); + ~B(); + }; + + // Just make sure the result passes verification. + B *test() { + return new B(A(), new B(A(), 0)); + } +} -- 2.40.0