template simplifier: fix new daca crashes (#2093)

This commit is contained in:
IOBYTE 2019-08-17 01:38:07 -04:00 committed by Daniel Marjamäki
parent ee7fe3aaa1
commit 04bb6c0d1f
4 changed files with 247 additions and 63 deletions

View File

@ -1237,7 +1237,9 @@ void TemplateSimplifier::simplifyTemplateAliases()
break; break;
} }
} }
if (!tok2 || tok2->str() != ">" || (!aliasDeclaration.isVariadic() && (args.size() != aliasParameters.size()))) { if (!tok2 || tok2->str() != ">" ||
(!aliasDeclaration.isVariadic() && (args.size() != aliasParameters.size())) ||
(aliasDeclaration.isVariadic() && (args.size() < aliasParameters.size()))) {
++it2; ++it2;
continue; continue;
} }
@ -1309,23 +1311,13 @@ void TemplateSimplifier::simplifyTemplateAliases()
bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::size_t numberOfArguments, const char patternAfter[]) bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::size_t numberOfArguments, const char patternAfter[])
{ {
// if (!Token::simpleMatch(instance, (name + " <").c_str())) assert(instance->strAt(1) == "<");
// return false;
if (numberOfArguments != templateParameters(instance->next())) if (numberOfArguments != templateParameters(instance->next()))
return false; return false;
if (patternAfter) { if (patternAfter) {
const Token *tok = instance; const Token *tok = instance->next()->findClosingBracket();
unsigned int indentlevel = 0;
for (tok = instance; tok && (tok->str() != ">" || indentlevel > 0); tok = tok->next()) {
if (Token::Match(tok, "<|,|(|:: %name% <") && (tok->strAt(3) == ">" || templateParameters(tok->tokAt(2))))
++indentlevel;
if (indentlevel > 0 && tok->str() == ">")
--indentlevel;
if (indentlevel > 0 && Token::Match(tok, "{|(|["))
tok = tok->link();
}
if (!tok || !Token::Match(tok->next(), patternAfter)) if (!tok || !Token::Match(tok->next(), patternAfter))
return false; return false;
} }
@ -1464,25 +1456,49 @@ void TemplateSimplifier::addNamespace(const TokenAndName &templateDeclaration, c
std::string::size_type start = 0; std::string::size_type start = 0;
std::string::size_type end = 0; std::string::size_type end = 0;
bool inTemplate = false;
int level = 0;
while ((end = templateDeclaration.scope().find(" ", start)) != std::string::npos) { while ((end = templateDeclaration.scope().find(" ", start)) != std::string::npos) {
std::string token = templateDeclaration.scope().substr(start, end - start); std::string token = templateDeclaration.scope().substr(start, end - start);
// done if scopes overlap // done if scopes overlap
if (token == tokStart->str() && tok->strAt(-1) != "::") if (token == tokStart->str() && tok->strAt(-1) != "::")
break; break;
if (insert) if (token == "<") {
mTokenList.back()->tokAt(offset)->insertToken(token, ""); inTemplate = true;
else ++level;
mTokenList.addtoken(token, tok->linenr(), tok->fileIndex()); }
if (inTemplate) {
if (insert)
mTokenList.back()->tokAt(offset)->str(mTokenList.back()->tokAt(offset)->str() + token);
else
mTokenList.back()->str(mTokenList.back()->str() + token);
if (token == ">") {
--level;
if (level == 0)
inTemplate = false;
}
} else {
if (insert)
mTokenList.back()->tokAt(offset)->insertToken(token, "");
else
mTokenList.addtoken(token, tok->linenr(), tok->fileIndex());
}
start = end + 1; start = end + 1;
} }
// don't add if it already exists // don't add if it already exists
std::string token = templateDeclaration.scope().substr(start, end - start); std::string token = templateDeclaration.scope().substr(start, end - start);
if (token != tokStart->str() || tok->strAt(-1) != "::") { if (token != tokStart->str() || tok->strAt(-1) != "::") {
if (insert) { if (insert) {
mTokenList.back()->tokAt(offset)->insertToken(templateDeclaration.scope().substr(start), ""); if (!inTemplate)
mTokenList.back()->tokAt(offset)->insertToken(templateDeclaration.scope().substr(start), "");
else
mTokenList.back()->tokAt(offset)->str(mTokenList.back()->tokAt(offset)->str() + templateDeclaration.scope().substr(start));
mTokenList.back()->tokAt(offset)->insertToken("::", ""); mTokenList.back()->tokAt(offset)->insertToken("::", "");
} else { } else {
mTokenList.addtoken(templateDeclaration.scope().substr(start), tok->linenr(), tok->fileIndex()); if (!inTemplate)
mTokenList.addtoken(templateDeclaration.scope().substr(start), tok->linenr(), tok->fileIndex());
else
mTokenList.back()->str(mTokenList.back()->str() + templateDeclaration.scope().substr(start));
mTokenList.addtoken("::", tok->linenr(), tok->fileIndex()); mTokenList.addtoken("::", tok->linenr(), tok->fileIndex());
} }
} }
@ -1842,7 +1858,7 @@ void TemplateSimplifier::expandTemplate(
++typeindentlevel; ++typeindentlevel;
else if (typetok->str() == ")") else if (typetok->str() == ")")
--typeindentlevel; --typeindentlevel;
mTokenList.addtoken(typetok, tok5->linenr(), tok5->fileIndex()); mTokenList.addtoken(typetok, tok5);
Token *back = mTokenList.back(); Token *back = mTokenList.back();
if (Token::Match(back, "{|(|[")) { if (Token::Match(back, "{|(|[")) {
brackets1.push(back); brackets1.push(back);
@ -1863,7 +1879,6 @@ void TemplateSimplifier::expandTemplate(
brackets1.pop(); brackets1.pop();
} }
back->isTemplateArg(true); back->isTemplateArg(true);
back->col(tok5->col());
added = true; added = true;
break; break;
} }
@ -1871,9 +1886,8 @@ void TemplateSimplifier::expandTemplate(
} }
} }
if (!added) { if (!added) {
mTokenList.addtoken(tok5, tok5->linenr(), tok5->fileIndex()); mTokenList.addtoken(tok5);
Token *back = mTokenList.back(); Token *back = mTokenList.back();
back->col(tok5->col());
if (Token::Match(back, "{|(|[")) { if (Token::Match(back, "{|(|[")) {
brackets2.push(back); brackets2.push(back);
} else if (back->str() == "}") { } else if (back->str() == "}") {
@ -1922,6 +1936,7 @@ void TemplateSimplifier::expandTemplate(
// FIXME use full name matching somehow // FIXME use full name matching somehow
const std::string lastName = (templateInstantiation.name().find(' ') != std::string::npos) ? templateInstantiation.name().substr(templateInstantiation.name().rfind(' ')+1) : templateInstantiation.name(); const std::string lastName = (templateInstantiation.name().find(' ') != std::string::npos) ? templateInstantiation.name().substr(templateInstantiation.name().rfind(' ')+1) : templateInstantiation.name();
std::stack<const Token *> templates;
for (; tok3; tok3 = tok3->next()) { for (; tok3; tok3 = tok3->next()) {
if (tok3->isName() && !Token::Match(tok3, "class|typename|struct") && !tok3->isStandardType()) { if (tok3->isName() && !Token::Match(tok3, "class|typename|struct") && !tok3->isStandardType()) {
// search for this token in the type vector // search for this token in the type vector
@ -1934,46 +1949,52 @@ void TemplateSimplifier::expandTemplate(
unsigned int typeindentlevel = 0; unsigned int typeindentlevel = 0;
std::stack<Token *> brackets1; // holds "(" and "{" tokens std::stack<Token *> brackets1; // holds "(" and "{" tokens
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token(); for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token();
typetok && (typeindentlevel>0 || !Token::Match(typetok, ",|>")); typetok && (typeindentlevel > 0 || !Token::Match(typetok, ",|>"));
typetok = typetok->next()) { typetok = typetok->next()) {
if (Token::simpleMatch(typetok, ". . .")) { if (Token::simpleMatch(typetok, ". . .")) {
typetok = typetok->tokAt(2); typetok = typetok->tokAt(2);
continue; continue;
} }
if (Token::Match(typetok, "%name% <") && (typetok->strAt(2) == ">" || templateParameters(typetok->next()))) if (Token::Match(typetok, "%name% <") &&
(typetok->strAt(2) == ">" || templateParameters(typetok->next()))) {
brackets1.push(typetok->next());
++typeindentlevel; ++typeindentlevel;
else if (typeindentlevel > 0 && typetok->str() == ">") } else if (typeindentlevel > 0 && typetok->str() == ">" && brackets1.top()->str() == "<") {
--typeindentlevel; --typeindentlevel;
else if (typetok->str() == "(") brackets1.pop();
} else if (typetok->str() == "(")
++typeindentlevel; ++typeindentlevel;
else if (typetok->str() == ")") else if (typetok->str() == ")")
--typeindentlevel; --typeindentlevel;
Token *back;
if (copy) { if (copy) {
mTokenList.addtoken(typetok, tok3->linenr(), tok3->fileIndex()); mTokenList.addtoken(typetok, tok3);
Token *back = mTokenList.back(); back = mTokenList.back();
back->col(tok3->col()); } else
if (Token::Match(back, "{|(|[")) { back = const_cast<Token *>(typetok);
brackets1.push(back); if (Token::Match(back, "{|(|["))
} else if (back->str() == "(") { brackets1.push(back);
brackets1.push(back); else if (back->str() == "}") {
} else if (back->str() == "}") { assert(brackets1.empty() == false);
assert(brackets1.empty() == false); assert(brackets1.top()->str() == "{");
assert(brackets1.top()->str() == "{"); if (copy)
Token::createMutualLinks(brackets1.top(), back); Token::createMutualLinks(brackets1.top(), back);
brackets1.pop(); brackets1.pop();
} else if (back->str() == ")") { } else if (back->str() == ")") {
assert(brackets1.empty() == false); assert(brackets1.empty() == false);
assert(brackets1.top()->str() == "("); assert(brackets1.top()->str() == "(");
if (copy)
Token::createMutualLinks(brackets1.top(), back); Token::createMutualLinks(brackets1.top(), back);
brackets1.pop(); brackets1.pop();
} else if (back->str() == "]") { } else if (back->str() == "]") {
assert(brackets1.empty() == false); assert(brackets1.empty() == false);
assert(brackets1.top()->str() == "["); assert(brackets1.top()->str() == "[");
if (copy)
Token::createMutualLinks(brackets1.top(), back); Token::createMutualLinks(brackets1.top(), back);
brackets1.pop(); brackets1.pop();
}
back->isTemplateArg(true);
} }
if (copy)
back->isTemplateArg(true);
} }
continue; continue;
} }
@ -1988,9 +2009,7 @@ void TemplateSimplifier::expandTemplate(
if (tok3 == templateDeclarationNameToken || if (tok3 == templateDeclarationNameToken ||
Token::Match(tok3, newName.c_str())) { Token::Match(tok3, newName.c_str())) {
if (copy) { if (copy) {
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex()); mTokenList.addtoken(newName, tok3);
Token *back = mTokenList.back();
back->col(tok3->col());
tok3 = closingBracket; tok3 = closingBracket;
} else { } else {
tok3->str(newName); tok3->str(newName);
@ -2011,9 +2030,7 @@ void TemplateSimplifier::expandTemplate(
(isClass ? tok3->strAt(1) != "(" : true)) { (isClass ? tok3->strAt(1) != "(" : true)) {
addNamespace(templateDeclaration, tok3); addNamespace(templateDeclaration, tok3);
} }
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex()); mTokenList.addtoken(newName, tok3);
Token *back = mTokenList.back();
back->col(tok3->col());
} else if (!Token::Match(tok3->next(), ":|{|=")) } else if (!Token::Match(tok3->next(), ":|{|="))
tok3->str(newName); tok3->str(newName);
continue; continue;
@ -2021,11 +2038,16 @@ void TemplateSimplifier::expandTemplate(
} }
// copy // copy
if (copy) { if (copy)
mTokenList.addtoken(tok3, tok3->linenr(), tok3->fileIndex()); mTokenList.addtoken(tok3);
Token *back = mTokenList.back();
back->col(tok3->col()); // look for template definitions
} if (Token::Match(tok3, "template <")) {
Token * tok2 = findTemplateDeclarationEnd(tok3);
if (tok2)
templates.push(tok2);
} else if (!templates.empty() && templates.top() == tok3)
templates.pop();
if (Token::Match(tok3, "%type% <") && if (Token::Match(tok3, "%type% <") &&
!Token::Match(tok3, "template|static_cast|const_cast|reinterpret_cast|dynamic_cast") && !Token::Match(tok3, "template|static_cast|const_cast|reinterpret_cast|dynamic_cast") &&
@ -2052,10 +2074,14 @@ void TemplateSimplifier::expandTemplate(
else else
scope = prev->str() + " :: " + scope; scope = prev->str() + " :: " + scope;
} }
if (copy)
newInstantiations.emplace_back(mTokenList.back(), scope); // don't add instantiations in template definitions
else if (!inTemplateDefinition) if (templates.empty()) {
newInstantiations.emplace_back(tok3, scope); if (copy)
newInstantiations.emplace_back(mTokenList.back(), scope);
else if (!inTemplateDefinition)
newInstantiations.emplace_back(tok3, scope);
}
} }
// link() newly tokens manually // link() newly tokens manually
@ -3488,6 +3514,11 @@ void TemplateSimplifier::simplifyTemplates(
if (mTemplateDeclarations.empty() && mTemplateForwardDeclarations.empty()) if (mTemplateDeclarations.empty() && mTemplateForwardDeclarations.empty())
return; return;
if (passCount != 0 && mSettings->debugtemplate && mSettings->debugnormal) {
std::string title("Template Simplifier pass " + std::to_string(passCount + 1));
mTokenList.front()->printOut(title.c_str(), mTokenList.getFiles());
}
// Copy default argument values from forward declaration to declaration // Copy default argument values from forward declaration to declaration
fixForwardDeclaredDefaultArgumentValues(); fixForwardDeclaredDefaultArgumentValues();

View File

@ -155,6 +155,40 @@ void TokenList::addtoken(std::string str, const nonneg int lineno, const nonneg
mTokensFrontBack.back->fileIndex(fileno); mTokensFrontBack.back->fileIndex(fileno);
} }
void TokenList::addtoken(std::string str, const Token *locationTok)
{
if (str.empty())
return;
// Replace hexadecimal value with decimal
const bool isHex = MathLib::isIntHex(str) ;
if (isHex || MathLib::isOct(str) || MathLib::isBin(str)) {
// TODO: It would be better if TokenList didn't simplify hexadecimal numbers
std::string suffix;
if (isHex &&
str.size() == (2 + mSettings->int_bit / 4) &&
(str[2] >= '8') && // includes A-F and a-f
MathLib::getSuffix(str).empty()
)
suffix = "U";
str = MathLib::value(str).str() + suffix;
}
if (mTokensFrontBack.back) {
mTokensFrontBack.back->insertToken(str);
} else {
mTokensFrontBack.front = new Token(&mTokensFrontBack);
mTokensFrontBack.back = mTokensFrontBack.front;
mTokensFrontBack.back->str(str);
}
if (isCPP() && str == "delete")
mTokensFrontBack.back->isKeyword(true);
mTokensFrontBack.back->linenr(locationTok->linenr());
mTokensFrontBack.back->col(locationTok->col());
mTokensFrontBack.back->fileIndex(locationTok->fileIndex());
}
void TokenList::addtoken(const Token * tok, const nonneg int lineno, const nonneg int fileno) void TokenList::addtoken(const Token * tok, const nonneg int lineno, const nonneg int fileno)
{ {
if (tok == nullptr) if (tok == nullptr)
@ -175,6 +209,48 @@ void TokenList::addtoken(const Token * tok, const nonneg int lineno, const nonne
mTokensFrontBack.back->flags(tok->flags()); mTokensFrontBack.back->flags(tok->flags());
} }
void TokenList::addtoken(const Token *tok, const Token *locationTok)
{
if (tok == nullptr || locationTok == nullptr)
return;
if (mTokensFrontBack.back) {
mTokensFrontBack.back->insertToken(tok->str(), tok->originalName());
} else {
mTokensFrontBack.front = new Token(&mTokensFrontBack);
mTokensFrontBack.back = mTokensFrontBack.front;
mTokensFrontBack.back->str(tok->str());
if (!tok->originalName().empty())
mTokensFrontBack.back->originalName(tok->originalName());
}
mTokensFrontBack.back->flags(tok->flags());
mTokensFrontBack.back->linenr(locationTok->linenr());
mTokensFrontBack.back->col(locationTok->col());
mTokensFrontBack.back->fileIndex(locationTok->fileIndex());
}
void TokenList::addtoken(const Token *tok)
{
if (tok == nullptr)
return;
if (mTokensFrontBack.back) {
mTokensFrontBack.back->insertToken(tok->str(), tok->originalName());
} else {
mTokensFrontBack.front = new Token(&mTokensFrontBack);
mTokensFrontBack.back = mTokensFrontBack.front;
mTokensFrontBack.back->str(tok->str());
if (!tok->originalName().empty())
mTokensFrontBack.back->originalName(tok->originalName());
}
mTokensFrontBack.back->flags(tok->flags());
mTokensFrontBack.back->linenr(tok->linenr());
mTokensFrontBack.back->col(tok->col());
mTokensFrontBack.back->fileIndex(tok->fileIndex());
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// copyTokens - Copy and insert tokens // copyTokens - Copy and insert tokens

View File

@ -70,7 +70,11 @@ public:
static void deleteTokens(Token *tok); static void deleteTokens(Token *tok);
void addtoken(std::string str, const nonneg int lineno, const nonneg int fileno, bool split = false); void addtoken(std::string str, const nonneg int lineno, const nonneg int fileno, bool split = false);
void addtoken(std::string str, const Token *locationTok);
void addtoken(const Token *tok, const nonneg int lineno, const nonneg int fileno); void addtoken(const Token *tok, const nonneg int lineno, const nonneg int fileno);
void addtoken(const Token *tok, const Token *locationTok);
void addtoken(const Token *tok);
static void insertTokens(Token *dest, const Token *src, nonneg int n); static void insertTokens(Token *dest, const Token *src, nonneg int n);

View File

@ -170,6 +170,9 @@ private:
TEST_CASE(template130); // #9246 TEST_CASE(template130); // #9246
TEST_CASE(template131); // #9249 TEST_CASE(template131); // #9249
TEST_CASE(template132); // #9250 TEST_CASE(template132); // #9250
TEST_CASE(template133);
TEST_CASE(template134);
TEST_CASE(template135);
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)
@ -3157,6 +3160,76 @@ private:
ASSERT_EQUALS(exp, tok(code)); ASSERT_EQUALS(exp, tok(code));
} }
void template133() {
const char code[] = "template <typename a> struct bar {\n"
" template <typename b> static bar foo(const bar<b> &c) {\n"
" return bar();\n"
" }\n"
"};\n"
"bar<short> bs;\n"
"bar<std::array<int,4>> ba;\n"
"bar<short> b1 = bar<short>::foo<std::array<int,4>>(ba);\n"
"bar<std::array<int,4>> b2 = bar<std::array<int,4>>::foo<short>(bs);";
const char act[] = "struct bar<short> ; struct bar<std::array<int,4>> ; "
"bar<short> bs ; "
"bar<std::array<int,4>> ba ; "
"bar<short> b1 ; b1 = bar<short> :: foo<std::array<int,4>> ( ba ) ; "
"bar<std::array<int,4>> b2 ; b2 = bar<std::array<int,4>> :: foo<short> ( bs ) ; "
"struct bar<short> { "
"static bar<short> foo<std::array<int,4>> ( const bar < std :: array < int , 4 > > & c ) ; "
"} ; "
"struct bar<std::array<int,4>> { "
"static bar<std::array<int,4>> foo<short> ( const bar < short > & c ) ; "
"} ; "
"bar<std::array<int,4>> bar<std::array<int,4>> :: foo<short> ( const bar < short > & c ) { "
"return bar<std::array<int,4>> ( ) ; "
"} "
"bar<short> bar<short> :: foo<std::array<int,4>> ( const bar < std :: array < int , 4 > > & c ) { "
"return bar<short> ( ) ; "
"}";
const char exp[] = "struct bar<short> ; struct bar<std::array<int,4>> ; "
"bar<short> bs ; "
"bar<std::array<int,4>> ba ; "
"bar<short> b1 ; b1 = bar<short> :: foo<std::array<int,4>> ( ba ) ; "
"bar<std::array<int,4>> b2 ; b2 = bar<std::array<int,4>> :: foo<short> ( bs ) ; "
"struct bar<short> { "
"static bar<short> foo<std::array<int,4>> ( const bar<std::array<int,4>> & c ) ; "
"} ; "
"struct bar<std::array<int,4>> { "
"static bar<std::array<int,4>> foo<short> ( const bar<short> & c ) ; "
"} ; "
"bar<std::array<int,4>> bar<std::array<int,4>> :: foo<short> ( const bar<short> & c ) { "
"return bar<std::array<int,4>> ( ) ; "
"} "
"bar<short> bar<short> :: foo<std::array<int,4>> ( const bar<std::array<int,4>> & c ) { "
"return bar<short> ( ) ; "
"}";
TODO_ASSERT_EQUALS(exp, act, tok(code));
}
void template134() {
const char code[] = "template <int a> class e { };\n"
"template <int a> class b { e<(c > a ? 1 : 0)> d; };\n"
"b<0> b0;\n"
"b<1> b1;";
const char exp[] = "class e<(c>0)> ; class e<(c>1)> ; "
"class b<0> ; class b<1> ; "
"b<0> b0 ; "
"b<1> b1 ; "
"class b<0> { e<(c>0)> d ; } ; class b<1> { e<(c>1)> d ; } ; "
"class e<(c>0)> { } ; class e<(c>1)> { } ;";
ASSERT_EQUALS(exp, tok(code));
}
void template135() {
const char code[] = "template <int> struct a { template <int b> void c(a<b>); };\n"
"a<2> d;";
const char exp[] = "struct a<2> ; "
"a<2> d ; "
"struct a<2> { template < int b > void c ( a < b > ) ; } ;";
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"