[clang] [CIR] [WIP] Implement null check for CXXNewExpr (PR #192848)

Henrich Lauko via cfe-commits cfe-commits at lists.llvm.org
Sun Apr 19 11:36:25 PDT 2026


================
@@ -0,0 +1,96 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+typedef __typeof__(sizeof(int)) size_t;
+
+namespace std {
+  struct nothrow_t {};
+}
+std::nothrow_t nothrow;
+
+void *operator new(size_t, const std::nothrow_t &) throw();
+void operator delete(void *, const std::nothrow_t &) throw();
+
+struct S {
+  S();
+  int a;
+};
+
+// nothrow new with non-POD type triggers null check
+S *test_nothrow_new() {
+  return new (nothrow) S;
+}
+
+// CHECK: cir.func {{.*}} @_Z16test_nothrow_newv()
+// CHECK:   %[[ALLOC:.*]] = cir.call @_ZnwmRKSt9nothrow_t({{.*}}) nothrow
+// CHECK:   %[[NULL:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!void>
+// CHECK:   %[[IS_NOT_NULL:.*]] = cir.cmp ne %[[ALLOC]], %[[NULL]] : !cir.ptr<!void>
+// CHECK:   cir.if %[[IS_NOT_NULL]] {
+// CHECK:     %[[CAST:.*]] = cir.cast bitcast %[[ALLOC]] : !cir.ptr<!void> -> !cir.ptr<!rec_S>
+// CHECK:     cir.call @_ZN1SC1Ev(%[[CAST]])
+// CHECK:   }
+// CHECK:   %[[RESULT_CAST:.*]] = cir.cast bitcast %[[ALLOC]] : !cir.ptr<!void> -> !cir.ptr<!rec_S>
+// CHECK:   %[[NULL_S:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!rec_S>
+// CHECK:   %[[RESULT:.*]] = cir.select if %[[IS_NOT_NULL]] then %[[RESULT_CAST]] else %[[NULL_S]]
+
+// LLVM: define {{.*}} ptr @_Z16test_nothrow_newv()
+// LLVM:   %[[ALLOC:.*]] = call {{.*}} ptr @_ZnwmRKSt9nothrow_t(i64 noundef 4, {{.*}})
+// LLVM:   %[[CMP:.*]] = icmp ne ptr %[[ALLOC]], null
+// LLVM:   br i1 %[[CMP]], label %[[NOT_NULL:.*]], label %[[CONT:.*]]
+// LLVM: [[NOT_NULL]]:
+// LLVM:   call void @_ZN1SC1Ev({{.*}} %[[ALLOC]])
+// LLVM:   br label %[[CONT]]
+// LLVM: [[CONT]]:
+// LLVM:   %[[RESULT:.*]] = select i1 %[[CMP]], ptr %[[ALLOC]], ptr null
+
+// OGCG: define {{.*}} ptr @_Z16test_nothrow_newv()
+// OGCG:   %[[ALLOC:.*]] = call {{.*}} ptr @_ZnwmRKSt9nothrow_t(i64 noundef 4, {{.*}})
+// OGCG:   %[[IS_NULL:.*]] = icmp eq ptr %[[ALLOC]], null
+// OGCG:   br i1 %[[IS_NULL]], label %[[CONT:.*]], label %[[NOT_NULL:.*]]
+// OGCG: [[NOT_NULL]]:
+// OGCG:   call void @_ZN1SC1Ev({{.*}} %[[ALLOC]])
+// OGCG:   br label %[[CONT]]
+// OGCG: [[CONT]]:
+// OGCG:   phi ptr
+
+// nothrow new with POD + initializer triggers null check
+int *test_nothrow_new_init() {
+  return new (nothrow) int(42);
+}
+
+// CHECK: cir.func {{.*}} @_Z21test_nothrow_new_initv()
+// CHECK:   %[[ALLOC:.*]] = cir.call @_ZnwmRKSt9nothrow_t({{.*}}) nothrow
+// CHECK:   %[[NULL:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!void>
+// CHECK:   %[[IS_NOT_NULL:.*]] = cir.cmp ne %[[ALLOC]], %[[NULL]] : !cir.ptr<!void>
+// CHECK:   cir.if %[[IS_NOT_NULL]] {
+// CHECK:     %[[CAST:.*]] = cir.cast bitcast %[[ALLOC]] : !cir.ptr<!void> -> !cir.ptr<!s32i>
+// CHECK:     %[[FORTY_TWO:.*]] = cir.const #cir.int<42> : !s32i
+// CHECK:     cir.store {{.*}} %[[FORTY_TWO]], %[[CAST]]
+// CHECK:   }
+// CHECK:   %[[RESULT_CAST:.*]] = cir.cast bitcast %[[ALLOC]] : !cir.ptr<!void> -> !cir.ptr<!s32i>
+// CHECK:   %[[NULL_I:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i>
+// CHECK:   %[[RESULT:.*]] = cir.select if %[[IS_NOT_NULL]] then %[[RESULT_CAST]] else %[[NULL_I]]
+
+// LLVM: define {{.*}} ptr @_Z21test_nothrow_new_initv()
+// LLVM:   %[[ALLOC:.*]] = call {{.*}} ptr @_ZnwmRKSt9nothrow_t(i64 noundef 4, {{.*}})
+// LLVM:   %[[CMP:.*]] = icmp ne ptr %[[ALLOC]], null
+// LLVM:   br i1 %[[CMP]], label %[[NOT_NULL:.*]], label %[[CONT:.*]]
+// LLVM: [[NOT_NULL]]:
+// LLVM:   store i32 42, ptr %[[ALLOC]], align 4
+// LLVM:   br label %[[CONT]]
+// LLVM: [[CONT]]:
+// LLVM:   %[[RESULT:.*]] = select i1 %[[CMP]], ptr %[[ALLOC]], ptr null
----------------
xlauko wrote:

CAn we make this as in OGCG, i.e. use icmp eq and first NOT_NULL block then CONT

https://github.com/llvm/llvm-project/pull/192848


More information about the cfe-commits mailing list