diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 8c87b324127..1c301bbf596 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2617,6 +2617,14 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti return false; } +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; +} + bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth) { if (!isMutableExpression(tok)) @@ -2631,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() == "->"))) + if (tok2->astParent() && (tok2->astParent()->isUnaryOp("*") || (astIsLHS(tok2) && tok2->astParent()->originalName() == "->" && !hasOverloadedMemberAccess(tok2)))) derefs++; if (derefs > indirect) break; 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() {