template simplifier: remove explicit instantiations after instantiation (#1523)
* template simplifier: remove explicit instantiations after instantiation * Fix use after free crash in clang test suite.
This commit is contained in:
parent
357e2fbfb3
commit
2090866cd0
|
@ -368,6 +368,12 @@ void TemplateSimplifier::eraseTokens(Token *begin, const Token *end)
|
||||||
mTypesUsedInTemplateInstantiation[i] = nullptr;
|
mTypesUsedInTemplateInstantiation[i] = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (size_t i = 0; i < mExplicitInstantiationsToDelete.size(); ++i) {
|
||||||
|
if (mExplicitInstantiationsToDelete[i] == begin->next()) {
|
||||||
|
mExplicitInstantiationsToDelete[i]->hasTemplateSimplifierPointer(false);
|
||||||
|
mExplicitInstantiationsToDelete[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
begin->deleteNext();
|
begin->deleteNext();
|
||||||
}
|
}
|
||||||
|
@ -1023,109 +1029,112 @@ void TemplateSimplifier::expandTemplate(
|
||||||
templateDeclaration.token->insertToken(newName, "", true);
|
templateDeclaration.token->insertToken(newName, "", true);
|
||||||
templateDeclaration.token->insertToken(";", "", true);
|
templateDeclaration.token->insertToken(";", "", true);
|
||||||
} else if (copy && isFunction) {
|
} else if (copy && isFunction) {
|
||||||
// check if this is an explicit instantiation
|
Token * dst = templateDeclaration.token;
|
||||||
Token * temp = templateInstantiation.token;
|
Token * start;
|
||||||
while (temp && !Token::Match(temp->previous(), "}|;|extern"))
|
Token * end;
|
||||||
temp = temp->previous();
|
auto it = mTemplateForwardDeclarationsMap.find(dst);
|
||||||
if (Token::Match(temp, "template !!<")) {
|
if (it != mTemplateForwardDeclarationsMap.end()) {
|
||||||
// just delete "template"
|
dst = it->second;
|
||||||
deleteToken(temp);
|
const Token * temp1 = dst->tokAt(1)->findClosingBracket();
|
||||||
|
const Token * temp2 = temp1->tokAt(getTemplateNamePosition(temp1));
|
||||||
|
start = temp1->next();
|
||||||
|
end = temp2->linkAt(1)->next();
|
||||||
} else {
|
} else {
|
||||||
// add forward declaration
|
start = templateDeclarationToken->next();
|
||||||
Token * dst = templateDeclaration.token;
|
end = templateDeclarationNameToken->linkAt(1)->next();
|
||||||
Token * start;
|
}
|
||||||
Token * end;
|
unsigned int typeindentlevel = 0;
|
||||||
auto it = mTemplateForwardDeclarationsMap.find(dst);
|
while (!(typeindentlevel == 0 && Token::Match(end, ";|{|:"))) {
|
||||||
if (it != mTemplateForwardDeclarationsMap.end()) {
|
if (Token::Match(end, "<|(|{"))
|
||||||
dst = it->second;
|
++typeindentlevel;
|
||||||
const Token * temp1 = dst->tokAt(1)->findClosingBracket();
|
else if (Token::Match(end, ">|)|}"))
|
||||||
const Token * temp2 = temp1->tokAt(getTemplateNamePosition(temp1));
|
--typeindentlevel;
|
||||||
start = temp1->next();
|
end = end->next();
|
||||||
end = temp2->linkAt(1)->next();
|
}
|
||||||
|
|
||||||
|
std::map<const Token *, Token *> links;
|
||||||
|
while (start && start != end) {
|
||||||
|
unsigned int itype = 0;
|
||||||
|
while (itype < typeParametersInDeclaration.size() && typeParametersInDeclaration[itype]->str() != start->str())
|
||||||
|
++itype;
|
||||||
|
|
||||||
|
if (itype < typeParametersInDeclaration.size()) {
|
||||||
|
typeindentlevel = 0;
|
||||||
|
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype];
|
||||||
|
typetok && (typeindentlevel > 0 || !Token::Match(typetok, ",|>"));
|
||||||
|
typetok = typetok->next()) {
|
||||||
|
if (Token::simpleMatch(typetok, ". . .")) {
|
||||||
|
typetok = typetok->tokAt(2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Token::Match(typetok, "%name% <") && templateParameters(typetok->next()) > 0)
|
||||||
|
++typeindentlevel;
|
||||||
|
else if (typeindentlevel > 0 && typetok->str() == ">")
|
||||||
|
--typeindentlevel;
|
||||||
|
dst->insertToken(typetok->str(), typetok->originalName(), true);
|
||||||
|
dst->previous()->isTemplateArg(true);
|
||||||
|
dst->previous()->isSigned(typetok->isSigned());
|
||||||
|
dst->previous()->isUnsigned(typetok->isUnsigned());
|
||||||
|
dst->previous()->isLong(typetok->isLong());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
start = templateDeclarationToken->next();
|
if (start->str() == templateDeclarationNameToken->str()) {
|
||||||
end = templateDeclarationNameToken->linkAt(1)->next();
|
dst->insertToken(newName, "", true);
|
||||||
}
|
if (start->strAt(1) == "<")
|
||||||
unsigned int typeindentlevel = 0;
|
start = start->next()->findClosingBracket();
|
||||||
while (!(typeindentlevel == 0 && Token::Match(end, ";|{|:"))) {
|
|
||||||
if (Token::Match(end, "<|(|{"))
|
|
||||||
++typeindentlevel;
|
|
||||||
else if (Token::Match(end, ">|)|}"))
|
|
||||||
--typeindentlevel;
|
|
||||||
end = end->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<const Token *, Token *> links;
|
|
||||||
while (start && start != end) {
|
|
||||||
unsigned int itype = 0;
|
|
||||||
while (itype < typeParametersInDeclaration.size() && typeParametersInDeclaration[itype]->str() != start->str())
|
|
||||||
++itype;
|
|
||||||
|
|
||||||
if (itype < typeParametersInDeclaration.size()) {
|
|
||||||
typeindentlevel = 0;
|
|
||||||
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype];
|
|
||||||
typetok && (typeindentlevel > 0 || !Token::Match(typetok, ",|>"));
|
|
||||||
typetok = typetok->next()) {
|
|
||||||
if (Token::simpleMatch(typetok, ". . .")) {
|
|
||||||
typetok = typetok->tokAt(2);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (Token::Match(typetok, "%name% <") && templateParameters(typetok->next()) > 0)
|
|
||||||
++typeindentlevel;
|
|
||||||
else if (typeindentlevel > 0 && typetok->str() == ">")
|
|
||||||
--typeindentlevel;
|
|
||||||
dst->insertToken(typetok->str(), typetok->originalName(), true);
|
|
||||||
dst->previous()->isTemplateArg(true);
|
|
||||||
dst->previous()->isSigned(typetok->isSigned());
|
|
||||||
dst->previous()->isUnsigned(typetok->isUnsigned());
|
|
||||||
dst->previous()->isLong(typetok->isLong());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (start->str() == templateDeclarationNameToken->str()) {
|
// check if type is a template
|
||||||
dst->insertToken(newName, "", true);
|
if (start->strAt(1) == "<") {
|
||||||
if (start->strAt(1) == "<")
|
// get the instantiated name
|
||||||
start = start->next()->findClosingBracket();
|
Token * closing = start->next()->findClosingBracket();
|
||||||
} else {
|
std::string name;
|
||||||
// check if type is a template
|
const Token * type = start;
|
||||||
if (start->strAt(1) == "<") {
|
while (type && type != closing->next()) {
|
||||||
// get the instantiated name
|
if (!name.empty())
|
||||||
Token * closing = start->next()->findClosingBracket();
|
name += " ";
|
||||||
std::string name;
|
name += type->str();
|
||||||
const Token * type = start;
|
type = type->next();
|
||||||
while (type && type != closing->next()) {
|
|
||||||
if (!name.empty())
|
|
||||||
name += " ";
|
|
||||||
name += type->str();
|
|
||||||
type = type->next();
|
|
||||||
}
|
|
||||||
// check if type is instantiated
|
|
||||||
for (const auto & inst : mTemplateInstantiations) {
|
|
||||||
if (Token::simpleMatch(inst.nameToken, name.c_str())) {
|
|
||||||
// use the instantiated name
|
|
||||||
dst->insertToken(name, "", true);
|
|
||||||
start = closing;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// just copy the token if it wasn't instantiated
|
|
||||||
if (start != closing)
|
|
||||||
dst->insertToken(start->str(), "", true);
|
|
||||||
} else
|
|
||||||
dst->insertToken(start->str(), "", true);
|
|
||||||
}
|
|
||||||
if (start->link()) {
|
|
||||||
if (Token::Match(start, "[|{|(")) {
|
|
||||||
links[start->link()] = dst->previous();
|
|
||||||
} else if (Token::Match(start, "]|}|)")) {
|
|
||||||
Token::createMutualLinks(links[start], dst->previous());
|
|
||||||
links.erase(start);
|
|
||||||
}
|
}
|
||||||
|
// check if type is instantiated
|
||||||
|
for (const auto & inst : mTemplateInstantiations) {
|
||||||
|
if (Token::simpleMatch(inst.nameToken, name.c_str())) {
|
||||||
|
// use the instantiated name
|
||||||
|
dst->insertToken(name, "", true);
|
||||||
|
start = closing;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// just copy the token if it wasn't instantiated
|
||||||
|
if (start != closing)
|
||||||
|
dst->insertToken(start->str(), "", true);
|
||||||
|
} else
|
||||||
|
dst->insertToken(start->str(), "", true);
|
||||||
|
}
|
||||||
|
if (start->link()) {
|
||||||
|
if (Token::Match(start, "[|{|(")) {
|
||||||
|
links[start->link()] = dst->previous();
|
||||||
|
} else if (Token::Match(start, "]|}|)")) {
|
||||||
|
Token::createMutualLinks(links[start], dst->previous());
|
||||||
|
links.erase(start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start = start->next();
|
|
||||||
}
|
}
|
||||||
dst->insertToken(";", "", true);
|
|
||||||
|
start = start->next();
|
||||||
|
}
|
||||||
|
dst->insertToken(";", "", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy && (isClass || isFunction)) {
|
||||||
|
// check if this is an explicit instantiation
|
||||||
|
Token * start = templateInstantiation.token;
|
||||||
|
while (start && !Token::Match(start->previous(), "}|;|extern"))
|
||||||
|
start = start->previous();
|
||||||
|
if (Token::Match(start, "template !!<")) {
|
||||||
|
if (start->strAt(-1) == "extern")
|
||||||
|
start = start->previous();
|
||||||
|
start->hasTemplateSimplifierPointer(true);
|
||||||
|
mExplicitInstantiationsToDelete.push_back(start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1781,7 +1790,8 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
|
||||||
|
|
||||||
// Contains tokens such as "T"
|
// Contains tokens such as "T"
|
||||||
std::vector<const Token *> typeParametersInDeclaration;
|
std::vector<const Token *> typeParametersInDeclaration;
|
||||||
const Token * const tok = getTemplateParametersInDeclaration(templateDeclaration.token->tokAt(2), typeParametersInDeclaration);
|
getTemplateParametersInDeclaration(templateDeclaration.token->tokAt(2), typeParametersInDeclaration);
|
||||||
|
const Token * const tok = templateDeclaration.token->next()->findClosingBracket();
|
||||||
|
|
||||||
// bail out if the end of the file was reached
|
// bail out if the end of the file was reached
|
||||||
if (!tok)
|
if (!tok)
|
||||||
|
@ -2084,12 +2094,12 @@ void TemplateSimplifier::fixForwardDeclaredDefaultArgumentValues()
|
||||||
for (const auto & forwardDecl : mTemplateForwardDeclarations) {
|
for (const auto & forwardDecl : mTemplateForwardDeclarations) {
|
||||||
std::vector<const Token *> params1;
|
std::vector<const Token *> params1;
|
||||||
|
|
||||||
getTemplateParametersInDeclaration(forwardDecl.token, params1);
|
getTemplateParametersInDeclaration(forwardDecl.token->tokAt(2), params1);
|
||||||
|
|
||||||
for (auto & decl : mTemplateDeclarations) {
|
for (auto & decl : mTemplateDeclarations) {
|
||||||
std::vector<const Token *> params2;
|
std::vector<const Token *> params2;
|
||||||
|
|
||||||
getTemplateParametersInDeclaration(decl.token, params2);
|
getTemplateParametersInDeclaration(decl.token->tokAt(2), params2);
|
||||||
|
|
||||||
// make sure the number of arguments match
|
// make sure the number of arguments match
|
||||||
if (params1.size() == params2.size()) {
|
if (params1.size() == params2.size()) {
|
||||||
|
@ -2153,6 +2163,7 @@ void TemplateSimplifier::simplifyTemplates(
|
||||||
mTemplateForwardDeclarationsMap.clear();
|
mTemplateForwardDeclarationsMap.clear();
|
||||||
mTemplateInstantiations.clear();
|
mTemplateInstantiations.clear();
|
||||||
mInstantiatedTemplates.clear();
|
mInstantiatedTemplates.clear();
|
||||||
|
mExplicitInstantiationsToDelete.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasTemplates = getTemplateDeclarations();
|
bool hasTemplates = getTemplateDeclarations();
|
||||||
|
@ -2244,6 +2255,21 @@ void TemplateSimplifier::simplifyTemplates(
|
||||||
}
|
}
|
||||||
mMemberFunctionsToDelete.erase(mMemberFunctionsToDelete.begin());
|
mMemberFunctionsToDelete.erase(mMemberFunctionsToDelete.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove explicit instantiations
|
||||||
|
for (size_t j = 0; j < mExplicitInstantiationsToDelete.size(); ++j) {
|
||||||
|
Token * start = mExplicitInstantiationsToDelete[j];
|
||||||
|
if (start) {
|
||||||
|
Token * end = start->next();
|
||||||
|
while (end && end->str() != ";")
|
||||||
|
end = end->next();
|
||||||
|
if (start->previous())
|
||||||
|
start = start->previous();
|
||||||
|
if (end->next())
|
||||||
|
end = end->next();
|
||||||
|
eraseTokens(start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -269,6 +269,7 @@ private:
|
||||||
std::list<TokenAndName> mTemplateInstantiations;
|
std::list<TokenAndName> mTemplateInstantiations;
|
||||||
std::list<TokenAndName> mInstantiatedTemplates;
|
std::list<TokenAndName> mInstantiatedTemplates;
|
||||||
std::list<TokenAndName> mMemberFunctionsToDelete;
|
std::list<TokenAndName> mMemberFunctionsToDelete;
|
||||||
|
std::vector<Token *> mExplicitInstantiationsToDelete;
|
||||||
std::vector<Token *> mTypesUsedInTemplateInstantiation;
|
std::vector<Token *> mTypesUsedInTemplateInstantiation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,7 @@ private:
|
||||||
TEST_CASE(template83);
|
TEST_CASE(template83);
|
||||||
TEST_CASE(template84); // #8880
|
TEST_CASE(template84); // #8880
|
||||||
TEST_CASE(template85); // #8902 crash
|
TEST_CASE(template85); // #8902 crash
|
||||||
|
TEST_CASE(template86); // crash
|
||||||
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)
|
||||||
|
@ -1020,8 +1021,6 @@ private:
|
||||||
|
|
||||||
const char expected[] = "class Fred<float> ; "
|
const char expected[] = "class Fred<float> ; "
|
||||||
"class Fred<int> ; "
|
"class Fred<int> ; "
|
||||||
"template void Fred<float> :: f ( ) ; "
|
|
||||||
"template void Fred<int> :: g ( ) ; "
|
|
||||||
"class Fred<float> { void f ( ) ; void g ( ) ; } ; "
|
"class Fred<float> { void f ( ) ; void g ( ) ; } ; "
|
||||||
"void Fred<float> :: f ( ) { } "
|
"void Fred<float> :: f ( ) { } "
|
||||||
"void Fred<float> :: g ( ) { } "
|
"void Fred<float> :: g ( ) { } "
|
||||||
|
@ -1419,8 +1418,8 @@ private:
|
||||||
"void keep_range(T& value, const T mini, const T maxi){}\n"
|
"void keep_range(T& value, const T mini, const T maxi){}\n"
|
||||||
"template void keep_range<float>(float& v, const float l, const float u);\n"
|
"template void keep_range<float>(float& v, const float l, const float u);\n"
|
||||||
"template void keep_range<int>(int& v, const int l, const int u);";
|
"template void keep_range<int>(int& v, const int l, const int u);";
|
||||||
const char exp[] = "void keep_range<float> ( float & v , const float l , const float u ) ; "
|
const char exp[] = "void keep_range<float> ( float & value , const float mini , const float maxi ) ; "
|
||||||
"void keep_range<int> ( int & v , const int l , const int u ) ; "
|
"void keep_range<int> ( int & value , const int mini , const int maxi ) ; "
|
||||||
"void keep_range<float> ( float & value , const float mini , const float maxi ) { } "
|
"void keep_range<float> ( float & value , const float mini , const float maxi ) { } "
|
||||||
"void keep_range<int> ( int & value , const int mini , const int maxi ) { }";
|
"void keep_range<int> ( int & value , const int mini , const int maxi ) { }";
|
||||||
ASSERT_EQUALS(exp, tok(code));
|
ASSERT_EQUALS(exp, tok(code));
|
||||||
|
@ -1445,7 +1444,7 @@ private:
|
||||||
const char code[] = "template<typename T>\n"
|
const char code[] = "template<typename T>\n"
|
||||||
"T foo(T& value){ return value; }\n"
|
"T foo(T& value){ return value; }\n"
|
||||||
"template std::vector<std::vector<int>> foo<std::vector<std::vector<int>>>(std::vector<std::vector<int>>& v);";
|
"template std::vector<std::vector<int>> foo<std::vector<std::vector<int>>>(std::vector<std::vector<int>>& v);";
|
||||||
const char exp[] = "std :: vector < std :: vector < int > > foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & v ) ; "
|
const char exp[] = "std :: vector < std :: vector < int > > foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & value ) ; "
|
||||||
"std :: vector < std :: vector < int > > foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & value ) { return value ; }";
|
"std :: vector < std :: vector < int > > foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & value ) { return value ; }";
|
||||||
ASSERT_EQUALS(exp, tok(code));
|
ASSERT_EQUALS(exp, tok(code));
|
||||||
}
|
}
|
||||||
|
@ -1458,7 +1457,7 @@ private:
|
||||||
"std::vector<std::vector<int>> v;\n"
|
"std::vector<std::vector<int>> v;\n"
|
||||||
"v = foo<std::vector<std::vector<int>>>(v);\n";
|
"v = foo<std::vector<std::vector<int>>>(v);\n";
|
||||||
const char exp[] = "namespace NS { "
|
const char exp[] = "namespace NS { "
|
||||||
"std :: vector < std :: vector < int > > foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & v ) ; "
|
"std :: vector < std :: vector < int > > foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & value ) ; "
|
||||||
"} "
|
"} "
|
||||||
"std :: vector < std :: vector < int > > v ; "
|
"std :: vector < std :: vector < int > > v ; "
|
||||||
"v = foo<std::vector<std::vector<int>>> ( v ) ; "
|
"v = foo<std::vector<std::vector<int>>> ( v ) ; "
|
||||||
|
@ -1637,6 +1636,21 @@ private:
|
||||||
tok(code);
|
tok(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void template86() { // crash
|
||||||
|
const char code[] = "struct S {\n"
|
||||||
|
" S();\n"
|
||||||
|
"};\n"
|
||||||
|
"template <typename T>\n"
|
||||||
|
"struct U {\n"
|
||||||
|
" static S<T> u;\n"
|
||||||
|
"};\n"
|
||||||
|
"template <typename T>\n"
|
||||||
|
"S<T> U<T>::u;\n"
|
||||||
|
"template S<int> U<int>::u;\n"
|
||||||
|
"S<int> &i = U<int>::u;";
|
||||||
|
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"
|
||||||
|
@ -2206,7 +2220,6 @@ private:
|
||||||
"template < int type > struct Barney ; "
|
"template < int type > struct Barney ; "
|
||||||
"struct Barney<1> { } ; "
|
"struct Barney<1> { } ; "
|
||||||
"class Fred<1> ; "
|
"class Fred<1> ; "
|
||||||
"template class Fred<1> ; "
|
|
||||||
"} "
|
"} "
|
||||||
"class NS :: Fred<1> { "
|
"class NS :: Fred<1> { "
|
||||||
"public: "
|
"public: "
|
||||||
|
|
|
@ -2391,7 +2391,7 @@ private:
|
||||||
"public:\n"
|
"public:\n"
|
||||||
" int f() { return C< ::D,int>::f(); }\n"
|
" int f() { return C< ::D,int>::f(); }\n"
|
||||||
"};");
|
"};");
|
||||||
ASSERT_EQUALS("[test.cpp:1]: (debug) simplifyTemplates: bailing out\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:6]: (debug) Failed to instantiate template \"C\". The checking continues anyway.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void symboldatabase8() {
|
void symboldatabase8() {
|
||||||
|
|
Loading…
Reference in New Issue