From 3b5ddfc71ebf16997177eb80c0877dfae46f00a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 20 Jul 2026 10:00:34 +0200 Subject: [PATCH 1/3] add test --- test/testnullpointer.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 86b0f4aeeb9..698946b8efa 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -146,6 +146,7 @@ class TestNullPointer : public TestFixture { TEST_CASE(nullpointer106); // #13682 TEST_CASE(nullpointer107); // #13682 (FP/FN cases around guards that depend on the pointer indirectly) TEST_CASE(nullpointer108); + TEST_CASE(nullpointer109); TEST_CASE(nullpointer_addressOf); // address of TEST_CASE(nullpointerSwitch); // #2626 TEST_CASE(nullpointer_cast); // #4692 @@ -3115,6 +3116,18 @@ class TestNullPointer : public TestFixture { ASSERT_EQUALS("[test.cpp:4:10]: (error) Null pointer dereference: r [nullPointer]\n", errout_str()); } + void nullpointer109() + { + check("boost::asio::awaitable test()\n" + "{\n" + " const auto *s = getStr();\n" + " if(!s) co_return int{1};\n" + " std::print(\"{}\",*s);\n" + " co_return int{9};\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void nullpointer_addressOf() { // address of check("void f() {\n" " struct X *x = 0;\n" From 09d75c1073ba603bb454620811146e62ba5ca040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 20 Jul 2026 09:26:29 +0200 Subject: [PATCH 2/3] fix --- lib/forwardanalyzer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index c38d93155ea..14678fc22a3 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -144,7 +144,7 @@ namespace { // If we are in a loop then jump to the end if (out) *out = loopEnds.back(); - } else if (Token::Match(tok, "return|throw")) { + } else if (Token::Match(tok, "return|co_return|throw")) { traverseRecursive(tok->astOperand2(), f, traverseUnknown); traverseRecursive(tok->astOperand1(), f, traverseUnknown); return Break(Analyzer::Terminate::Escape); From 3611973c8774062007aa812b3822af5c845093a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Wed, 22 Jul 2026 13:43:15 +0200 Subject: [PATCH 3/3] Add isEscapeKeyword --- lib/astutils.cpp | 17 +++++++++++++++++ lib/astutils.h | 2 ++ lib/forwardanalyzer.cpp | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 74d2274ae6c..041e3788ec5 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -3918,3 +3918,20 @@ const Token *skipUnreachableBranch(const Token *tok) return tok; } + +bool isEscapeKeyword(const Token *tok, const Settings &settings) +{ + if (tok->str() == "return") + return true; + + if (!tok->isCpp()) + return false; + + if (tok->str() == "throw") + return true; + + if (settings.standards.cpp < Standards::CPP20) + return false; + + return tok->str() == "co_return"; +} diff --git a/lib/astutils.h b/lib/astutils.h index 2c6650068b5..79a607108fd 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -463,4 +463,6 @@ bool isUnreachableOperand(const Token *tok); const Token *skipUnreachableBranch(const Token *tok); +bool isEscapeKeyword(const Token *tok, const Settings &settings); + #endif // astutilsH diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index 14678fc22a3..3e227873b26 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -144,7 +144,7 @@ namespace { // If we are in a loop then jump to the end if (out) *out = loopEnds.back(); - } else if (Token::Match(tok, "return|co_return|throw")) { + } else if (isEscapeKeyword(tok, settings)) { traverseRecursive(tok->astOperand2(), f, traverseUnknown); traverseRecursive(tok->astOperand1(), f, traverseUnknown); return Break(Analyzer::Terminate::Escape);