From 32a5d66e5b1faa872b3b5a60edc1b22572d831e7 Mon Sep 17 00:00:00 2001 From: IOBYTE Date: Sat, 5 Jan 2019 05:14:09 -0500 Subject: [PATCH] Fixed #8927 (SIGSEGV below TemplateSimplifier::expandTemplate) (#1564) --- lib/templatesimplifier.cpp | 27 +++++++++++++---- test/testsimplifytemplate.cpp | 55 +++++++++++++++++++++++++++++------ 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 866983b13..a78f0ad28 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -524,6 +524,7 @@ bool TemplateSimplifier::getTemplateDeclarations() void TemplateSimplifier::getTemplateInstantiations() { std::list scopeList; + const Token *skip = nullptr; for (Token *tok = mTokenList.front(); tok; tok = tok->next()) { if (Token::Match(tok, "}|namespace|class|struct|union")) { @@ -535,12 +536,21 @@ void TemplateSimplifier::getTemplateInstantiations() tok = tok->next()->findClosingBracket(); if (!tok) break; - // #7914 - // Ignore template instantiations within template definitions: they will only be - // handled if the definition is actually instantiated - const Token *tok2 = Token::findmatch(tok, "{|;"); - if (tok2 && tok2->str() == "{") - tok = tok2->link(); + if (tok->strAt(-1) == "<") { + // Don't ignore user specialization but don't consider it an instantiation. + // Instantiations in return type, function parameters, and executable code + // are not ignored. + unsigned int pos = getTemplateNamePosition(tok); + if (pos > 0) + skip = tok->tokAt(pos); + } else { + // #7914 + // Ignore template instantiations within template definitions: they will only be + // handled if the definition is actually instantiated + const Token *tok2 = Token::findmatch(tok, "{|;"); + if (tok2 && tok2->str() == "{") + tok = tok2->link(); + } } else if (Token::Match(tok->previous(), "(|{|}|;|=|>|<<|:|.|*|& %name% ::|<") || Token::Match(tok->previous(), "%type% %name% ::|<") || Token::Match(tok->tokAt(-2), "[,:] private|protected|public %name% ::|<")) { @@ -553,6 +563,11 @@ void TemplateSimplifier::getTemplateInstantiations() if (!Token::Match(tok, "%name% <")) continue; + if (tok == skip) { + skip = nullptr; + continue; + } + // Add inner template instantiations first => go to the ">" // and then parse backwards, adding all seen instantiations const Token *tok2 = tok->next()->findClosingBracket(); diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index dd475193c..28f079513 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -131,6 +131,7 @@ private: TEST_CASE(template91); TEST_CASE(template92); TEST_CASE(template93); // crash + TEST_CASE(template94); // #8927 crash TEST_CASE(template_specialization_1); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_specialization_2); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template) @@ -927,7 +928,7 @@ private: " template struct X { T t; };" "};" "template<> struct A::X { int *t; };"; - ASSERT_EQUALS("struct A { template < typename T > struct X { T t ; } ; } ;", tok(code)); + ASSERT_EQUALS("struct A { struct X ; } ; struct A :: X { int t ; } ;", tok(code)); } void template41() { // #4710 - const in template instantiation not handled perfectly @@ -1044,12 +1045,16 @@ private: const char code[] = "template class Fred { void f(); };\n" "template void Fred::f() { }\n" "template<> void Fred::f() { }\n" - "template<> void Fred::g() { }\n"; + "template<> void Fred::f() { }\n"; - const char expected[] = "template < class T > class Fred { void f ( ) ; } ; " - "template < class T > void Fred < T > :: f ( ) { } " - "template < > void Fred < float > :: f ( ) { } " - "template < > void Fred < int > :: g ( ) { }"; + const char expected[] = "class Fred ; " + "class Fred ; " + "template < > void Fred :: f ( ) { } " + "template < > void Fred :: f ( ) { } " + "class Fred { void f ( ) ; } ; " + "void Fred :: f ( ) { } " + "class Fred { void f ( ) ; } ; " + "void Fred :: f ( ) { }"; ASSERT_EQUALS(expected, tok(code)); } @@ -1866,6 +1871,40 @@ private: ASSERT_EQUALS(exp, tok(code)); } + void template94() { // #8927 crash + const char code[] = "template \n" + "class Array { };\n" + "template\n" + "Array foo() {};\n" + "template <> Array foo() { }\n" + "template <> Array> foo>() { }\n" + "template <> Array foo() { }\n" + "template < typename T >\n" + "Array matmul() {\n" + " return foo( );\n" + "}\n" + "template Array> matmul>();"; + const char exp[] = "class Array ; " + "class Array> ; " + "class Array ; " + "Array foo ( ) ; " + "Array> foo> ( ) ; " + "Array foo ( ) ; " + "template < typename T > " + "Array < T > foo ( ) { } ; " + "Array foo ( ) { } " + "Array> foo> ( ) { } " + "Array foo ( ) { } " + "Array> matmul> ( ) ; " + "Array> matmul> ( ) { " + "return foo> ( ) ; " + "} " + "class Array { } ; " + "class Array> { } ; " + "class Array { } ;"; + ASSERT_EQUALS(exp, tok(code)); + } + void template_specialization_1() { // #7868 - template specialization template struct S> {..}; const char code[] = "template struct C {};\n" "template struct S {a};\n" @@ -2571,9 +2610,7 @@ private: "template class A { unsigned foo(); }; " "template unsigned A::foo() { return 0; }", 25)); ASSERT_EQUALS(12, templateNamePositionHelper( - "template class v {}; " - "template class A { unsigned foo(); }; " - "template<> unsigned A >::foo() { return 0; }", 30)); + "template<> unsigned A >::foo() { return 0; }", 2)); } void expandSpecialized1() {