@@ -848,12 +848,21 @@ namespace {
848848
849849 class DeductionSymbolTable ;
850850
851+ // a function template declaration that a call could instantiate,
852+ // together with its template type parameters
853+ struct DeductionCandidate {
854+ const TemplateSimplifier::TokenAndName *declaration;
855+ std::vector<const Token *> templateParams;
856+ };
857+
851858 // Token keyword flags are not set yet when templates are simplified so
852859 // keywords are recognized by their string.
853860 struct DeductionContext {
854861 const Settings &settings;
855862 const TokenList &tokenList;
856863 const DeductionSymbolTable &symbols;
864+ // the function templates, by name
865+ const std::multimap<std::string, DeductionCandidate> &templateFunctions;
857866
858867 // is |tok| a name that can be a user defined identifier?
859868 bool isIdentifier (const Token *tok) const {
@@ -1312,7 +1321,8 @@ namespace {
13121321 // the walk can record a declaration twice (class members are
13131322 // recorded up front and again when the body is walked)
13141323 if (std::none_of (declarations.cbegin (), declarations.cend (), [&](const ParsedType &declaration) {
1315- return sameDeducedType (declaration.type , returnType.type );
1324+ return (!declaration.type .valid && !returnType.type .valid ) ||
1325+ sameDeducedType (declaration.type , returnType.type );
13161326 }))
13171327 declarations.push_back (returnType);
13181328 }
@@ -1341,6 +1351,23 @@ namespace {
13411351 return false ;
13421352 }
13431353
1354+ // is a (non template) function with this name visible?
1355+ bool hasFunction (const std::string &name) const {
1356+ for (auto scope = mScopes .crbegin (); scope != mScopes .crend (); ++scope) {
1357+ if (scope->members .functions .find (name) != scope->members .functions .cend ())
1358+ return true ;
1359+ if (scope->memberClass .empty ())
1360+ continue ;
1361+ for (const std::string &className : withBaseClasses (scope->memberClass )) {
1362+ const auto classIt = mClassMembers .find (className);
1363+ if (classIt != mClassMembers .cend () &&
1364+ classIt->second .functions .find (name) != classIt->second .functions .cend ())
1365+ return true ;
1366+ }
1367+ }
1368+ return false ;
1369+ }
1370+
13441371 // all visible declarations of the function must agree on the return type
13451372 bool lookupFunctionReturnType (const std::string &name, ParsedType &result) const {
13461373 bool found = false ;
@@ -1574,8 +1601,12 @@ static ExprType parseOperandType(const DeductionContext &ctx, const Token *&tok,
15741601 return ExprType ();
15751602 } else if (ctx.isIdentifier (tok)) {
15761603 if (tok->next () != end && Token::simpleMatch (tok->next (), " (" )) {
1577- // function call
1604+ // function call: the return type of the visible declarations.
1605+ // When the name is also a function template the call could
1606+ // resolve to an instantiation with another return type.
15781607 ParsedType returnType;
1608+ if (ctx.templateFunctions .count (tok->str ()) != 0 )
1609+ return ExprType ();
15791610 if (!ctx.symbols .lookupFunctionReturnType (tok->str (), returnType))
15801611 return ExprType ();
15811612 if (!tok->next ()->link ())
@@ -1784,15 +1815,6 @@ static bool deduceTemplateArgumentFromParam(const ParsedType ¶m, const ExprT
17841815 return renderDeducedType (type, keepTopConst, tokens);
17851816}
17861817
1787- namespace {
1788- // a function template declaration that a call could instantiate,
1789- // together with its template type parameters
1790- struct DeductionCandidate {
1791- const TemplateSimplifier::TokenAndName *declaration;
1792- std::vector<const Token *> templateParams;
1793- };
1794- }
1795-
17961818// Deduce the template arguments of the function template call at |tok| from
17971819// the argument types and insert the explicit "< ... >" tokens after the
17981820// function name when the deduction succeeds.
@@ -1978,8 +2000,14 @@ static void recordDeclaration(const DeductionContext &ctx, DeductionSymbolTable
19782000 const Token *rpar = tok->next ()->link ();
19792001 if (Token::Match (rpar->next (), " ;|{|const|noexcept" )) {
19802002 const Token *start = findDeclarationTypeStart (ctx, tok);
1981- if (start && parseType (ctx, start, tok, parsed) == tok && parsed.type .valid )
1982- symbols.addFunction (tok->str (), parsed);
2003+ if (start) {
2004+ if (parseType (ctx, start, tok, parsed) == tok && parsed.type .valid )
2005+ symbols.addFunction (tok->str (), parsed);
2006+ else
2007+ // unsupported return type ("void" etc): record that the
2008+ // function exists but that its type is not known
2009+ symbols.addFunction (tok->str (), ParsedType ());
2010+ }
19832011 }
19842012 }
19852013}
@@ -2031,7 +2059,7 @@ void TemplateSimplifier::deduceFunctionTemplateArguments()
20312059 // during the walk so that at every call site the declarations that are
20322060 // visible there - and only those - can be looked up by name.
20332061 DeductionSymbolTable symbols;
2034- const DeductionContext ctx = { mSettings , mTokenList , symbols };
2062+ const DeductionContext ctx = { mSettings , mTokenList , symbols, functionNameMap };
20352063
20362064 // the body of the class definition that is about to start
20372065 const Token *classBodyStart = nullptr ;
@@ -2138,9 +2166,13 @@ void TemplateSimplifier::deduceFunctionTemplateArguments()
21382166 if (tok->strAt (1 ) == " (" ) {
21392167 const auto range = functionNameMap.equal_range (tok->str ());
21402168
2141- // a visible variable with the same name hides the function templates
2169+ // A visible variable with the same name hides the function
2170+ // templates. A visible non template function with the same
2171+ // name might be a better match than the templates (overload
2172+ // resolution is not supported). Bail out in both cases.
21422173 ParsedType shadowingVariable;
2143- if (range.first == range.second || ctx.symbols .lookupVariable (tok->str (), shadowingVariable))
2174+ if (range.first == range.second || ctx.symbols .lookupVariable (tok->str (), shadowingVariable) ||
2175+ ctx.symbols .hasFunction (tok->str ()))
21442176 continue ;
21452177
21462178 // The name is looked up like the compiler does: in the
0 commit comments