aboutsummaryrefslogtreecommitdiff
path: root/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
diff options
context:
space:
mode:
authorEric Li <li.zhe.hua@gmail.com>2024-03-20 12:45:30 -0400
committerGitHub <noreply@github.com>2024-03-20 12:45:30 -0400
commita6a6066290679f23f2bd6b27afc7a06aab07590f (patch)
treebfbabcb4050a6885eaa92ccc6b6cb158dfd4ed99 /clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
parent1b5b4eebb6a012cf223954013d34c6e896720822 (diff)
downloadllvm-a6a6066290679f23f2bd6b27afc7a06aab07590f.zip
llvm-a6a6066290679f23f2bd6b27afc7a06aab07590f.tar.gz
llvm-a6a6066290679f23f2bd6b27afc7a06aab07590f.tar.bz2
[clang][dataflow] Fix crash when analyzing a coroutine (#85957)
A coroutine function body (`CoroutineBodyStmt`) may have null children, which causes `isa` to segfault.
Diffstat (limited to 'clang/unittests/Analysis/FlowSensitive/TransferTest.cpp')
-rw-r--r--clang/unittests/Analysis/FlowSensitive/TransferTest.cpp54
1 files changed, 52 insertions, 2 deletions
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index a243535..1d3b268 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -37,6 +37,40 @@ using ::testing::Ne;
using ::testing::NotNull;
using ::testing::UnorderedElementsAre;
+// Declares a minimal coroutine library.
+constexpr llvm::StringRef CoroutineLibrary = R"cc(
+struct promise;
+struct task;
+
+namespace std {
+template <class, class...>
+struct coroutine_traits {};
+template <>
+struct coroutine_traits<task> {
+ using promise_type = promise;
+};
+
+template <class Promise = void>
+struct coroutine_handle {
+ static constexpr coroutine_handle from_address(void *addr) { return {}; }
+};
+} // namespace std
+
+struct awaitable {
+ bool await_ready() const noexcept;
+ void await_suspend(std::coroutine_handle<promise>) const noexcept;
+ void await_resume() const noexcept;
+};
+struct task {};
+struct promise {
+ task get_return_object();
+ awaitable initial_suspend();
+ awaitable final_suspend() noexcept;
+ void unhandled_exception();
+ void return_void();
+};
+)cc";
+
void runDataflow(
llvm::StringRef Code,
std::function<
@@ -4607,7 +4641,7 @@ TEST(TransferTest, LoopCanProveInvariantForBoolean) {
}
TEST(TransferTest, DoesNotCrashOnUnionThisExpr) {
- std::string Code = R"(
+ std::string Code = R"cc(
union Union {
int A;
float B;
@@ -4618,7 +4652,7 @@ TEST(TransferTest, DoesNotCrashOnUnionThisExpr) {
Union B;
A = B;
}
- )";
+ )cc";
// This is a crash regression test when calling the transfer function on a
// `CXXThisExpr` that refers to a union.
runDataflow(
@@ -4628,6 +4662,22 @@ TEST(TransferTest, DoesNotCrashOnUnionThisExpr) {
LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator=");
}
+TEST(TransferTest, DoesNotCrashOnNullChildren) {
+ std::string Code = (CoroutineLibrary + R"cc(
+ task target() noexcept {
+ co_return;
+ }
+ )cc")
+ .str();
+ // This is a crash regression test when calling `AdornedCFG::build` on a
+ // statement (in this case, the `CoroutineBodyStmt`) with null children.
+ runDataflow(
+ Code,
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
+ ASTContext &) {},
+ LangStandard::lang_cxx20, /*ApplyBuiltinTransfer=*/true);
+}
+
TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) {
std::string Code = R"(
struct A {