Fixed #9860 (unused template not removed properly by default)

This commit is contained in:
Daniel Marjamäki 2020-11-22 16:43:36 +01:00
parent 28bc823264
commit 2cd8ea83a7
13 changed files with 126 additions and 78 deletions

View File

@ -293,18 +293,14 @@ void Token::deleteThis()
takeData(mNext); takeData(mNext);
mNext->link(nullptr); // mark as unlinked mNext->link(nullptr); // mark as unlinked
deleteNext(); deleteNext();
} else if (mPrevious && mPrevious->mPrevious) { // Copy previous to this and delete previous } else if (mPrevious) { // Copy previous to this and delete previous
takeData(mPrevious); takeData(mPrevious);
mPrevious->link(nullptr);
Token* toDelete = mPrevious; deletePrevious();
mPrevious = mPrevious->mPrevious;
mPrevious->mNext = this;
delete toDelete;
} else { } else {
// We are the last token in the list, we can't delete // We are the last token in the list, we can't delete
// ourselves, so just make us empty // ourselves, so just make us empty
str(""); str(";");
} }
} }

View File

@ -4365,7 +4365,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
reportUnknownMacros(); reportUnknownMacros();
simplifyHeaders(); simplifyHeadersAndUnusedTemplates();
// Remove __asm.. // Remove __asm..
simplifyAsm(); simplifyAsm();
@ -5027,7 +5027,7 @@ void Tokenizer::dump(std::ostream &out) const
list.front()->printValueFlow(true, out); list.front()->printValueFlow(true, out);
} }
void Tokenizer::simplifyHeaders() void Tokenizer::simplifyHeadersAndUnusedTemplates()
{ {
if (mSettings->checkHeaders && mSettings->checkUnusedTemplates) if (mSettings->checkHeaders && mSettings->checkUnusedTemplates)
// Full analysis. All information in the headers are kept. // Full analysis. All information in the headers are kept.
@ -5053,7 +5053,13 @@ void Tokenizer::simplifyHeaders()
// functions and types to keep // functions and types to keep
std::set<std::string> keep; std::set<std::string> keep;
for (const Token *tok = list.front(); tok; tok = tok->next()) { for (const Token *tok = list.front(); tok; tok = tok->next()) {
if (!tok->isName()) if (isCPP() && Token::simpleMatch(tok, "template <")) {
const Token *closingBracket = tok->next()->findClosingBracket();
if (Token::Match(closingBracket, "> class|struct %name% {"))
tok = closingBracket->linkAt(3);
}
if (!tok->isName() || tok->isKeyword())
continue; continue;
if (!checkHeaders && tok->fileIndex() != 0) if (!checkHeaders && tok->fileIndex() != 0)
@ -5088,49 +5094,42 @@ void Tokenizer::simplifyHeaders()
} }
} }
if (Token::Match(tok, "[;{}]")) { if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) {
// Remove unused function declarations // Remove unused function declarations
if (isIncluded && removeUnusedIncludedFunctions) { if (isIncluded && removeUnusedIncludedFunctions) {
while (1) { while (1) {
Token *start = tok->next(); Token *start = tok;
while (start && functionStart.find(start->str()) != functionStart.end()) while (start && functionStart.find(start->str()) != functionStart.end())
start = start->next(); start = start->next();
if (Token::Match(start, "%name% (") && Token::Match(start->linkAt(1), ") const| ;") && keep.find(start->str()) == keep.end()) if (Token::Match(start, "%name% (") && Token::Match(start->linkAt(1), ") const| ;") && keep.find(start->str()) == keep.end()) {
Token::eraseTokens(tok, start->linkAt(1)->tokAt(2)); Token::eraseTokens(tok, start->linkAt(1)->tokAt(2));
else tok->deleteThis();
} else
break; break;
} }
} }
if (isIncluded && removeUnusedIncludedClasses) { if (isIncluded && removeUnusedIncludedClasses) {
if (Token::Match(tok, "[;{}] class|struct %name% [:{]") && keep.find(tok->strAt(2)) == keep.end()) { if (Token::Match(tok, "class|struct %name% [:{]") && keep.find(tok->strAt(1)) == keep.end()) {
// Remove this class/struct // Remove this class/struct
const Token *endToken = tok->tokAt(3); const Token *endToken = tok->tokAt(2);
if (endToken->str() == ":") { if (endToken->str() == ":") {
endToken = endToken->next(); endToken = endToken->next();
while (Token::Match(endToken, "%name%|,")) while (Token::Match(endToken, "%name%|,"))
endToken = endToken->next(); endToken = endToken->next();
} }
if (endToken && endToken->str() == "{" && Token::simpleMatch(endToken->link(), "} ;")) if (endToken && endToken->str() == "{" && Token::simpleMatch(endToken->link(), "} ;")) {
Token::eraseTokens(tok, endToken->link()->next()); Token::eraseTokens(tok, endToken->link()->next());
tok->deleteThis();
}
} }
} }
if (removeUnusedTemplates || (isIncluded && removeUnusedIncludedTemplates)) { if (removeUnusedTemplates || (isIncluded && removeUnusedIncludedTemplates)) {
if (Token::Match(tok->next(), "template < %name%")) { if (Token::Match(tok, "template < %name%")) {
const Token *tok2 = tok->tokAt(3); const Token *closingBracket = tok->next()->findClosingBracket();
while (Token::Match(tok2, "%name% %name% [,=>]") || Token::Match(tok2, "typename|class ... %name% [,>]")) { if (Token::Match(closingBracket, "> class|struct %name% [;:{]") && keep.find(closingBracket->strAt(2)) == keep.end()) {
if (Token::Match(tok2, "typename|class ...")) const Token *endToken = closingBracket->tokAt(3);
tok2 = tok2->tokAt(3);
else
tok2 = tok2->tokAt(2);
if (Token::Match(tok2, "= %name% [,>]"))
tok2 = tok2->tokAt(2);
if (tok2->str() == ",")
tok2 = tok2->next();
}
if (Token::Match(tok2, "> class|struct %name% [;:{]") && keep.find(tok2->strAt(2)) == keep.end()) {
const Token *endToken = tok2->tokAt(3);
if (endToken->str() == ":") { if (endToken->str() == ":") {
endToken = endToken->next(); endToken = endToken->next();
while (Token::Match(endToken, "%name%|,")) while (Token::Match(endToken, "%name%|,"))
@ -5138,11 +5137,14 @@ void Tokenizer::simplifyHeaders()
} }
if (endToken && endToken->str() == "{") if (endToken && endToken->str() == "{")
endToken = endToken->link()->next(); endToken = endToken->link()->next();
if (endToken && endToken->str() == ";") if (endToken && endToken->str() == ";") {
Token::eraseTokens(tok, endToken); Token::eraseTokens(tok, endToken);
} else if (Token::Match(tok2, "> %type% %name% (") && Token::simpleMatch(tok2->linkAt(3), ") {") && keep.find(tok2->strAt(2)) == keep.end()) { tok->deleteThis();
const Token *endToken = tok2->linkAt(3)->linkAt(1)->next(); }
} else if (Token::Match(closingBracket, "> %type% %name% (") && Token::simpleMatch(closingBracket->linkAt(3), ") {") && keep.find(closingBracket->strAt(2)) == keep.end()) {
const Token *endToken = closingBracket->linkAt(3)->linkAt(1)->next();
Token::eraseTokens(tok, endToken); Token::eraseTokens(tok, endToken);
tok->deleteThis();
} }
} }
} }

View File

@ -169,7 +169,7 @@ public:
* - All executable code. * - All executable code.
* - Unused types/variables/etc * - Unused types/variables/etc
*/ */
void simplifyHeaders(); void simplifyHeadersAndUnusedTemplates();
/** /**
* Deletes dead code between 'begin' and 'end'. * Deletes dead code between 'begin' and 'end'.

View File

@ -31,11 +31,11 @@ public:
private: private:
Settings settings; Settings settings;
void check(const char code[], bool showAll = false) { void check(const char code[], bool inconclusive = false) {
// Clear the error buffer.. // Clear the error buffer..
errout.str(""); errout.str("");
settings.inconclusive = showAll; settings.inconclusive = inconclusive;
// Tokenize.. // Tokenize..
Tokenizer tokenizer(&settings, this); Tokenizer tokenizer(&settings, this);
@ -348,16 +348,6 @@ private:
" int x;\n" " int x;\n"
"};"); "};");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("template <class T> struct A {\n"
" A<T>() : x(0) { }\n"
" A<T>(const T & t) : x(t.x) { }\n"
"private:\n"
" int x;\n"
" int y;\n"
"};");
ASSERT_EQUALS("[test.cpp:2]: (warning) Member variable 'A::y' is not initialized in the constructor.\n"
"[test.cpp:3]: (warning) Member variable 'A::y' is not initialized in the constructor.\n", errout.str());
} }
void simple7() { // ticket #4531 void simple7() { // ticket #4531

View File

@ -1378,7 +1378,7 @@ private:
); );
// #3449 // #3449
ASSERT_EQUALS("template < typename T > struct A ;\n" ASSERT_EQUALS(";\n"
"struct B { template < typename T > struct C } ;\n" "struct B { template < typename T > struct C } ;\n"
"{ } ;", "{ } ;",
checkCode("template<typename T> struct A;\n" checkCode("template<typename T> struct A;\n"

View File

@ -6101,10 +6101,14 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
{
Settings keepTemplates;
keepTemplates.checkUnusedTemplates = true;
check("template<int n> void foo(unsigned int x) {\n" check("template<int n> void foo(unsigned int x) {\n"
"if (x <= 0);\n" "if (x <= 0);\n"
"}\n"); "}\n", &keepTemplates);
ASSERT_EQUALS("[test.cpp:2]: (style) Checking if unsigned expression 'x' is less than zero.\n", errout.str()); ASSERT_EQUALS("[test.cpp:2]: (style) Checking if unsigned expression 'x' is less than zero.\n", errout.str());
}
// #8836 // #8836
check("uint32_t value = 0xFUL;\n" check("uint32_t value = 0xFUL;\n"
@ -8743,11 +8747,14 @@ private:
} }
void forwardAndUsed() { void forwardAndUsed() {
Settings keepTemplates;
keepTemplates.checkUnusedTemplates = true;
check("template<typename T>\n" check("template<typename T>\n"
"void f(T && t) {\n" "void f(T && t) {\n"
" g(std::forward<T>(t));\n" " g(std::forward<T>(t));\n"
" T s = t;\n" " T s = t;\n"
"}"); "}", &keepTemplates);
ASSERT_EQUALS("[test.cpp:4]: (warning) Access of forwarded variable 't'.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (warning) Access of forwarded variable 't'.\n", errout.str());
} }

View File

@ -41,6 +41,9 @@ private:
void run() OVERRIDE { void run() OVERRIDE {
settings.addEnabled("portability"); settings.addEnabled("portability");
// If there are unused templates, keep those
settings.checkUnusedTemplates = true;
TEST_CASE(template1); TEST_CASE(template1);
TEST_CASE(template2); TEST_CASE(template2);
TEST_CASE(template3); TEST_CASE(template3);
@ -458,7 +461,8 @@ private:
// The expected result.. // The expected result..
const char expected[] = "class A<int> ; " const char expected[] = "class A<int> ; "
"void f ( ) { A<int> a ; } ; " "void f ( ) { A<int> a ; } "
"template < typename T > class B { void g ( ) { A < T > b ; b = A < T > :: h ( ) ; } } ; "
"class A<int> { } ;"; "class A<int> { } ;";
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
@ -1472,6 +1476,7 @@ private:
"template <class T, unsigned S> C3<T, S>::C3(const C3<T, S> &v) { C1<T *> c1; }\n" "template <class T, unsigned S> C3<T, S>::C3(const C3<T, S> &v) { C1<T *> c1; }\n"
"C3<int,6> c3;"; "C3<int,6> c3;";
const char exp[] = "struct C1<int*> ; " const char exp[] = "struct C1<int*> ; "
"template < class T > void f ( ) { x = y ? ( C1 < int > :: allocate ( 1 ) ) : 0 ; } "
"class C3<int,6> ; " "class C3<int,6> ; "
"C3<int,6> c3 ; " "C3<int,6> c3 ; "
"class C3<int,6> { } ; " "class C3<int,6> { } ; "
@ -2549,8 +2554,8 @@ private:
"template <typename T> class Fred {};\n" "template <typename T> class Fred {};\n"
"ObjectCache<Fred> _cache;"; "ObjectCache<Fred> _cache;";
const char exp[] = "class ObjectCache<Fred> ; " const char exp[] = "class ObjectCache<Fred> ; "
"ObjectCache<Fred> _cache ; " "template < typename T > class Fred { } ; "
"class ObjectCache<Fred> { } ;"; "ObjectCache<Fred> _cache ; class ObjectCache<Fred> { } ;";
ASSERT_EQUALS(exp, tok(code)); ASSERT_EQUALS(exp, tok(code));
} }
@ -4092,7 +4097,8 @@ private:
"template < class T > struct Unconst < const T & > { } ; " "template < class T > struct Unconst < const T & > { } ; "
"template < class T > struct Unconst < T * const > { } ; " "template < class T > struct Unconst < T * const > { } ; "
"template < class T1 , class T2 > struct type_equal { enum Anonymous0 { value = 0 } ; } ; " "template < class T1 , class T2 > struct type_equal { enum Anonymous0 { value = 0 } ; } ; "
"template < class T > struct type_equal < T , T > { enum Anonymous1 { value = 1 } ; } ;"; "template < class T > struct type_equal < T , T > { enum Anonymous1 { value = 1 } ; } ; "
"template < class T > struct template_is_const { enum Anonymous2 { value = ! type_equal < T , Unconst < T > :: type > :: value } ; } ;";
ASSERT_EQUALS(exp1, tok(code1)); ASSERT_EQUALS(exp1, tok(code1));
} }
@ -4372,7 +4378,7 @@ private:
const char code[] = "class Fred {\n" const char code[] = "class Fred {\n"
" template<class T> explicit Fred(T t) { }\n" " template<class T> explicit Fred(T t) { }\n"
"}"; "}";
ASSERT_EQUALS("class Fred { }", tok(code)); ASSERT_EQUALS("class Fred { template < class T > explicit Fred ( T t ) { } }", tok(code));
// #3532 // #3532
const char code2[] = "class Fred {\n" const char code2[] = "class Fred {\n"

View File

@ -46,6 +46,12 @@ private:
settings1.addEnabled("style"); settings1.addEnabled("style");
settings_windows.addEnabled("portability"); settings_windows.addEnabled("portability");
// If there are unused templates, keep those
settings0.checkUnusedTemplates = true;
settings1.checkUnusedTemplates = true;
settings_std.checkUnusedTemplates = true;
settings_windows.checkUnusedTemplates = true;
// Make sure the Tokenizer::simplifyTokenList works. // Make sure the Tokenizer::simplifyTokenList works.
// The order of the simplifications is important. So this test // The order of the simplifications is important. So this test
// case shall make sure the simplifications are done in the // case shall make sure the simplifications are done in the
@ -2883,7 +2889,7 @@ private:
{ {
const char code[] = "namespace std { }"; const char code[] = "namespace std { }";
ASSERT_EQUALS("", tok(code)); ASSERT_EQUALS(";", tok(code));
} }
{ {

View File

@ -42,6 +42,11 @@ private:
settings0.addEnabled("style"); settings0.addEnabled("style");
settings2.addEnabled("style"); settings2.addEnabled("style");
// If there are unused templates, keep those
settings0.checkUnusedTemplates = true;
settings1.checkUnusedTemplates = true;
settings2.checkUnusedTemplates = true;
TEST_CASE(simplifyTypedef1); TEST_CASE(simplifyTypedef1);
TEST_CASE(simplifyTypedef2); TEST_CASE(simplifyTypedef2);
TEST_CASE(simplifyTypedef3); TEST_CASE(simplifyTypedef3);
@ -1797,7 +1802,7 @@ private:
void simplifyTypedef75() { // ticket #2426 void simplifyTypedef75() { // ticket #2426
const char code[] = "typedef _Packed struct S { long l; };"; const char code[] = "typedef _Packed struct S { long l; };";
ASSERT_EQUALS("", tok(code, true, Settings::Native, false)); ASSERT_EQUALS(";", tok(code, true, Settings::Native, false));
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
@ -2047,7 +2052,7 @@ private:
const char code[] = "typedef long Long;\n" const char code[] = "typedef long Long;\n"
"namespace NS {\n" "namespace NS {\n"
"}"; "}";
ASSERT_EQUALS("", tok(code)); ASSERT_EQUALS(";", tok(code));
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
@ -2532,7 +2537,8 @@ private:
"template <long, class> struct c; " "template <long, class> struct c; "
"template <int g> struct d { enum { e = c<g, b>::f }; };"; "template <int g> struct d { enum { e = c<g, b>::f }; };";
const char exp [] = "class a ; " const char exp [] = "class a ; "
"template < long , class > struct c ;"; "template < long , class > struct c ; "
"template < int g > struct d { enum Anonymous0 { e = c < g , int ( a :: * ) > :: f } ; } ;";
ASSERT_EQUALS(exp, tok(code, false)); ASSERT_EQUALS(exp, tok(code, false));
} }

View File

@ -42,6 +42,11 @@ private:
settings0.addEnabled("style"); settings0.addEnabled("style");
settings2.addEnabled("style"); settings2.addEnabled("style");
// If there are unused templates, keep those
settings0.checkUnusedTemplates = true;
settings1.checkUnusedTemplates = true;
settings2.checkUnusedTemplates = true;
TEST_CASE(simplifyUsing1); TEST_CASE(simplifyUsing1);
TEST_CASE(simplifyUsing2); TEST_CASE(simplifyUsing2);
TEST_CASE(simplifyUsing3); TEST_CASE(simplifyUsing3);
@ -492,7 +497,8 @@ private:
"class c { " "class c { "
"int i ; i = 0 ; " "int i ; i = 0 ; "
"c ( ) { i -- ; } " "c ( ) { i -- ; } "
"} ;"; "} ; "
"template < class T > class s { } ;";
ASSERT_EQUALS(exp, tok(code, true, Settings::Win64)); ASSERT_EQUALS(exp, tok(code, true, Settings::Win64));
} }

View File

@ -115,6 +115,10 @@ private:
LOAD_LIB_2(settings1.library, "std.cfg"); LOAD_LIB_2(settings1.library, "std.cfg");
settings2.platform(Settings::Unspecified); settings2.platform(Settings::Unspecified);
// If there are unused templates, keep those
settings1.checkUnusedTemplates = true;
settings2.checkUnusedTemplates = true;
TEST_CASE(array); TEST_CASE(array);
TEST_CASE(stlarray1); TEST_CASE(stlarray1);
TEST_CASE(stlarray2); TEST_CASE(stlarray2);

View File

@ -47,6 +47,12 @@ private:
void run() OVERRIDE { void run() OVERRIDE {
LOAD_LIB_2(settings_windows.library, "windows.cfg"); LOAD_LIB_2(settings_windows.library, "windows.cfg");
// If there are unused templates, keep those
settings0.checkUnusedTemplates = true;
settings1.checkUnusedTemplates = true;
settings2.checkUnusedTemplates = true;
settings_windows.checkUnusedTemplates = true;
TEST_CASE(tokenize1); TEST_CASE(tokenize1);
TEST_CASE(tokenize2); TEST_CASE(tokenize2);
TEST_CASE(tokenize4); TEST_CASE(tokenize4);
@ -95,7 +101,8 @@ private:
TEST_CASE(longtok); TEST_CASE(longtok);
TEST_CASE(removeUnusedTemplates); TEST_CASE(simplifyHeadersAndUnusedTemplates1);
TEST_CASE(simplifyHeadersAndUnusedTemplates2);
TEST_CASE(simplifyCasts1); TEST_CASE(simplifyCasts1);
TEST_CASE(simplifyCasts2); TEST_CASE(simplifyCasts2);
@ -1028,7 +1035,7 @@ private:
} }
void removeUnusedTemplates() { void simplifyHeadersAndUnusedTemplates1() {
Settings s; Settings s;
s.checkUnusedTemplates = false; s.checkUnusedTemplates = false;
ASSERT_EQUALS(";", ASSERT_EQUALS(";",
@ -1044,6 +1051,22 @@ private:
"}", s)); "}", s));
} }
void simplifyHeadersAndUnusedTemplates2() {
const char code[] = "; template< typename T, u_int uBAR = 0 >\n"
"class Foo {\n"
"public:\n"
" void FooBar() {\n"
" new ( (uBAR ? uBAR : sizeof(T))) T;\n"
" }\n"
"};";
Settings s;
s.checkUnusedTemplates = false;
ASSERT_EQUALS(";", tokenizeAndStringify(code, s));
s.checkUnusedTemplates = true;
ASSERT_THROW(tokenizeAndStringify(code, s), InternalError);
}
// Dont remove "(int *)".. // Dont remove "(int *)"..
void simplifyCasts1() { void simplifyCasts1() {
@ -7467,11 +7490,11 @@ private:
} }
void simplifyEmptyNamespaces() { void simplifyEmptyNamespaces() {
ASSERT_EQUALS("", tokenizeAndStringify("namespace { }")); ASSERT_EQUALS(";", tokenizeAndStringify("namespace { }"));
ASSERT_EQUALS("", tokenizeAndStringify("namespace foo { }")); ASSERT_EQUALS(";", tokenizeAndStringify("namespace foo { }"));
ASSERT_EQUALS("", tokenizeAndStringify("namespace foo { namespace { } }")); ASSERT_EQUALS(";", tokenizeAndStringify("namespace foo { namespace { } }"));
ASSERT_EQUALS("", tokenizeAndStringify("namespace { namespace { } }")); // Ticket #9512 ASSERT_EQUALS(";", tokenizeAndStringify("namespace { namespace { } }")); // Ticket #9512
ASSERT_EQUALS("", tokenizeAndStringify("namespace foo { namespace bar { } }")); ASSERT_EQUALS(";", tokenizeAndStringify("namespace foo { namespace bar { } }"));
} }
void prepareTernaryOpForAST() { void prepareTernaryOpForAST() {
@ -8625,12 +8648,12 @@ private:
} }
} }
std::string checkHeaders(const char code[], bool f) { std::string checkHeaders(const char code[], bool checkHeadersFlag) {
// Clear the error buffer.. // Clear the error buffer..
errout.str(""); errout.str("");
Settings settings; Settings settings;
settings.checkHeaders = f; settings.checkHeaders = checkHeadersFlag;
// Raw tokens.. // Raw tokens..
std::vector<std::string> files(1, "test.cpp"); std::vector<std::string> files(1, "test.cpp");
@ -8670,12 +8693,11 @@ private:
"5: } ; void A :: g<int> ( int x ) { a = 2 ; }\n", "5: } ; void A :: g<int> ( int x ) { a = 2 ; }\n",
checkHeaders(code, true)); checkHeaders(code, true));
ASSERT_EQUALS("\n\n##file 1\n" ASSERT_EQUALS("\n\n##file 1\n\n"
"1: struct A {\n" "1:\n"
"2: int a ; a = 1 ;\n" "|\n"
"3: void f ( ) ;\n"
"4:\n" "4:\n"
"5: } ;\n", "5: ;\n",
checkHeaders(code, false)); checkHeaders(code, false));
} }
}; };

View File

@ -221,6 +221,7 @@ private:
settings.platform(Settings::Unix64); settings.platform(Settings::Unix64);
settings.standards.c = Standards::C89; settings.standards.c = Standards::C89;
settings.standards.cpp = Standards::CPP11; settings.standards.cpp = Standards::CPP11;
settings.checkUnusedTemplates = true;
Tokenizer tokenizer(&settings, this); Tokenizer tokenizer(&settings, this);
std::istringstream istr(code); std::istringstream istr(code);
@ -239,6 +240,7 @@ private:
settings.platform(Settings::Unix64); settings.platform(Settings::Unix64);
settings.standards.c = Standards::C89; settings.standards.c = Standards::C89;
settings.standards.cpp = Standards::CPP11; settings.standards.cpp = Standards::CPP11;
settings.checkUnusedTemplates = true;
Tokenizer tokenizer(&settings, this); Tokenizer tokenizer(&settings, this);
std::istringstream istr(code); std::istringstream istr(code);
@ -257,6 +259,7 @@ private:
settings.platform(Settings::Unix64); settings.platform(Settings::Unix64);
settings.standards.c = Standards::C89; settings.standards.c = Standards::C89;
settings.standards.cpp = Standards::CPP11; settings.standards.cpp = Standards::CPP11;
settings.checkUnusedTemplates = true;
Tokenizer tokenizer(&settings, this); Tokenizer tokenizer(&settings, this);
std::istringstream istr(code); std::istringstream istr(code);