fix overloaded function lookup for explicit instantiations (#2929)

This commit is contained in:
IOBYTE 2020-12-01 03:43:16 -05:00 committed by GitHub
parent f250e06df7
commit 2bbc7abedc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 94 additions and 29 deletions

View File

@ -69,8 +69,15 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *token, const std::string &
mFullName(mScope.empty() ? mName : (mScope + " :: " + mName)), mFullName(mScope.empty() ? mName : (mScope + " :: " + mName)),
mNameToken(nullptr), mParamEnd(nullptr), mFlags(0) 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); mToken->templateSimplifierPointer(this);
}
} }
TemplateSimplifier::TokenAndName::TokenAndName(Token *token, const std::string &scope, const Token *nameToken, const Token *paramEnd) : 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<const Token *> &args) static void getFunctionArguments(const Token *nameToken, std::vector<const Token *> &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() == ")") if (argToken->str() == ")")
return; return;
@ -3041,6 +3059,27 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
continue; continue;
} }
if (templateDeclaration.isFunction() && instantiation.isFunction()) {
std::vector<const Token*> declFuncArgs;
getFunctionArguments(templateDeclaration.nameToken(), declFuncArgs);
std::vector<const Token*> 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. // A global function can't be called through a pointer.
if (templateDeclaration.isFunction() && templateDeclaration.scope().empty() && if (templateDeclaration.isFunction() && templateDeclaration.scope().empty() &&
(instantiation.token()->strAt(-1) == "." || (instantiation.token()->strAt(-1) == "." ||
@ -3300,7 +3339,26 @@ static bool specMatch(
if (decl.isPartialSpecialization() || decl.isSpecialization() || decl.isAlias() || decl.isFriend()) if (decl.isPartialSpecialization() || decl.isSpecialization() || decl.isAlias() || decl.isFriend())
return false; 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<const Token*> specArgs;
std::vector<const Token*> 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() void TemplateSimplifier::getSpecializations()
@ -3310,26 +3368,18 @@ void TemplateSimplifier::getSpecializations()
if (spec.isSpecialization()) { if (spec.isSpecialization()) {
bool found = false; bool found = false;
for (auto & decl : mTemplateDeclarations) { for (auto & decl : mTemplateDeclarations) {
if (!specMatch(spec, decl)) if (specMatch(spec, decl)) {
continue;
// make sure the scopes and names match
if (spec.fullName() == decl.fullName()) {
// @todo make sure function parameters also match
mTemplateSpecializationMap[spec.token()] = decl.token(); mTemplateSpecializationMap[spec.token()] = decl.token();
found = true; found = true;
break;
} }
} }
if (!found) { if (!found) {
for (auto & decl : mTemplateForwardDeclarations) { for (auto & decl : mTemplateForwardDeclarations) {
if (!specMatch(spec, decl)) if (specMatch(spec, decl)) {
continue;
// make sure the scopes and names match
if (spec.fullName() == decl.fullName()) {
// @todo make sure function parameters also match
mTemplateSpecializationMap[spec.token()] = decl.token(); mTemplateSpecializationMap[spec.token()] = decl.token();
break;
} }
} }
} }
@ -3344,26 +3394,18 @@ void TemplateSimplifier::getPartialSpecializations()
if (spec.isPartialSpecialization()) { if (spec.isPartialSpecialization()) {
bool found = false; bool found = false;
for (auto & decl : mTemplateDeclarations) { for (auto & decl : mTemplateDeclarations) {
if (!specMatch(spec, decl)) if (specMatch(spec, decl)) {
continue;
// make sure the scopes and names match
if (spec.fullName() == decl.fullName()) {
// @todo make sure function parameters also match
mTemplatePartialSpecializationMap[spec.token()] = decl.token(); mTemplatePartialSpecializationMap[spec.token()] = decl.token();
found = true; found = true;
break;
} }
} }
if (!found) { if (!found) {
for (auto & decl : mTemplateForwardDeclarations) { for (auto & decl : mTemplateForwardDeclarations) {
if (!specMatch(spec, decl)) if (specMatch(spec, decl)) {
continue;
// make sure the scopes and names match
if (spec.fullName() == decl.fullName()) {
// @todo make sure function parameters also match
mTemplatePartialSpecializationMap[spec.token()] = decl.token(); mTemplatePartialSpecializationMap[spec.token()] = decl.token();
break;
} }
} }
} }

View File

@ -202,6 +202,7 @@ private:
TEST_CASE(template157); // #9854 TEST_CASE(template157); // #9854
TEST_CASE(template158); // daca crash TEST_CASE(template158); // daca crash
TEST_CASE(template159); // #9886 TEST_CASE(template159); // #9886
TEST_CASE(template160);
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..}; TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..}; TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template) TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
@ -1971,8 +1972,8 @@ private:
void template87() { void template87() {
const char code[] = "template<typename T>\n" const char code[] = "template<typename T>\n"
"T f1(T t) { return t; }\n" "T f1(T t) { return t; }\n"
"template const char * f1<const char *>();\n" "template const char * f1<const char *>(const char *);\n"
"template const char & f1<const char &>();"; "template const char & f1<const char &>(const char &);";
const char exp[] = "const char * f1<constchar*> ( const char * t ) ; " const char exp[] = "const char * f1<constchar*> ( const char * t ) ; "
"const char & f1<constchar&> ( const char & t ) ; " "const char & f1<constchar&> ( const char & t ) ; "
"const char * f1<constchar*> ( const char * t ) { return t ; } " "const char * f1<constchar*> ( const char * t ) { return t ; } "
@ -4045,6 +4046,28 @@ private:
ASSERT_EQUALS(exp, tok(code)); ASSERT_EQUALS(exp, tok(code));
} }
void template160() {
const char code[] = "struct Fred {\n"
" template <typename T> static void foo() { }\n"
" template <typename T> static void foo(T) { }\n"
"};\n"
"template void Fred::foo<char>();\n"
"template <> void Fred::foo<bool>() { }\n"
"template void Fred::foo<float>(float);\n"
"template <> void Fred::foo<int>(int) { }";
const char exp[] = "struct Fred { "
"static void foo<bool> ( ) ; "
"static void foo<char> ( ) ; "
"static void foo<int> ( int ) ; "
"static void foo<float> ( float ) ; "
"} ; "
"void Fred :: foo<bool> ( ) { } "
"void Fred :: foo<int> ( int ) { } "
"void Fred :: foo<float> ( float ) { } "
"void Fred :: foo<char> ( ) { }";
ASSERT_EQUALS(exp, tok(code));
}
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..}; void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
const char code[] = "template <typename T> struct C {};\n" const char code[] = "template <typename T> struct C {};\n"
"template <typename T> struct S {a};\n" "template <typename T> struct S {a};\n"