diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 83f183643e6..5d321dba285 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3223,6 +3223,14 @@ static Token* findEndOfFunctionCallForParameter(Token* parameterToken) return nextAfterAstRightmostLeaf(parent); } +static bool isTryEmplace(const Token* tok) +{ + if (tok->str() != "(" || !Token::simpleMatch(tok->astOperand1(), ".") || !tok->astOperand1()->astOperand1() || !Token::simpleMatch(tok->astOperand1()->astOperand2(), "try_emplace")) + return false; + const ValueType* vt = tok->astOperand1()->astOperand1()->valueType(); + return vt && vt->container && vt->container->stdAssociativeLike; +} + static void valueFlowAfterMove(const TokenList& tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger& errorLogger, const Settings& settings) { if (!tokenlist.isCPP() || settings.standards.cpp < Standards::CPP11) @@ -3265,9 +3273,17 @@ static void valueFlowAfterMove(const TokenList& tokenlist, const SymbolDatabase& const nonneg int varId = varTok->varId(); // x is not MOVED after assignment if code is: x = ... std::move(x) .. ; const Token *parent = tok->astParent(); + bool bail = false; while (parent && parent->str() != "=" && parent->str() != "return" && - !(parent->str() == "(" && isOpenParenthesisMemberFunctionCallOfVarId(parent, varId))) + !(parent->str() == "(" && isOpenParenthesisMemberFunctionCallOfVarId(parent, varId))) { + if (isTryEmplace(parent)) { + bail = true; + break; + } parent = parent->astParent(); + } + if (bail) + continue; if (parent && (parent->str() == "return" || // MOVED in return statement parent->str() == "(")) // MOVED in self assignment, isOpenParenthesisMemberFunctionCallOfVarId == true diff --git a/test/testother.cpp b/test/testother.cpp index 13e26f5f245..95c2cdf3b5c 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -304,6 +304,7 @@ class TestOther : public TestFixture { TEST_CASE(moveForRange); TEST_CASE(moveTernary); TEST_CASE(movePointerAlias); + TEST_CASE(moveTryEmplace); TEST_CASE(funcArgNamesDifferent); TEST_CASE(funcArgOrderDifferent); @@ -12730,6 +12731,17 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:5:8]: (warning) Access of moved variable '.'. [accessMoved]\n", errout_str()); } + void moveTryEmplace() + { + check("void f(std::map& m, std::string& s) {\n" // #12773 + " bool b = m.try_emplace(\"a\", std::move(s)).second;\n" + " if (!b) {\n" + " std::cout << s;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void funcArgNamesDifferent() { check("void func1(int a, int b, int c);\n" "void func1(int a, int b, int c) { }\n"