aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2011-03-07 01:52:56 +0000
committerJohn McCall <rjmccall@apple.com>2011-03-07 01:52:56 +0000
commita7f633f522af786e80dc08dbd63e222c9414095b (patch)
tree4ada9ad427b1a0b97bbfd52b6f94745f73d76fad
parent03fd362dbf6fcd077df566fe2ac3165be668323b (diff)
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
-rw-r--r--lib/CodeGen/CGExprCXX.cpp8
-rw-r--r--test/CodeGenCXX/exceptions.cpp18
2 files changed, 26 insertions, 0 deletions
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<llvm::PointerType>(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));
+ }
+}