From 83c81365d1a34030862476a067b2be7f4bccd1e2 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 6 Nov 2025 13:41:46 +0100 Subject: [PATCH 1/5] Update astutils.cpp --- lib/astutils.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 8c87b324127..156c46cfab0 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2617,6 +2617,11 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti return false; } +static bool hasOverloadedMemberAccess(const Token* varTok) +{ + return !varTok || !varTok->variable() || !varTok->variable()->valueType() || varTok->variable()->valueType()->pointer == 0; +} + bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth) { if (!isMutableExpression(tok)) @@ -2631,7 +2636,7 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, (Token::simpleMatch(tok2->astParent(), ".") && !Token::Match(tok2->astParent()->astParent(), "[(,]")) || (tok2->astParent() && tok2->astParent()->isUnaryOp("&") && Token::simpleMatch(tok2->astParent()->astParent(), ".") && tok2->astParent()->astParent()->originalName()=="->") || (Token::simpleMatch(tok2->astParent(), "[") && tok2 == tok2->astParent()->astOperand1())) { - if (tok2->astParent() && (tok2->astParent()->isUnaryOp("*") || (astIsLHS(tok2) && tok2->astParent()->originalName() == "->"))) + if (tok2->astParent() && (tok2->astParent()->isUnaryOp("*") || (astIsLHS(tok2) && tok2->astParent()->originalName() == "->") && !hasOverloadedMemberAccess(tok2->astOperand2()))) derefs++; if (derefs > indirect) break; From 1a2fcc02f5ebb67e779c50e8ab64304902017526 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 6 Nov 2025 13:42:58 +0100 Subject: [PATCH 2/5] Update testother.cpp --- test/testother.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/testother.cpp b/test/testother.cpp index 8f21a7eedea..33a7714d0b0 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -3974,6 +3974,13 @@ class TestOther : public TestFixture { " return (void*)&s;\n" "}\n"); // don't crash ASSERT_EQUALS("", errout_str()); + + check("struct S { int i; };\n" // #14251 + "struct T { std::optional s; };\n" + "void f(T& t) {\n" + " t.s->i = 0;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void constParameterCallback() { From f33d65389c3499114f2410a78f46e9d617352e89 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 6 Nov 2025 13:59:03 +0100 Subject: [PATCH 3/5] Update astutils.cpp --- lib/astutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 156c46cfab0..25a841f5309 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2636,7 +2636,7 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, (Token::simpleMatch(tok2->astParent(), ".") && !Token::Match(tok2->astParent()->astParent(), "[(,]")) || (tok2->astParent() && tok2->astParent()->isUnaryOp("&") && Token::simpleMatch(tok2->astParent()->astParent(), ".") && tok2->astParent()->astParent()->originalName()=="->") || (Token::simpleMatch(tok2->astParent(), "[") && tok2 == tok2->astParent()->astOperand1())) { - if (tok2->astParent() && (tok2->astParent()->isUnaryOp("*") || (astIsLHS(tok2) && tok2->astParent()->originalName() == "->") && !hasOverloadedMemberAccess(tok2->astOperand2()))) + if (tok2->astParent() && (tok2->astParent()->isUnaryOp("*") || (astIsLHS(tok2) && tok2->astParent()->originalName() == "->" && !hasOverloadedMemberAccess(tok2->astOperand2())))) derefs++; if (derefs > indirect) break; From 47f26ccbdb87d950dea4a5d48bf2011465bdd690 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 6 Nov 2025 14:20:50 +0100 Subject: [PATCH 4/5] Update astutils.cpp --- lib/astutils.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 25a841f5309..adbf15b22d8 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2617,8 +2617,11 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti return false; } -static bool hasOverloadedMemberAccess(const Token* varTok) +static bool hasOverloadedMemberAccess(const Token* tok) { + if (!Token::simpleMatch(tok, ".)) + return false; + const Token* varTok = tok->astOperand2(); return !varTok || !varTok->variable() || !varTok->variable()->valueType() || varTok->variable()->valueType()->pointer == 0; } @@ -2636,7 +2639,7 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, (Token::simpleMatch(tok2->astParent(), ".") && !Token::Match(tok2->astParent()->astParent(), "[(,]")) || (tok2->astParent() && tok2->astParent()->isUnaryOp("&") && Token::simpleMatch(tok2->astParent()->astParent(), ".") && tok2->astParent()->astParent()->originalName()=="->") || (Token::simpleMatch(tok2->astParent(), "[") && tok2 == tok2->astParent()->astOperand1())) { - if (tok2->astParent() && (tok2->astParent()->isUnaryOp("*") || (astIsLHS(tok2) && tok2->astParent()->originalName() == "->" && !hasOverloadedMemberAccess(tok2->astOperand2())))) + if (tok2->astParent() && (tok2->astParent()->isUnaryOp("*") || (astIsLHS(tok2) && tok2->astParent()->originalName() == "->" && !hasOverloadedMemberAccess(tok2)))) derefs++; if (derefs > indirect) break; From 274d2f0fd0fe4ab68920b1f65746325883f95126 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 6 Nov 2025 15:27:57 +0100 Subject: [PATCH 5/5] Update astutils.cpp --- lib/astutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index adbf15b22d8..1c301bbf596 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2619,7 +2619,7 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti static bool hasOverloadedMemberAccess(const Token* tok) { - if (!Token::simpleMatch(tok, ".)) + if (!Token::simpleMatch(tok, ".")) return false; const Token* varTok = tok->astOperand2(); return !varTok || !varTok->variable() || !varTok->variable()->valueType() || varTok->variable()->valueType()->pointer == 0;