[clang] 883ef1b - [clang] Don't omit null pointer checks with -fms-compatibility (#204658)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 9 06:58:49 PDT 2026
Author: eleviant
Date: 2026-07-09T13:58:43Z
New Revision: 883ef1ba1442618938961e8f8e3a6a74f3b7320a
URL: https://github.com/llvm/llvm-project/commit/883ef1ba1442618938961e8f8e3a6a74f3b7320a
DIFF: https://github.com/llvm/llvm-project/commit/883ef1ba1442618938961e8f8e3a6a74f3b7320a.diff
LOG: [clang] Don't omit null pointer checks with -fms-compatibility (#204658)
MSVC preserves null check after dereference, e.g
```
struct Obj { int value, extra; };
int null_check_is_kept(Obj* p) {
int v = p->value;
if (p == nullptr)
return -1;
return v + p->extra;
}
```
Also MSVC keeps standard library calls (e.g memcpy), where target is
null pointer.
Added:
clang/test/CodeGen/null-checks.c
Modified:
clang/docs/ReleaseNotes.md
clang/include/clang/Options/Options.td
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 4304bb4df6ecb..92e63585e492a 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -460,6 +460,8 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
- The `-cl` `/Brepro` option was modified to match the original CL's option
and now defines the standard macros `__DATE__`, `__TIME__` and `__TIMESTAMP__` to
"1". The previous functionality remains unchanged.
+- The `-fms-kernel` flag will now implicitly add `-fno-delete-null-pointer-checks`.
+ Still `-fdelete-null-pointer-checks` can be used to override this behavior.
### Removed Compiler Flags
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 59bfd621a5994..c498b4e6acc44 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -3083,10 +3083,10 @@ defm rewrite_includes : BoolFOption<"rewrite-includes",
defm directives_only : OptInCC1FFlag<"directives-only", "">;
defm delete_null_pointer_checks : BoolFOption<"delete-null-pointer-checks",
- CodeGenOpts<"NullPointerIsValid">, DefaultFalse,
+ CodeGenOpts<"NullPointerIsValid">, Default<"LangOpts->Kernel">,
NegFlag<SetTrue, [], [ClangOption, CC1Option],
"Do not treat usage of null pointers as undefined behavior">,
- PosFlag<SetFalse, [], [ClangOption], "Treat usage of null pointers as undefined behavior (default)">,
+ PosFlag<SetFalse, [], [ClangOption, CC1Option], "Treat usage of null pointers as undefined behavior (default)">,
BothFlags<[], [ClangOption, CLOption]>>,
DocBrief<[{When enabled, treat null pointer dereference, creation of a reference to null,
or passing a null pointer to a function parameter annotated with the "nonnull"
diff --git a/clang/test/CodeGen/null-checks.c b/clang/test/CodeGen/null-checks.c
new file mode 100644
index 0000000000000..a0ff4cc4dbed0
--- /dev/null
+++ b/clang/test/CodeGen/null-checks.c
@@ -0,0 +1,36 @@
+// Check that null pointer checks are not optimized out if -fms-compatibility is set
+// RUN: %clang_cc1 -fms-kernel -O2 -triple x86_64-pc-windows-msvc %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -O2 -triple x86_64-pc-windows-msvc %s -emit-llvm -o - | FileCheck %s --check-prefix=NOCHECK
+// RUN: %clang_cc1 -fms-kernel -O2 -triple x86_64-pc-windows-msvc -fdelete-null-pointer-checks %s -emit-llvm -o - | FileCheck %s --check-prefix=NOCHECK
+// RUN: %clang_cc1 -O2 -triple x86_64-pc-windows-msvc -fdelete-null-pointer-checks -fms-kernel %s -emit-llvm -o - | FileCheck %s --check-prefix=NOCHECK
+
+// CHECK-LABEL: i32 @process
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %tobool.not = icmp eq ptr %p, null
+// CHECK-NEXT: br i1 %tobool.not, label %cleanup, label %if.end
+
+// CHECK-LABEL: ptr @call_memcpy
+// CHECK-NEXT: entry:
+// CHECK-NEXT: tail call void @llvm.memcpy.p0.p0.i64
+// CHECK-NEXT: ret ptr null
+
+
+// NOCHECK-LABEL: i32 @process
+// NOCHECK-NOT: icmp eq ptr %p, null
+
+// NOCHECK-LABEL: ptr @call_memcpy
+// NOCHECK-NEXT: entry:
+// NOCHECK-NEXT: ret ptr null
+
+struct Obj { int value; int extra; };
+
+int process(struct Obj* p) {
+ int v = p->value;
+ if (!p)
+ return -1;
+ return v + p->extra;
+}
+
+void* call_memcpy(void* p, long long size) {
+ return __builtin_memcpy(0, p, size);
+}
More information about the cfe-commits
mailing list