[clang] [Clang] Fix null-pointer assertion reading CtorClosureDefaultArgs (PR #207917)
Wenju He via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 7 02:58:17 PDT 2026
https://github.com/wenju-he updated https://github.com/llvm/llvm-project/pull/207917
>From d36ab97dd4818a50a9e4b5cd91223757738715aa Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Tue, 7 Jul 2026 09:39:12 +0200
Subject: [PATCH 1/3] [Clang] Fix null-pointer assertion reading
CtorClosureDefaultArgs
BuildCtorClosureDefaultArgs deliberately leaves the first default-arg
slot null for MS ABI copy-constructor closures (the closure itself
supplies that argument), and ASTWriterDecl.cpp serializes the null.
But e7924d50db0a deserialized it with cast<>, which asserts
on null. This only triggers under the MS C++ ABI, e.g. when
throwing a class with a non-trivial copy constructor by value across
a PCH boundary, as in test
https://github.com/intel/llvm/blob/cb9b7b7/clang-tools-extra/clangd/test/sycl.test
Assisted by: Claude
---
clang/lib/Serialization/ASTReaderDecl.cpp | 2 +-
.../test/PCH/dllexport-ctor-closure-copy.cpp | 29 +++++++++++++++++++
2 files changed, 30 insertions(+), 1 deletion(-)
create mode 100644 clang/test/PCH/dllexport-ctor-closure-copy.cpp
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 86445e196722c..25598683d1d62 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2345,7 +2345,7 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
CXXDefaultArgExpr **Args =
new (Reader.getContext()) CXXDefaultArgExpr *[NumArgs];
for (unsigned I = 0; I != NumArgs; I++)
- Args[I] = cast<CXXDefaultArgExpr>(Record.readStmt());
+ Args[I] = cast_or_null<CXXDefaultArgExpr>(Record.readStmt());
D->setCtorClosureDefaultArgs(ArrayRef(Args, NumArgs));
}
diff --git a/clang/test/PCH/dllexport-ctor-closure-copy.cpp b/clang/test/PCH/dllexport-ctor-closure-copy.cpp
new file mode 100644
index 0000000000000..bc7855deaba76
--- /dev/null
+++ b/clang/test/PCH/dllexport-ctor-closure-copy.cpp
@@ -0,0 +1,29 @@
+// Test that MS ABI copy-constructor closures (built when throwing a class by
+// value whose copy constructor has default arguments) survive a PCH
+// round-trip. BuildCtorClosureDefaultArgs deliberately leaves the first
+// default-arg slot null for a copy ctor closure (the closure itself supplies
+// that argument).
+//
+// Test this without pch.
+// RUN: %clang_cc1 -fcxx-exceptions -fms-extensions -triple i386-pc-win32 -std=c++20 -include %s -emit-llvm -o - %s | FileCheck %s
+//
+// Test with pch.
+// RUN: %clang_cc1 -fcxx-exceptions -fms-extensions -triple i386-pc-win32 -std=c++20 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fcxx-exceptions -fms-extensions -triple i386-pc-win32 -std=c++20 -include-pch %t -emit-llvm -o - %s | FileCheck %s
+
+#ifndef HEADER
+#define HEADER
+
+struct Default {
+ Default(Default &, int = 42);
+};
+
+void h(Default &d) {
+ throw d;
+}
+
+// CHECK-LABEL: define {{.*}} void @"?h@@YAXAAUDefault@@@Z"
+
+#else
+
+#endif
>From 4bb4a64b69df407cdfce28c842ed01bce2c24768 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Tue, 7 Jul 2026 11:37:17 +0200
Subject: [PATCH 2/3] check ??_ODefault@@QAEXAAU0@@Z for non-pch case, add
issue link
---
clang/test/PCH/dllexport-ctor-closure-copy.cpp | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/clang/test/PCH/dllexport-ctor-closure-copy.cpp b/clang/test/PCH/dllexport-ctor-closure-copy.cpp
index bc7855deaba76..86e163f608c02 100644
--- a/clang/test/PCH/dllexport-ctor-closure-copy.cpp
+++ b/clang/test/PCH/dllexport-ctor-closure-copy.cpp
@@ -5,9 +5,11 @@
// that argument).
//
// Test this without pch.
-// RUN: %clang_cc1 -fcxx-exceptions -fms-extensions -triple i386-pc-win32 -std=c++20 -include %s -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fcxx-exceptions -fms-extensions -triple i386-pc-win32 -std=c++20 -include %s -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,CHECK-NOPCH %s
//
// Test with pch.
+// #207949: this cannot check for ??_ODefault copy-ctor closure:
+// ASTContext::CopyConstructorForExceptionObject is serialized into the PCH.
// RUN: %clang_cc1 -fcxx-exceptions -fms-extensions -triple i386-pc-win32 -std=c++20 -emit-pch -o %t %s
// RUN: %clang_cc1 -fcxx-exceptions -fms-extensions -triple i386-pc-win32 -std=c++20 -include-pch %t -emit-llvm -o - %s | FileCheck %s
@@ -23,6 +25,8 @@ void h(Default &d) {
}
// CHECK-LABEL: define {{.*}} void @"?h@@YAXAAUDefault@@@Z"
+// CHECK-NOPCH-LABEL: define linkonce_odr {{.*}} void @"??_ODefault@@QAEXAAU0@@Z"
+// CHECK-NOPCH: call {{.*}} @"??0Default@@QAE at AAU0@H at Z"({{.*}}, i32 noundef 42)
#else
>From 16a9045d17d502fd75e1979e5f8e7016899d177a Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Tue, 7 Jul 2026 11:58:04 +0200
Subject: [PATCH 3/3] add not
---
clang/test/PCH/dllexport-ctor-closure-copy.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/PCH/dllexport-ctor-closure-copy.cpp b/clang/test/PCH/dllexport-ctor-closure-copy.cpp
index 86e163f608c02..ec847f56f84ca 100644
--- a/clang/test/PCH/dllexport-ctor-closure-copy.cpp
+++ b/clang/test/PCH/dllexport-ctor-closure-copy.cpp
@@ -9,7 +9,7 @@
//
// Test with pch.
// #207949: this cannot check for ??_ODefault copy-ctor closure:
-// ASTContext::CopyConstructorForExceptionObject is serialized into the PCH.
+// ASTContext::CopyConstructorForExceptionObject is not serialized into the PCH.
// RUN: %clang_cc1 -fcxx-exceptions -fms-extensions -triple i386-pc-win32 -std=c++20 -emit-pch -o %t %s
// RUN: %clang_cc1 -fcxx-exceptions -fms-extensions -triple i386-pc-win32 -std=c++20 -include-pch %t -emit-llvm -o - %s | FileCheck %s
More information about the cfe-commits
mailing list