]> granicus.if.org Git - clang/commitdiff
An operator new with an empty exception specifier returns null on a bad
authorJohn McCall <rjmccall@apple.com>
Mon, 7 Mar 2011 01:52:56 +0000 (01:52 +0000)
committerJohn McCall <rjmccall@apple.com>
Mon, 7 Mar 2011 01:52:56 +0000 (01:52 +0000)
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
test/CodeGenCXX/exceptions.cpp

index bba7864bff988e77952da5f1e64739811c432fc3..2b8efa0e39fe4c4245bd5335d53f38d0ebbd3be9 100644 (file)
@@ -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);
index e7231cc7d3089ae5ce09fc98dd2b5bbd01b10134..5c38f01309cd9713b7a9571cff5c809e0136cdaa 100644 (file)
@@ -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));
+  }
+}