Skip to content

Commit 2bbc7ab

Browse files
authored
fix overloaded function lookup for explicit instantiations (cppcheck-opensource#2929)
1 parent f250e06 commit 2bbc7ab

2 files changed

Lines changed: 94 additions & 29 deletions

File tree

lib/templatesimplifier.cpp

Lines changed: 69 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,15 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *token, const std::string &
6969
mFullName(mScope.empty() ? mName : (mScope + " :: " + mName)),
7070
mNameToken(nullptr), mParamEnd(nullptr), mFlags(0)
7171
{
72-
if (mToken)
72+
if (mToken) {
73+
if (mToken->strAt(1) == "<") {
74+
const Token *end = mToken->next()->findClosingBracket();
75+
if (end && end->strAt(1) == "(") {
76+
isFunction(true);
77+
}
78+
}
7379
mToken->templateSimplifierPointer(this);
80+
}
7481
}
7582

7683
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
749756

750757
static void getFunctionArguments(const Token *nameToken, std::vector<const Token *> &args)
751758
{
752-
const Token *argToken = nameToken->tokAt(2);
759+
const Token *argToken;
760+
761+
if (nameToken->strAt(1) == "(")
762+
argToken = nameToken->tokAt(2);
763+
else if (nameToken->strAt(1) == "<") {
764+
const Token *end = nameToken->next()->findClosingBracket();
765+
if (end)
766+
argToken = end->tokAt(2);
767+
else
768+
return;
769+
} else
770+
return;
753771

754772
if (argToken->str() == ")")
755773
return;
@@ -3041,6 +3059,27 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
30413059
continue;
30423060
}
30433061

3062+
if (templateDeclaration.isFunction() && instantiation.isFunction()) {
3063+
std::vector<const Token*> declFuncArgs;
3064+
getFunctionArguments(templateDeclaration.nameToken(), declFuncArgs);
3065+
std::vector<const Token*> instFuncParams;
3066+
getFunctionArguments(instantiation.token(), instFuncParams);
3067+
3068+
if (declFuncArgs.size() != instFuncParams.size()) {
3069+
// check for default arguments
3070+
const Token* tok = templateDeclaration.nameToken()->tokAt(2);
3071+
const Token* end = templateDeclaration.nameToken()->linkAt(1);
3072+
size_t count = 0;
3073+
for (; tok != end; tok = tok->next()) {
3074+
if (tok->str() == "=")
3075+
count++;
3076+
}
3077+
3078+
if (instFuncParams.size() < (declFuncArgs.size() - count) || instFuncParams.size() > declFuncArgs.size())
3079+
continue;
3080+
}
3081+
}
3082+
30443083
// A global function can't be called through a pointer.
30453084
if (templateDeclaration.isFunction() && templateDeclaration.scope().empty() &&
30463085
(instantiation.token()->strAt(-1) == "." ||
@@ -3300,7 +3339,26 @@ static bool specMatch(
33003339
if (decl.isPartialSpecialization() || decl.isSpecialization() || decl.isAlias() || decl.isFriend())
33013340
return false;
33023341

3303-
return spec.isSameFamily(decl);
3342+
if (!spec.isSameFamily(decl))
3343+
return false;
3344+
3345+
// make sure the scopes and names match
3346+
if (spec.fullName() == decl.fullName()) {
3347+
if (spec.isFunction()) {
3348+
std::vector<const Token*> specArgs;
3349+
std::vector<const Token*> declArgs;
3350+
getFunctionArguments(spec.nameToken(), specArgs);
3351+
getFunctionArguments(decl.nameToken(), declArgs);
3352+
3353+
if (specArgs.size() == declArgs.size()) {
3354+
// @todo make sure function parameters also match
3355+
return true;
3356+
}
3357+
} else
3358+
return true;
3359+
}
3360+
3361+
return false;
33043362
}
33053363

33063364
void TemplateSimplifier::getSpecializations()
@@ -3310,26 +3368,18 @@ void TemplateSimplifier::getSpecializations()
33103368
if (spec.isSpecialization()) {
33113369
bool found = false;
33123370
for (auto & decl : mTemplateDeclarations) {
3313-
if (!specMatch(spec, decl))
3314-
continue;
3315-
3316-
// make sure the scopes and names match
3317-
if (spec.fullName() == decl.fullName()) {
3318-
// @todo make sure function parameters also match
3371+
if (specMatch(spec, decl)) {
33193372
mTemplateSpecializationMap[spec.token()] = decl.token();
33203373
found = true;
3374+
break;
33213375
}
33223376
}
33233377

33243378
if (!found) {
33253379
for (auto & decl : mTemplateForwardDeclarations) {
3326-
if (!specMatch(spec, decl))
3327-
continue;
3328-
3329-
// make sure the scopes and names match
3330-
if (spec.fullName() == decl.fullName()) {
3331-
// @todo make sure function parameters also match
3380+
if (specMatch(spec, decl)) {
33323381
mTemplateSpecializationMap[spec.token()] = decl.token();
3382+
break;
33333383
}
33343384
}
33353385
}
@@ -3344,26 +3394,18 @@ void TemplateSimplifier::getPartialSpecializations()
33443394
if (spec.isPartialSpecialization()) {
33453395
bool found = false;
33463396
for (auto & decl : mTemplateDeclarations) {
3347-
if (!specMatch(spec, decl))
3348-
continue;
3349-
3350-
// make sure the scopes and names match
3351-
if (spec.fullName() == decl.fullName()) {
3352-
// @todo make sure function parameters also match
3397+
if (specMatch(spec, decl)) {
33533398
mTemplatePartialSpecializationMap[spec.token()] = decl.token();
33543399
found = true;
3400+
break;
33553401
}
33563402
}
33573403

33583404
if (!found) {
33593405
for (auto & decl : mTemplateForwardDeclarations) {
3360-
if (!specMatch(spec, decl))
3361-
continue;
3362-
3363-
// make sure the scopes and names match
3364-
if (spec.fullName() == decl.fullName()) {
3365-
// @todo make sure function parameters also match
3406+
if (specMatch(spec, decl)) {
33663407
mTemplatePartialSpecializationMap[spec.token()] = decl.token();
3408+
break;
33673409
}
33683410
}
33693411
}

test/testsimplifytemplate.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ class TestSimplifyTemplate : public TestFixture {
202202
TEST_CASE(template157); // #9854
203203
TEST_CASE(template158); // daca crash
204204
TEST_CASE(template159); // #9886
205+
TEST_CASE(template160);
205206
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
206207
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
207208
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
@@ -1971,8 +1972,8 @@ class TestSimplifyTemplate : public TestFixture {
19711972
void template87() {
19721973
const char code[] = "template<typename T>\n"
19731974
"T f1(T t) { return t; }\n"
1974-
"template const char * f1<const char *>();\n"
1975-
"template const char & f1<const char &>();";
1975+
"template const char * f1<const char *>(const char *);\n"
1976+
"template const char & f1<const char &>(const char &);";
19761977
const char exp[] = "const char * f1<constchar*> ( const char * t ) ; "
19771978
"const char & f1<constchar&> ( const char & t ) ; "
19781979
"const char * f1<constchar*> ( const char * t ) { return t ; } "
@@ -4045,6 +4046,28 @@ class TestSimplifyTemplate : public TestFixture {
40454046
ASSERT_EQUALS(exp, tok(code));
40464047
}
40474048

4049+
void template160() {
4050+
const char code[] = "struct Fred {\n"
4051+
" template <typename T> static void foo() { }\n"
4052+
" template <typename T> static void foo(T) { }\n"
4053+
"};\n"
4054+
"template void Fred::foo<char>();\n"
4055+
"template <> void Fred::foo<bool>() { }\n"
4056+
"template void Fred::foo<float>(float);\n"
4057+
"template <> void Fred::foo<int>(int) { }";
4058+
const char exp[] = "struct Fred { "
4059+
"static void foo<bool> ( ) ; "
4060+
"static void foo<char> ( ) ; "
4061+
"static void foo<int> ( int ) ; "
4062+
"static void foo<float> ( float ) ; "
4063+
"} ; "
4064+
"void Fred :: foo<bool> ( ) { } "
4065+
"void Fred :: foo<int> ( int ) { } "
4066+
"void Fred :: foo<float> ( float ) { } "
4067+
"void Fred :: foo<char> ( ) { }";
4068+
ASSERT_EQUALS(exp, tok(code));
4069+
}
4070+
40484071
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
40494072
const char code[] = "template <typename T> struct C {};\n"
40504073
"template <typename T> struct S {a};\n"

0 commit comments

Comments
 (0)