From 2bbc7abedcb51fd59d113813c83538b29f9e7090 Mon Sep 17 00:00:00 2001 From: IOBYTE Date: Tue, 1 Dec 2020 03:43:16 -0500 Subject: [PATCH] fix overloaded function lookup for explicit instantiations (#2929) --- lib/templatesimplifier.cpp | 96 +++++++++++++++++++++++++---------- test/testsimplifytemplate.cpp | 27 +++++++++- 2 files changed, 94 insertions(+), 29 deletions(-) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index ad33e718e..36486e72f 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -69,8 +69,15 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *token, const std::string & mFullName(mScope.empty() ? mName : (mScope + " :: " + mName)), mNameToken(nullptr), mParamEnd(nullptr), mFlags(0) { - if (mToken) + if (mToken) { + if (mToken->strAt(1) == "<") { + const Token *end = mToken->next()->findClosingBracket(); + if (end && end->strAt(1) == "(") { + isFunction(true); + } + } mToken->templateSimplifierPointer(this); + } } TemplateSimplifier::TokenAndName::TokenAndName(Token *token, const std::string &scope, const Token *nameToken, const Token *paramEnd) : @@ -749,7 +756,18 @@ void TemplateSimplifier::addInstantiation(Token *token, const std::string &scope static void getFunctionArguments(const Token *nameToken, std::vector &args) { - const Token *argToken = nameToken->tokAt(2); + const Token *argToken; + + if (nameToken->strAt(1) == "(") + argToken = nameToken->tokAt(2); + else if (nameToken->strAt(1) == "<") { + const Token *end = nameToken->next()->findClosingBracket(); + if (end) + argToken = end->tokAt(2); + else + return; + } else + return; if (argToken->str() == ")") return; @@ -3041,6 +3059,27 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( continue; } + if (templateDeclaration.isFunction() && instantiation.isFunction()) { + std::vector declFuncArgs; + getFunctionArguments(templateDeclaration.nameToken(), declFuncArgs); + std::vector instFuncParams; + getFunctionArguments(instantiation.token(), instFuncParams); + + if (declFuncArgs.size() != instFuncParams.size()) { + // check for default arguments + const Token* tok = templateDeclaration.nameToken()->tokAt(2); + const Token* end = templateDeclaration.nameToken()->linkAt(1); + size_t count = 0; + for (; tok != end; tok = tok->next()) { + if (tok->str() == "=") + count++; + } + + if (instFuncParams.size() < (declFuncArgs.size() - count) || instFuncParams.size() > declFuncArgs.size()) + continue; + } + } + // A global function can't be called through a pointer. if (templateDeclaration.isFunction() && templateDeclaration.scope().empty() && (instantiation.token()->strAt(-1) == "." || @@ -3300,7 +3339,26 @@ static bool specMatch( if (decl.isPartialSpecialization() || decl.isSpecialization() || decl.isAlias() || decl.isFriend()) return false; - return spec.isSameFamily(decl); + if (!spec.isSameFamily(decl)) + return false; + + // make sure the scopes and names match + if (spec.fullName() == decl.fullName()) { + if (spec.isFunction()) { + std::vector specArgs; + std::vector declArgs; + getFunctionArguments(spec.nameToken(), specArgs); + getFunctionArguments(decl.nameToken(), declArgs); + + if (specArgs.size() == declArgs.size()) { + // @todo make sure function parameters also match + return true; + } + } else + return true; + } + + return false; } void TemplateSimplifier::getSpecializations() @@ -3310,26 +3368,18 @@ void TemplateSimplifier::getSpecializations() if (spec.isSpecialization()) { bool found = false; for (auto & decl : mTemplateDeclarations) { - if (!specMatch(spec, decl)) - continue; - - // make sure the scopes and names match - if (spec.fullName() == decl.fullName()) { - // @todo make sure function parameters also match + if (specMatch(spec, decl)) { mTemplateSpecializationMap[spec.token()] = decl.token(); found = true; + break; } } if (!found) { for (auto & decl : mTemplateForwardDeclarations) { - if (!specMatch(spec, decl)) - continue; - - // make sure the scopes and names match - if (spec.fullName() == decl.fullName()) { - // @todo make sure function parameters also match + if (specMatch(spec, decl)) { mTemplateSpecializationMap[spec.token()] = decl.token(); + break; } } } @@ -3344,26 +3394,18 @@ void TemplateSimplifier::getPartialSpecializations() if (spec.isPartialSpecialization()) { bool found = false; for (auto & decl : mTemplateDeclarations) { - if (!specMatch(spec, decl)) - continue; - - // make sure the scopes and names match - if (spec.fullName() == decl.fullName()) { - // @todo make sure function parameters also match + if (specMatch(spec, decl)) { mTemplatePartialSpecializationMap[spec.token()] = decl.token(); found = true; + break; } } if (!found) { for (auto & decl : mTemplateForwardDeclarations) { - if (!specMatch(spec, decl)) - continue; - - // make sure the scopes and names match - if (spec.fullName() == decl.fullName()) { - // @todo make sure function parameters also match + if (specMatch(spec, decl)) { mTemplatePartialSpecializationMap[spec.token()] = decl.token(); + break; } } } diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index d8cb4af82..291a3744f 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -202,6 +202,7 @@ private: TEST_CASE(template157); // #9854 TEST_CASE(template158); // daca crash TEST_CASE(template159); // #9886 + TEST_CASE(template160); TEST_CASE(template_specialization_1); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_specialization_2); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template) @@ -1971,8 +1972,8 @@ private: void template87() { const char code[] = "template\n" "T f1(T t) { return t; }\n" - "template const char * f1();\n" - "template const char & f1();"; + "template const char * f1(const char *);\n" + "template const char & f1(const char &);"; const char exp[] = "const char * f1 ( const char * t ) ; " "const char & f1 ( const char & t ) ; " "const char * f1 ( const char * t ) { return t ; } " @@ -4045,6 +4046,28 @@ private: ASSERT_EQUALS(exp, tok(code)); } + void template160() { + const char code[] = "struct Fred {\n" + " template static void foo() { }\n" + " template static void foo(T) { }\n" + "};\n" + "template void Fred::foo();\n" + "template <> void Fred::foo() { }\n" + "template void Fred::foo(float);\n" + "template <> void Fred::foo(int) { }"; + const char exp[] = "struct Fred { " + "static void foo ( ) ; " + "static void foo ( ) ; " + "static void foo ( int ) ; " + "static void foo ( float ) ; " + "} ; " + "void Fred :: foo ( ) { } " + "void Fred :: foo ( int ) { } " + "void Fred :: foo ( float ) { } " + "void Fred :: foo ( ) { }"; + ASSERT_EQUALS(exp, tok(code)); + } + void template_specialization_1() { // #7868 - template specialization template struct S> {..}; const char code[] = "template struct C {};\n" "template struct S {a};\n"