/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2023 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "errortypes.h" #include "platform.h" #include "settings.h" #include "templatesimplifier.h" #include "fixture.h" #include "token.h" #include "tokenize.h" #include "tokenlist.h" #include #include // IWYU pragma: keep #include #include class TestSimplifyTemplate : public TestFixture { public: TestSimplifyTemplate() : TestFixture("TestSimplifyTemplate") {} private: // If there are unused templates, keep those const Settings settings = settingsBuilder().severity(Severity::portability).build(); void run() override { TEST_CASE(template1); TEST_CASE(template2); TEST_CASE(template3); TEST_CASE(template4); TEST_CASE(template5); TEST_CASE(template6); TEST_CASE(template7); TEST_CASE(template8); TEST_CASE(template9); TEST_CASE(template10); TEST_CASE(template11); TEST_CASE(template12); TEST_CASE(template13); TEST_CASE(template14); TEST_CASE(template15); // recursive templates TEST_CASE(template16); TEST_CASE(template17); TEST_CASE(template18); TEST_CASE(template19); TEST_CASE(template20); TEST_CASE(template21); TEST_CASE(template22); TEST_CASE(template23); TEST_CASE(template24); // #2648 - using sizeof in template parameter TEST_CASE(template25); // #2648 - another test for sizeof template parameter TEST_CASE(template26); // #2721 - passing 'char[2]' as template parameter TEST_CASE(template27); // #3350 - removing unused template in macro call TEST_CASE(template28); TEST_CASE(template30); // #3529 - template < template < .. TEST_CASE(template31); // #4010 - reference type TEST_CASE(template32); // #3818 - mismatching template not handled well TEST_CASE(template33); // #3818,#4544 - inner templates in template instantiation not handled well TEST_CASE(template34); // #3706 - namespace => hang TEST_CASE(template35); // #4074 - A<'x'> a; TEST_CASE(template36); // #4310 - passing unknown template instantiation as template argument TEST_CASE(template37); // #4544 - A a; TEST_CASE(template38); // #4832 - crash on C++11 right angle brackets TEST_CASE(template39); // #4742 - freeze TEST_CASE(template40); // #5055 - template specialization outside struct TEST_CASE(template41); // #4710 - const in instantiation not handled perfectly TEST_CASE(template42); // #4878 - variadic templates TEST_CASE(template43); // #5097 - assert due to '>>' not treated as end of template instantiation TEST_CASE(template44); // #5297 - TemplateSimplifier::simplifyCalculations not eager enough TEST_CASE(template45); // #5814 - syntax error reported for valid code TEST_CASE(template46); // #5816 - syntax error reported for valid code TEST_CASE(template47); // #6023 - syntax error reported for valid code TEST_CASE(template48); // #6134 - 100% CPU upon invalid code TEST_CASE(template49); // #6237 - template instantiation TEST_CASE(template50); // #4272 - simple partial specialization TEST_CASE(template52); // #6437 - crash upon valid code TEST_CASE(template53); // #4335 - bail out for valid code TEST_CASE(template54); // #6587 - memory corruption upon valid code TEST_CASE(template55); // #6604 - simplify "const const" to "const" in template instantiations TEST_CASE(template56); // #7117 - const ternary operator simplification as template parameter TEST_CASE(template57); // #7891 TEST_CASE(template58); // #6021 - use after free (deleted tokens in simplifyCalculations) TEST_CASE(template59); // #8051 - TemplateSimplifier::simplifyTemplateInstantiation failure TEST_CASE(template60); // handling of methods outside template definition TEST_CASE(template61); // daca2, kodi TEST_CASE(template62); // #8314 - inner template instantiation TEST_CASE(template63); // #8576 - qualified type TEST_CASE(template64); // #8683 TEST_CASE(template65); // #8321 TEST_CASE(template66); // #8725 TEST_CASE(template67); // #8122 TEST_CASE(template68); // union TEST_CASE(template69); // #8791 TEST_CASE(template70); // #5289 TEST_CASE(template71); // #8821 TEST_CASE(template72); TEST_CASE(template73); TEST_CASE(template74); TEST_CASE(template75); TEST_CASE(template76); TEST_CASE(template77); TEST_CASE(template78); TEST_CASE(template79); // #5133 TEST_CASE(template80); TEST_CASE(template81); TEST_CASE(template82); // #8603 TEST_CASE(template83); // #8867 TEST_CASE(template84); // #8880 TEST_CASE(template85); // #8902 crash TEST_CASE(template86); // crash TEST_CASE(template87); TEST_CASE(template88); // #6183 TEST_CASE(template89); // #8917 TEST_CASE(template90); // crash TEST_CASE(template91); TEST_CASE(template92); TEST_CASE(template93); // crash TEST_CASE(template94); // #8927 crash TEST_CASE(template95); // #7417 TEST_CASE(template96); // #7854 TEST_CASE(template97); TEST_CASE(template98); // #8959 TEST_CASE(template99); // #8960 TEST_CASE(template100); // #8967 TEST_CASE(template101); // #8968 TEST_CASE(template102); // #9005 TEST_CASE(template103); TEST_CASE(template104); // #9021 TEST_CASE(template105); // #9076 TEST_CASE(template106); TEST_CASE(template107); // #8663 TEST_CASE(template108); // #9109 TEST_CASE(template109); // #9144 TEST_CASE(template110); TEST_CASE(template111); // crash TEST_CASE(template112); // #9146 syntax error TEST_CASE(template113); TEST_CASE(template114); // #9155 TEST_CASE(template115); // #9153 TEST_CASE(template116); // #9178 TEST_CASE(template117); TEST_CASE(template118); TEST_CASE(template119); // #9186 TEST_CASE(template120); TEST_CASE(template121); // #9193 TEST_CASE(template122); // #9147 TEST_CASE(template123); // #9183 TEST_CASE(template124); // #9197 TEST_CASE(template125); TEST_CASE(template126); // #9217 TEST_CASE(template127); // #9225 TEST_CASE(template128); // #9224 TEST_CASE(template129); TEST_CASE(template130); // #9246 TEST_CASE(template131); // #9249 TEST_CASE(template132); // #9250 TEST_CASE(template133); TEST_CASE(template134); TEST_CASE(template135); TEST_CASE(template136); // #9287 TEST_CASE(template137); // #9288 TEST_CASE(template138); TEST_CASE(template139); TEST_CASE(template140); TEST_CASE(template141); // #9337 TEST_CASE(template142); // #9338 TEST_CASE(template143); TEST_CASE(template144); // #9046 TEST_CASE(template145); // syntax error TEST_CASE(template146); // syntax error TEST_CASE(template147); // syntax error TEST_CASE(template148); // syntax error TEST_CASE(template149); // unknown macro TEST_CASE(template150); // syntax error TEST_CASE(template151); // crash TEST_CASE(template152); // #9467 TEST_CASE(template153); // #9483 TEST_CASE(template154); // #9495 TEST_CASE(template155); // #9539 TEST_CASE(template156); TEST_CASE(template157); // #9854 TEST_CASE(template158); // daca crash TEST_CASE(template159); // #9886 TEST_CASE(template160); TEST_CASE(template161); TEST_CASE(template162); TEST_CASE(template163); // #9685 syntax error TEST_CASE(template164); // #9394 TEST_CASE(template165); // #10032 syntax error TEST_CASE(template166); // #10081 hang TEST_CASE(template167); TEST_CASE(template168); TEST_CASE(template169); TEST_CASE(template170); // crash TEST_CASE(template171); // crash TEST_CASE(template172); // #10258 crash TEST_CASE(template173); // #10332 crash TEST_CASE(template174); // #10506 hang TEST_CASE(template175); // #10908 TEST_CASE(template176); // #11146 TEST_CASE(template177); TEST_CASE(template178); 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) TEST_CASE(template_unhandled); TEST_CASE(template_default_parameter); TEST_CASE(template_forward_declared_default_parameter); TEST_CASE(template_default_type); TEST_CASE(template_typename); TEST_CASE(template_constructor); // #3152 - template constructor is removed TEST_CASE(syntax_error_templates_1); TEST_CASE(template_member_ptr); // Ticket #5786 - crash upon valid code TEST_CASE(template_namespace_1); TEST_CASE(template_namespace_2); TEST_CASE(template_namespace_3); TEST_CASE(template_namespace_4); TEST_CASE(template_namespace_5); TEST_CASE(template_namespace_6); TEST_CASE(template_namespace_7); // #8768 TEST_CASE(template_namespace_8); TEST_CASE(template_namespace_9); TEST_CASE(template_namespace_10); TEST_CASE(template_namespace_11); // #7145 TEST_CASE(template_pointer_type); TEST_CASE(template_array_type); // Test TemplateSimplifier::templateParameters TEST_CASE(templateParameters); TEST_CASE(templateNamePosition); TEST_CASE(findTemplateDeclarationEnd); TEST_CASE(getTemplateParametersInDeclaration); TEST_CASE(expandSpecialized1); TEST_CASE(expandSpecialized2); TEST_CASE(expandSpecialized3); // #8671 TEST_CASE(expandSpecialized4); TEST_CASE(expandSpecialized5); // #10494 TEST_CASE(templateAlias1); TEST_CASE(templateAlias2); TEST_CASE(templateAlias3); // #8315 TEST_CASE(templateAlias4); // #9070 TEST_CASE(templateAlias5); // Test TemplateSimplifier::instantiateMatch TEST_CASE(instantiateMatchTest); TEST_CASE(templateParameterWithoutName); // #8602 Template default parameter without name yields syntax error TEST_CASE(templateTypeDeduction1); // #8962 TEST_CASE(templateTypeDeduction2); TEST_CASE(templateTypeDeduction3); TEST_CASE(templateTypeDeduction4); // #9983 TEST_CASE(templateTypeDeduction5); TEST_CASE(simplifyTemplateArgs1); TEST_CASE(simplifyTemplateArgs2); TEST_CASE(simplifyTemplateArgs3); TEST_CASE(template_variadic_1); // #9144 TEST_CASE(template_variadic_2); // #4349 TEST_CASE(template_variadic_3); // #6172 TEST_CASE(template_variadic_4); TEST_CASE(template_variable_1); TEST_CASE(template_variable_2); TEST_CASE(template_variable_3); TEST_CASE(template_variable_4); TEST_CASE(simplifyDecltype); TEST_CASE(castInExpansion); TEST_CASE(fold_expression_1); TEST_CASE(fold_expression_2); TEST_CASE(fold_expression_3); TEST_CASE(fold_expression_4); TEST_CASE(concepts1); TEST_CASE(requires1); TEST_CASE(requires2); TEST_CASE(requires3); TEST_CASE(requires4); TEST_CASE(requires5); TEST_CASE(explicitBool1); TEST_CASE(explicitBool2); } #define tok(...) tok_(__FILE__, __LINE__, __VA_ARGS__) std::string tok_(const char* file, int line, const char code[], bool debugwarnings = false, Platform::Type type = Platform::Type::Native) { errout.str(""); const Settings settings1 = settingsBuilder(settings).library("std.cfg").debugwarnings(debugwarnings).platform(type).build(); Tokenizer tokenizer(&settings1, this); std::istringstream istr(code); ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), file, line); return tokenizer.tokens()->stringifyList(nullptr, true); } void template1() { const char code[] = "template T f(T val) { T a; }\n" "f(10);"; const char expected[] = "int f ( int val ) ; " "f ( 10 ) ; " "int f ( int val ) { int a ; }"; ASSERT_EQUALS(expected, tok(code)); } void template2() { const char code[] = "template class Fred { T a; };\n" "Fred fred;"; const char expected[] = "class Fred ; " "Fred fred ; " "class Fred { int a ; } ;"; ASSERT_EQUALS(expected, tok(code)); } void template3() { const char code[] = "template class Fred { T data[sz]; };\n" "Fred fred;"; const char expected[] = "class Fred ; " "Fred fred ; " "class Fred { float data [ 4 ] ; } ;"; ASSERT_EQUALS(expected, tok(code)); } void template4() { const char code[] = "template class Fred { Fred(); };\n" "Fred fred;"; const char expected[] = "class Fred ; " "Fred fred ; " "class Fred { Fred ( ) ; } ;"; ASSERT_EQUALS(expected, tok(code)); } void template5() { const char code[] = "template class Fred { };\n" "template Fred::Fred() { }\n" "Fred fred;"; const char expected[] = "class Fred ; " "Fred fred ; " "class Fred { } ; " "Fred :: Fred ( ) { }"; ASSERT_EQUALS(expected, tok(code)); } void template6() { const char code[] = "template class Fred { };\n" "Fred fred1;\n" "Fred fred2;"; const char expected[] = "class Fred ; " "Fred fred1 ; " "Fred fred2 ; " "class Fred { } ;"; ASSERT_EQUALS(expected, tok(code)); } void template7() { // A template class that is not used => no simplification { const char code[] = "template \n" "class ABC\n" "{\n" "public:\n" " typedef ABC m;\n" "};\n"; const char expected[] = "template < class T > class ABC { public: } ;"; ASSERT_EQUALS(expected, tok(code)); } { const char code[] = "template class ABC {\n" "public:\n" " typedef std::vector type;\n" "};\n" "int main() {\n" " ABC::type v;\n" " v.push_back(4);\n" " return 0;\n" "}\n"; const char wanted[] = "class ABC ; " "int main ( ) { " "std :: vector < int > v ; " "v . push_back ( 4 ) ; " "return 0 ; " "} " "class ABC { public: } ;"; const char current[] = "class ABC ; " "int main ( ) { " "ABC :: type v ; " "v . push_back ( 4 ) ; " "return 0 ; " "} " "class ABC { public: } ;"; TODO_ASSERT_EQUALS(wanted, current, tok(code)); } { const char code[] = "template class ABC {\n" "public:\n" " typedef std::vector type;\n" " void f()\n" " {\n" " ABC::type v;\n" " v.push_back(4);\n" " }\n" "};\n"; const char expected[] = "template < typename T > class ABC { " "public: void f ( ) { " "ABC < int > :: type v ; " "v . push_back ( 4 ) ; " "} " "} ;"; ASSERT_EQUALS(expected, tok(code)); } } // Template definitions but no usage => no expansion void template8() { const char code[] = "template class A;\n" "template class B;\n" "\n" "typedef A x;\n" "typedef B y;\n" "\n" "template class A {\n" " void f() {\n" " B a = B::g();\n" " T b = 0;\n" " if (b)\n" " b = 0;\n" " }\n" "};\n" "\n" "template inline B h() { return B(); }\n"; ASSERT_EQUALS("template < typename T > class A ; " "template < typename T > class B ; " "template < typename T > class A { void f ( ) { B < T > a ; a = B < T > :: g ( ) ; T b ; b = 0 ; if ( b ) { b = 0 ; } } } ; " "template < typename T > B < T > h ( ) { return B < T > ( ) ; }", tok(code)); ASSERT_EQUALS("class A { template < typename T > int foo ( T d ) ; } ;", tok("class A{ template int foo(T d);};")); } void template9() { const char code[] = "template < typename T > class A { } ;\n" "\n" "void f ( ) {\n" " A < int > a ;\n" "}\n" "\n" "template < typename T >\n" "class B {\n" " void g ( ) {\n" " A < T > b = A < T > :: h ( ) ;\n" " }\n" "} ;\n"; // The expected result.. const char expected[] = "class A ; " "void f ( ) { A a ; } " "template < typename T > class B { void g ( ) { A < T > b ; b = A < T > :: h ( ) ; } } ; " "class A { } ;"; ASSERT_EQUALS(expected, tok(code)); } void template10() { const char code[] = "template T * foo()\n" "{ return new T[ui]; }\n" "\n" "void f ( )\n" "{\n" " foo<3,int>();\n" "}\n"; // The expected result.. const char expected[] = "int * foo<3,int> ( ) ; " "void f ( ) " "{" " foo<3,int> ( ) ; " "} " "int * foo<3,int> ( ) { return new int [ 3 ] ; }"; ASSERT_EQUALS(expected, tok(code)); } void template11() { const char code[] = "template T * foo()\n" "{ return new T[ui]; }\n" "\n" "void f ( )\n" "{\n" " char * p = foo<3,char>();\n" "}\n"; // The expected result.. const char expected[] = "char * foo<3,char> ( ) ; " "void f ( ) " "{" " char * p ; p = foo<3,char> ( ) ; " "} " "char * foo<3,char> ( ) { return new char [ 3 ] ; }"; ASSERT_EQUALS(expected, tok(code)); } void template12() { const char code[] = "template \n" "class A : public B\n" "{ };\n" "\n" "void f()\n" "{\n" " A<12,12,11> a;\n" "}\n"; const char expected[] = "class A<12,12,11> ; " "void f ( ) " "{" " A<12,12,11> a ; " "} " "class A<12,12,11> : public B < 12 , 12 , 0 > " "{ } ;"; ASSERT_EQUALS(expected, tok(code)); } void template13() { const char code[] = "class BB {};\n" "\n" "template \n" "class AA {\n" "public:\n" " static AA create(T* newObject);\n" " static int size();\n" "};\n" "\n" "class CC { public: CC(AA, int) {} };\n" "\n" "class XX {\n" " AA y;\n" "public:\n" " XX();\n" "};\n" "\n" "XX::XX():\n" " y(AA::create(new CC(AA(), 0)))\n" " {}\n" "\n" "int yy[AA::size()];"; const char expected[] = "class BB { } ; " "class AA ; " "class AA ; " "class CC { public: CC ( AA , int ) { } } ; " "class XX { " "AA y ; " "public: " "XX ( ) ; " "} ; " "XX :: XX ( ) : " "y ( AA :: create ( new CC ( AA ( ) , 0 ) ) ) " "{ } " "int yy [ AA :: size ( ) ] ; " "class AA { " "public: " "static AA create ( BB * newObject ) ; " "static int size ( ) ; " "} ; " "class AA { " "public: " "static AA create ( CC * newObject ) ; " "static int size ( ) ; " "} ;"; ASSERT_EQUALS(expected, tok(code)); } void template14() { const char code[] = "template <> void foo()\n" "{ x(); }\n" "\n" "int main()\n" "{\n" "foo();\n" "}\n"; const char expected[] = "void foo ( ) ; " "void foo ( ) " "{ x ( ) ; } " "int main ( ) " "{ foo ( ) ; }"; ASSERT_EQUALS(expected, tok(code)); } void template15() { // recursive templates #3130 etc const char code[] = "template void a()\n" "{\n" " a();\n" "}\n" "\n" "template <> void a<0>()\n" "{ }\n" "\n" "int main()\n" "{\n" " a<2>();\n" " return 0;\n" "}\n"; // The expected result.. const char expected[] = "void a<0> ( ) ; " "void a<2> ( ) ; " "void a<1> ( ) ; " "void a<0> ( ) { } " "int main ( ) " "{ a<2> ( ) ; return 0 ; } " "void a<2> ( ) { a<1> ( ) ; } " "void a<1> ( ) { a<0> ( ) ; }"; ASSERT_EQUALS(expected, tok(code)); // #3130 const char code2[] = "template struct vec {\n" " vec() {}\n" " vec(const vec& v) {}\n" // <- never used don't instantiate "};\n" "\n" "vec<4> v;"; const char expected2[] = "struct vec<4> ; " "vec<4> v ; " "struct vec<4> { " "vec<4> ( ) { } " "vec<4> ( const vec < 4 - 1 > & v ) { } " "} ;"; ASSERT_EQUALS(expected2, tok(code2)); } void template16() { const char code[] = "template void a()\n" "{ }\n" "\n" "template void b()\n" "{ a(); }\n" "\n" "int main()\n" "{\n" " b<2>();\n" " return 0;\n" "}\n"; const char expected[] = "void a<2> ( ) ; " "void b<2> ( ) ; " "int main ( ) { b<2> ( ) ; return 0 ; } " "void b<2> ( ) { a<2> ( ) ; } " "void a<2> ( ) { }"; ASSERT_EQUALS(expected, tok(code)); } void template17() { const char code[] = "template\n" "class Fred\n" "{\n" " template\n" " static shared_ptr< Fred > CreateFred()\n" " {\n" " }\n" "};\n" "\n" "shared_ptr i;\n"; const char expected[] = "template < class T > " "class Fred " "{ " "template < class T > " "static shared_ptr < Fred < T > > CreateFred ( ) " "{ " "} " "} ; " "shared_ptr < int > i ;"; ASSERT_EQUALS(expected, tok(code)); } void template18() { const char code[] = "template class foo { T a; };\n" "foo *f;"; const char expected[] = "class foo ; " "foo * f ; " "class foo { int a ; } ;"; ASSERT_EQUALS(expected, tok(code)); } void template19() { const char code[] = "template T & foo()\n" "{ static T temp; return temp; }\n" "\n" "void f ( )\n" "{\n" " char p = foo();\n" "}\n"; // The expected result.. const char expected[] = "char & foo ( ) ; " "void f ( ) " "{" " char p ; p = foo ( ) ; " "} " "char & foo ( ) { static char temp ; return temp ; }"; ASSERT_EQUALS(expected, tok(code)); } void template20() { // Ticket #1788 - the destructor implementation is lost const char code[] = "template class A { public: ~A(); };\n" "template A::~A() {}\n" "A a;\n"; // The expected result.. const char expected[] = "class A ; " "A a ; " "class A { public: ~ A ( ) ; } ; " "A :: ~ A ( ) { }"; ASSERT_EQUALS(expected, tok(code)); } void template21() { { const char code[] = "template struct Fred { T a; };\n" "Fred fred;"; const char expected[] = "struct Fred ; " "Fred fred ; " "struct Fred { int a ; } ;"; ASSERT_EQUALS(expected, tok(code)); } { const char code[] = "template struct Fred { T data[sz]; };\n" "Fred fred;"; const char expected[] = "struct Fred ; " "Fred fred ; " "struct Fred { float data [ 4 ] ; } ;"; ASSERT_EQUALS(expected, tok(code)); } { const char code[] = "template struct Fred { Fred(); };\n" "Fred fred;"; const char expected[] = "struct Fred ; " "Fred fred ; " "struct Fred { Fred ( ) ; } ;"; ASSERT_EQUALS(expected, tok(code)); } { const char code[] = "template struct Fred { };\n" "Fred fred1;\n" "Fred fred2;"; const char expected[] = "struct Fred ; " "Fred fred1 ; " "Fred fred2 ; " "struct Fred { } ;"; ASSERT_EQUALS(expected, tok(code)); } } void template22() { const char code[] = "template struct Fred { T a; };\n" "Fred fred;"; const char expected[] = "struct Fred ; " "Fred fred ; " "struct Fred { std :: string a ; } ;"; ASSERT_EQUALS(expected, tok(code)); } void template23() { const char code[] = "template void foo() { }\n" "void bar() {\n" " std::cout << (foo());\n" "}"; const char expected[] = "void foo ( ) ; " "void bar ( ) {" " std :: cout << ( foo ( ) ) ; " "} " "void foo ( ) { }"; ASSERT_EQUALS(expected, tok(code)); } void template24() { // #2648 const char code[] = "template struct B\n" "{\n" " int a[n];\n" "};\n" "\n" "template class bitset: B\n" "{};\n" "\n" "bitset<1> z;"; const char expected[] = "struct B<4> ; " "class bitset<1> ; " "bitset<1> z ; " "class bitset<1> : B<4> { } ; " "struct B<4> { int a [ 4 ] ; } ;"; ASSERT_EQUALS(expected, tok(code)); } void template25() { const char code[] = "template struct B\n" "{\n" " int a[n];\n" "};\n" "\n" "template class bitset: B<((sizeof(int)) ? : 1)>\n" "{};\n" "\n" "bitset<1> z;"; const char expected[] = "struct B<4> ; " "class bitset<1> ; " "bitset<1> z ; " "class bitset<1> : B<4> { } ; " "struct B<4> { int a [ 4 ] ; } ;"; ASSERT_EQUALS(expected, tok(code)); } void template26() { // #2721 const char code[] = "template\n" "class A { public: T x; };\n" "\n" "template\n" "class C: public A {};\n" "\n" "C<2> a;\n"; ASSERT_EQUALS("class A ; class C<2> ; C<2> a ; class C<2> : public A { } ; class A { public: char [ 2 ] x ; } ;", tok(code)); } void template27() { // #3350 - template inside macro call const char code[] = "X(template class Fred);"; ASSERT_THROW(tok(code), InternalError); } void template28() { // #3226 - inner template const char code[] = "template class Fred {};\n" "Fred > x;\n"; ASSERT_EQUALS("class Fred ; " "class Fred> ; " "Fred> x ; " "class Fred { } ; " "class Fred> { } ;", tok(code)); } void template30() { // #3529 - template < template < .. const char code[] = "template class A, class B> void f(){}"; ASSERT_EQUALS("template < template < class > class A , class B > void f ( ) { }", tok(code)); } void template31() { // #4010 - template reference type const char code[] = "template struct A{}; A a;"; ASSERT_EQUALS("struct A ; " "A a ; " "struct A { } ;", tok(code)); // #7409 - rvalue const char code2[] = "template struct A{}; A a;"; ASSERT_EQUALS("struct A ; " "A a ; " "struct A { } ;", tok(code2)); } void template32() { // #3818 - mismatching template not handled well const char code[] = "template struct A { };\n" "\n" "template \n" "struct B\n" "{\n" " public:\n" " A < int, Pair, int > a;\n" // mismatching parameters => don't instantiate "};\n" "\n" "B b;\n"; ASSERT_EQUALS("template < class T1 , class T2 , class T3 , class T4 > struct A { } ; " "struct B ; " "B b ; " "struct B { public: A < int , Pair < int , int > , int > a ; } ;", tok(code)); } void template33() { { // #3818 - inner templates in template instantiation not handled well const char code[] = "template struct A { };\n" "template struct B { };\n" "template struct C { A > > ab; };\n" "C c;"; ASSERT_EQUALS("struct A>> ; " "struct B> ; " "struct C ; " "C c ; " "struct C { A>> ab ; } ; " "struct B> { } ; " // <- redundant.. but nevermind "struct A>> { } ;", tok(code)); } { // #4544 const char code[] = "struct A { };\n" "template struct B { };\n" "template struct C { };\n" "C< B > c;"; ASSERT_EQUALS("struct A { } ; " "template < class T > struct B { } ; " // <- redundant.. but nevermind "struct C> ; " "C> c ; " "struct C> { } ;", tok(code)); } } void template34() { // #3706 - namespace => hang const char code[] = "namespace abc {\n" "template struct X { void f(X &x) {} };\n" "}\n" "template <> int X::Y(0);"; tok(code); } void template35() { // #4074 - "A<'x'> a;" is not recognized as template instantiation const char code[] = "template class A {};\n" "A <'x'> a;"; ASSERT_EQUALS("class A<'x'> ; " "A<'x'> a ; " "class A<'x'> { } ;", tok(code)); } void template36() { // #4310 - Passing unknown template instantiation as template argument const char code[] = "template struct X { T t; };\n" "template struct Y { Foo < X< Bar > > _foo; };\n" // <- Bar is unknown "Y bar;"; ASSERT_EQUALS("struct X> ; " "struct Y ; " "Y bar ; " "struct Y { Foo < X> > _foo ; } ; " "struct X> { Bar < int > t ; } ;", tok(code)); } void template37() { // #4544 - A a; { const char code[] = "class A { };\n" "template class B {};\n" "B b1;\n" "B b2;"; ASSERT_EQUALS("class A { } ; class B ; B b1 ; B b2 ; class B { } ;", tok(code)); } { const char code[] = "struct A { };\n" "template class B {};\n" "B b1;\n" "B b2;"; ASSERT_EQUALS("struct A { } ; class B ; B b1 ; B b2 ; class B { } ;", tok(code)); } { const char code[] = "enum A { };\n" "template class B {};\n" "B b1;\n" "B b2;"; ASSERT_EQUALS("enum A { } ; class B ; B b1 ; B b2 ; class B { } ;", tok(code)); } } void template_unhandled() { // An unhandled template usage should not be simplified.. ASSERT_EQUALS("x < int > ( ) ;", tok("x();")); } void template38() { // #4832 - Crash on C++11 right angle brackets const char code[] = "template class A {\n" " T mT;\n" "public:\n" " void foo() {}\n" "};\n" "\n" "int main() {\n" " A> gna1;\n" " A gna2;\n" "}\n"; const char expected[] = "class A ; " "class A> ; " "int main ( ) { " "A> gna1 ; " "A gna2 ; " "} " "class A { " "BLA mT ; " "public: " "void foo ( ) { } " "} ; " "class A> { " "A mT ; " "public: " "void foo ( ) { } " "} ;"; ASSERT_EQUALS(expected, tok(code)); } void template39() { // #4742 - Used to freeze in 1.60 const char code[] = "template struct vector {" " operator T() const;" "};" "void f() {" " vector> v;" " const vector vi = static_cast>(v);" "}"; tok(code); } void template40() { // #5055 - false negatives when there is template specialization outside struct const char code[] = "struct A {" " template struct X { T t; };" "};" "template<> struct A::X { int *t; };"; const char expected[] = "struct A { " "struct X ; " "template < typename T > struct X { T t ; } ; " "} ; " "struct A :: X { int * t ; } ;"; ASSERT_EQUALS(expected, tok(code)); } void template41() { // #4710 - const in template instantiation not handled perfectly const char code1[] = "template struct X { };\n" "void f(const X x) { }"; ASSERT_EQUALS("struct X ; " "void f ( const X x ) { } " "struct X { } ;", tok(code1)); const char code2[] = "template T f(T t) { return t; }\n" "int x() { return f(123); }"; ASSERT_EQUALS("int f ( int t ) ; " "int x ( ) { return f ( 123 ) ; } " "int f ( int t ) { return t ; }", tok(code2)); } void template42() { // #4878 cppcheck aborts in ext-blocks.cpp (clang testcode) const char code[] = "template\n" "int f0(Args ...args) {\n" " return ^ {\n" " return sizeof...(Args);\n" " }() + ^ {\n" " return sizeof...(args);\n" " }();\n" "}"; ASSERT_THROW(tok(code), InternalError); } void template43() { // #5097 - Assert due to '>>' in 'B>' not being treated as end of template instantiation const char code[] = "template struct E { typedef int Int; };\n" "template struct C { };\n" "template struct D { static int f() { return C::f(); } };\n" "template inline int f2() { return D::f(); }\n" "template int f1 (int x, T *) { int id = f2(); return id; }\n" "template struct B { void f3(B & other) { } };\n" "struct A { };\n" "template <> struct C> {\n" " static int f() { return f1>(0, reinterpret_cast*>(E::Int(-1))); }\n" "};\n" "int main(void) {\n" " C ca;\n" " return 0;\n" "}"; const char expected[] = "struct E ; " "struct C> ; " "struct C ; " "struct D> ; " "int f2> ( ) ; " "int f1> ( int x , B * ) ; " "struct B ; " "struct A { } ; " "struct C> { " "static int f ( ) { " "return f1> ( 0 , reinterpret_cast < B * > ( E :: Int ( -1 ) ) ) ; " "} " "} ; " "int main ( ) { " "C ca ; " "return 0 ; " "} " "struct B { " "void f3 ( B & other ) { } " "} ; " "int f1> ( int x , B * ) { " "int id ; id = f2> ( ) ; " "return id ; " "} " "int f2> ( ) { " "return D> :: f ( ) ; " "} " "struct D> { " "static int f ( ) { " "return C> :: f ( ) ; " "} " "} ; " "struct C { } ; struct E { " "} ;"; ASSERT_EQUALS(expected, tok(code)); } void template44() { // #5297 const char code[] = "template struct StackContainer {" " void foo(int i) {" " if (0 >= 1 && i<0) {}" " }" "};" "template class ZContainer : public StackContainer {};" "struct FGSTensor {};" "class FoldedZContainer : public ZContainer {};"; const char expected[] = "struct StackContainer ; " "class ZContainer ; " "struct FGSTensor { } ; " "class FoldedZContainer : public ZContainer { } ; " "class ZContainer : public StackContainer { } ; " "struct StackContainer { " "void foo ( int i ) { " "if ( 0 >= 1 && i < 0 ) { } " "} " "} ;"; ASSERT_EQUALS(expected, tok(code)); } void template45() { // #5814 const char code[] = "namespace Constants { const int fourtytwo = 42; } " "template struct TypeMath { " " static const int mult = sizeof(T) * U; " "}; " "template struct FOO { " " enum { value = TypeMath::mult }; " "}; " "FOO foo;"; const char expected[] = "namespace Constants { const int fourtytwo = 42 ; } " "struct TypeMath ; " "struct FOO ; " "FOO foo ; " "struct FOO { " "enum Anonymous0 { value = TypeMath :: mult } ; " "} ; " "struct TypeMath { " "static const int mult = sizeof ( int ) * Constants :: fourtytwo ; " "} ;"; ASSERT_EQUALS(expected, tok(code, true)); ASSERT_EQUALS("", errout.str()); } void template46() { // #5816 tok("template struct A { static const int value = 0; }; " "template struct B { " " enum { value = A::value }; " "};"); ASSERT_EQUALS("", errout.str()); tok("template struct A {}; " "enum { e = sizeof(A) }; " "template struct B {};"); ASSERT_EQUALS("", errout.str()); tok("template struct A { static const int value = 0; }; " "template struct B { typedef int type; }; " "template struct C { " " enum { value = A::type, int>::value }; " "};"); ASSERT_EQUALS("", errout.str()); } void template47() { // #6023 tok("template > class C1 {}; " "class C2 : public C1 {};"); ASSERT_EQUALS("", errout.str()); } void template48() { // #6134 tok("template int f( { } ); " "int foo = f<1>(0);"); ASSERT_EQUALS("", errout.str()); } void template49() { // #6237 const char code[] = "template class Fred { void f(); void g(); };\n" "template void Fred::f() { }\n" "template void Fred::g() { }\n" "template void Fred::f();\n" "template void Fred::g();\n"; const char expected[] = "class Fred ; " "class Fred ; " "class Fred { void f ( ) ; void g ( ) ; } ; " "void Fred :: f ( ) { } " "void Fred :: g ( ) { } " "class Fred { void f ( ) ; void g ( ) ; } ; " "void Fred :: f ( ) { } " "void Fred :: g ( ) { }"; ASSERT_EQUALS(expected, tok(code)); } void template50() { // #4272 const char code[] = "template class Fred { void f(); };\n" "template void Fred::f() { }\n" "template<> void Fred::f() { }\n" "template<> void Fred::f() { }\n"; 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)); } void template52() { // #6437 const char code[] = "template int sum() { " " return value + sum(); " "} " "template int calculate_value() { " " if (x != y) { " " return sum(); " " } else { " " return 0; " " } " "} " "int value = calculate_value<1,1>();"; const char expected[] = "int sum<0> ( ) ; " "int calculate_value<1,1> ( ) ; " "int value ; value = calculate_value<1,1> ( ) ; " "int calculate_value<1,1> ( ) { " "if ( 1 != 1 ) { " "return sum<0> ( ) ; " "} else { " "return 0 ; " "} " "} " "int sum<0> ( ) { " "return 0 + sum<0> ( ) ; " "}"; ASSERT_EQUALS(expected, tok(code)); } void template53() { // #4335 const char code[] = "template struct Factorial { " " enum { value = N * Factorial::value }; " "};" "template <> struct Factorial<0> { " " enum { value = 1 }; " "};" "const int x = Factorial<4>::value;"; const char expected[] = "struct Factorial<0> ; " "struct Factorial<4> ; " "struct Factorial<3> ; " "struct Factorial<2> ; " "struct Factorial<1> ; " "struct Factorial<0> { " "enum Anonymous1 { value = 1 } ; " "} ; " "const int x = Factorial<4> :: value ; " "struct Factorial<4> { " "enum Anonymous0 { value = 4 * Factorial<3> :: value } ; " "} ; " "struct Factorial<3> { " "enum Anonymous0 { value = 3 * Factorial<2> :: value } ; " "} ; " "struct Factorial<2> { " "enum Anonymous0 { value = 2 * Factorial<1> :: value } ; " "} ; " "struct Factorial<1> { " "enum Anonymous0 { value = 1 * Factorial<0> :: value } ; " "} ;"; ASSERT_EQUALS(expected, tok(code, true)); ASSERT_EQUALS("", errout.str()); } void template54() { // #6587 tok("template _Tp* fn(); " "template struct A { " " template ())> " " struct B { }; " "}; " "A a;"); } void template55() { // #6604 // Avoid constconstconst in macro instantiations ASSERT_EQUALS( "template < class T > class AtSmartPtr : public ConstCastHelper < AtSmartPtr < const T > , T > { " "friend struct ConstCastHelper < AtSmartPtr < const T > , T > ; " "AtSmartPtr ( const AtSmartPtr < T > & r ) ; " "} ;", tok("template class AtSmartPtr : public ConstCastHelper, T>\n" "{\n" " friend struct ConstCastHelper, T>;\n" " AtSmartPtr(const AtSmartPtr& r);\n" "};")); // Similar problem can also happen with ... ASSERT_EQUALS( "struct A ; " "struct A ; " "A a ( 0 ) ; " "struct A { " "A ( int * p ) { ( A * ) ( p ) ; } " "} ; " "struct A { " "A ( int * p ) { " "( A * ) ( p ) ; " "} } ;", tok("template struct A\n" "{\n" " A(T* p) {\n" " (A*)(p);\n" " }\n" "};\n" "A a(0);")); } void template56() { // #7117 const char code[] = "template struct Foo { " " std::array mfoo; " "}; " "void foo() { " " Foo myFoo; " "}"; const char expected[] = "struct Foo ; " "void foo ( ) { " "Foo myFoo ; " "} struct Foo { " "std :: array < int , 1 > mfoo ; " "} ;"; ASSERT_EQUALS(expected, tok(code, true)); ASSERT_EQUALS("", errout.str()); } void template57() { // #7891 const char code[] = "template struct Test { Test(T); };\n" "Test test( 0 );"; const char exp[] = "struct Test ; " "Test test ( 0 ) ; " "struct Test { Test ( unsigned long ) ; } ;"; ASSERT_EQUALS(exp, tok(code)); } void template58() { // #6021 const char code[] = "template \n" "void TestArithmetic() {\n" " x(1 * CheckedNumeric());\n" "}\n" "void foo() {\n" " TestArithmetic();\n" "}"; const char exp[] = "void TestArithmetic ( ) ; " "void foo ( ) {" " TestArithmetic ( ) ; " "} " "void TestArithmetic ( ) {" " x ( 1 * CheckedNumeric < int > ( ) ) ; " "}"; ASSERT_EQUALS(exp, tok(code)); } void template59() { // #8051 const char code[] = "template\n" "struct Factorial {\n" " enum FacHelper { value = N * Factorial::value };\n" "};\n" "template <>\n" "struct Factorial<0> {\n" " enum FacHelper { value = 1 };\n" "};\n" "template\n" "int diagonalGroupTest() {\n" " return Factorial::value;\n" "}\n" "int main () {\n" " return diagonalGroupTest<4>();\n" "}"; const char exp[] = "struct Factorial<0> ; " "struct Factorial<4> ; " "struct Factorial<3> ; " "struct Factorial<2> ; " "struct Factorial<1> ; " "struct Factorial<0> { enum FacHelper { value = 1 } ; } ; " "int diagonalGroupTest<4> ( ) ; " "int main ( ) { return diagonalGroupTest<4> ( ) ; } " "int diagonalGroupTest<4> ( ) { return Factorial<4> :: value ; } " "struct Factorial<4> { enum FacHelper { value = 4 * Factorial<3> :: value } ; } ; " "struct Factorial<3> { enum FacHelper { value = 3 * Factorial<2> :: value } ; } ; " "struct Factorial<2> { enum FacHelper { value = 2 * Factorial<1> :: value } ; } ; " "struct Factorial<1> { enum FacHelper { value = 1 * Factorial<0> :: value } ; } ;"; ASSERT_EQUALS(exp, tok(code)); } void template60() { // Extracted from Clang testfile const char code[] = "template struct S { typedef int type; };\n" "template void f() {}\n" "template void h() { f::type(0)>(); }\n" "\n" "void j() { h(); }"; const char exp[] = "struct S ; " "void f::type(0)> ( ) ; " "void h ( ) ; " "void j ( ) { h ( ) ; } " "void h ( ) { f::type(0)> ( ) ; } " "struct S { } ; " "void f::type(0)> ( ) { }"; const char act[] = "template < typename T > struct S { } ; " "void f::type(0)> ( ) ; " "void h ( ) ; " "void j ( ) { h ( ) ; } " "void h ( ) { f::type(0)> ( ) ; } " "void f::type(0)> ( ) { }"; TODO_ASSERT_EQUALS(exp, act, tok(code)); } void template61() { // hang in daca, code extracted from kodi const char code[] = "template struct Foo {};\n" "template struct Bar {\n" " void f1(Bar x) {}\n" " Foo> f2() { }\n" "};\n" "Bar c;"; const char exp[] = "struct Foo> ; " "struct Bar ; " "Bar c ; " "struct Bar {" " void f1 ( Bar x ) { }" " Foo> f2 ( ) { } " "} ; " "struct Foo> { } ;"; ASSERT_EQUALS(exp, tok(code)); } void template62() { // #8314 const char code[] = "template struct C1 {};\n" "template void f() { x = y ? C1::allocate(1) : 0; }\n" "template class C3 {};\n" "template C3::C3(const C3 &v) { C1 c1; }\n" "C3 c3;"; const char exp[] = "struct C1 ; " "template < class T > void f ( ) { x = y ? ( C1 < int > :: allocate ( 1 ) ) : 0 ; } " "class C3 ; " "C3 c3 ; " "class C3 { } ; " "C3 :: C3 ( const C3 & v ) { C1 c1 ; } " "struct C1 { } ;"; ASSERT_EQUALS(exp, tok(code)); } void template63() { // #8576 const char code[] = "template struct TestClass { T m_hi; };" "TestClass> objTest3;"; const char exp[] = "struct TestClass> ; " "TestClass> objTest3 ; " "struct TestClass> { std :: auto_ptr < v > m_hi ; } ;"; ASSERT_EQUALS(exp, tok(code)); } void template64() { // #8683 const char code[] = "template \n" "bool foo(){return true;}\n" "struct A {\n" "template\n" "void t_func()\n" "{\n" " if( n != 0 || foo());\n" "}\n" "void t_caller()\n" "{\n" " t_func<0>();\n" " t_func<1>();\n" "}\n" "};"; const char exp[] = "bool foo ( ) ; " "struct A { " "void t_func<0> ( ) ; " "void t_func<1> ( ) ; " "void t_caller ( ) " "{ " "t_func<0> ( ) ; " "t_func<1> ( ) ; " "} " "} ; " "void A :: t_func<0> ( ) " "{ " "if ( 0 != 0 || foo ( ) ) { ; } " "} " "void A :: t_func<1> ( ) " "{ " "if ( 1 != 0 || foo ( ) ) { ; } " "} " "bool foo ( ) { return true ; }"; ASSERT_EQUALS(exp, tok(code)); } void template65() { // #8321 (crash) const char code[] = "namespace bpp\n" "{\n" "template\n" "class AssociationDAGraphImplObserver :\n" " public AssociationGraphImplObserver\n" "{};\n" "template\n" "using AssociationDAGlobalGraphObserver = AssociationDAGraphImplObserver;\n" "}\n" "using namespace bpp;\n" "using namespace std;\n" "int main() {\n" " AssociationDAGlobalGraphObserver grObs;\n" " return 1;\n" "}"; const char exp[] = "namespace bpp " "{ " "class AssociationDAGraphImplObserver ; " "} " "using namespace bpp ; " "int main ( ) { " "bpp :: AssociationDAGraphImplObserver grObs ; " "return 1 ; " "} class bpp :: AssociationDAGraphImplObserver : " "public AssociationGraphImplObserver < std :: string , unsigned int , DAGlobalGraph > " "{ } ;"; ASSERT_EQUALS(exp, tok(code)); } void template66() { // #8725 const char code[] = "template struct Fred {\n" " const int ** foo();\n" "};\n" "template const int ** Fred::foo() { return nullptr; }\n" "Fred fred;"; const char exp[] = "struct Fred ; " "Fred fred ; " "struct Fred { " "const int * * foo ( ) ; " "} ; " "const int * * Fred :: foo ( ) { return nullptr ; }"; ASSERT_EQUALS(exp, tok(code)); } void template67() { // ticket #8122 const char code[] = "template struct Container {\n" " Container();\n" " Container(const Container &);\n" " Container & operator = (const Container &);\n" " ~Container();\n" " T* mElements;\n" " const Container * c;\n" "};\n" "template Container::Container() : mElements(nullptr), c(nullptr) {}\n" "template Container::Container(const Container & x) { nElements = x.nElements; c = x.c; }\n" "template Container & Container::operator = (const Container & x) { mElements = x.mElements; c = x.c; return *this; }\n" "template Container::~Container() {}\n" "Container intContainer;"; const char expected[] = "struct Container ; " "Container intContainer ; " "struct Container { " "Container ( ) ; " "Container ( const Container & ) ; " "Container & operator= ( const Container & ) ; " "~ Container ( ) ; " "int * mElements ; " "const Container * c ; " "} ; " "Container :: Container ( ) : mElements ( nullptr ) , c ( nullptr ) { } " "Container :: Container ( const Container & x ) { nElements = x . nElements ; c = x . c ; } " "Container & Container :: operator= ( const Container & x ) { mElements = x . mElements ; c = x . c ; return * this ; } " "Container :: ~ Container ( ) { }"; ASSERT_EQUALS(expected, tok(code)); } void template68() { const char code[] = "template union Fred {\n" " char dummy[sizeof(T)];\n" " T value;\n" "};\n" "Fred fred;"; const char exp[] = "union Fred ; " "Fred fred ; " "union Fred { " "char dummy [ sizeof ( int ) ] ; " "int value ; " "} ;"; ASSERT_EQUALS(exp, tok(code)); } void template69() { // #8791 const char code[] = "class Test {\n" " int test;\n" " template T lookup() { return test; }\n" " int Fun() { return lookup(); }\n" "};"; const char exp[] = "class Test { " "int test ; " "int lookup ( ) ; " "int Fun ( ) { return lookup ( ) ; } " "} ; " "int Test :: lookup ( ) { return test ; }"; ASSERT_EQUALS(exp, tok(code)); } void template70() { // #5289 const char code[] = "template class Bar;\n" "template<>\n" "class Bar {\n" "};\n" "template\n" "class Bar : private Bar {\n" " void foo() { }\n" "};"; const char exp[] = "template < typename T , typename V , int KeySize = 0 > class Bar ; " "class Bar ; " "class Bar { " "} ; " "template < typename K , typename V , int KeySize = 0 > " "class Bar : private Bar { " "void foo ( ) { } " "} ;"; const char act[] = "template < typename T , typename V , int KeySize = 0 > class Bar ; " "class Bar { " "} ; " "class Bar ; " "template < typename K , typename V , int KeySize = 0 > " "class Bar : private Bar { " "void foo ( ) { } " "} ;"; TODO_ASSERT_EQUALS(exp, act, tok(code)); } void template71() { // #8821 const char code[] = "int f1(int * pInterface, int x) { return 0; }\n" "\n" "template< class interface_type > class Reference {\n" " template< class interface_type > int i();\n" " int *pInterface;\n" "};\n" "\n" "template< class interface_type > int Reference< interface_type >::i() {\n" " return f1(pInterface, interface_type::static_type());\n" "}\n" "\n" "Reference< class XPropertyList > dostuff();"; const char exp[] = "int f1 ( int * pInterface , int x ) { return 0 ; } " "class Reference ; " "Reference dostuff ( ) ; " "class Reference { template < class XPropertyList > int i ( ) ; int * pInterface ; } ; " "int Reference :: i ( ) { return f1 ( pInterface , XPropertyList :: static_type ( ) ) ; }"; ASSERT_EQUALS(exp, tok(code)); } void template72() { const char code[] = "template class Tokenizer;\n" "const Tokenizer *tokenizer() const;\n" "template \n" "Tokenizer::Tokenizer() { }"; const char exp[] = "template < typename N , typename P > class Tokenizer ; " "const Tokenizer < Node , Path > * tokenizer ( ) const ; " "template < typename N , typename P > " "Tokenizer < N , P > :: Tokenizer ( ) { }"; ASSERT_EQUALS(exp, tok(code)); } void template73() { const char code[] = "template\n" "void keep_range(T& value, const T mini, const T maxi){}\n" "template void keep_range(float& v, const float l, const float u);\n" "template void keep_range(int& v, const int l, const int u);"; const char exp[] = "void keep_range ( float & value , const float mini , const float maxi ) ; " "void keep_range ( int & value , const int mini , const int maxi ) ; " "void keep_range ( float & value , const float mini , const float maxi ) { } " "void keep_range ( int & value , const int mini , const int maxi ) { }"; ASSERT_EQUALS(exp, tok(code)); } void template74() { const char code[] = "template class BTlist { };\n" "class PushBackStreamBuf {\n" "public:\n" " void pushBack(const BTlist &vec);\n" "};"; const char exp[] = "class BTlist ; " "class PushBackStreamBuf { " "public: " "void pushBack ( const BTlist & vec ) ; " "} ; " "class BTlist { } ;"; ASSERT_EQUALS(exp, tok(code)); } void template75() { const char code[] = "template\n" "T foo(T& value){ return value; }\n" "template std::vector> foo>>(std::vector>& v);"; const char exp[] = "std :: vector < std :: vector < int > > foo>> ( std :: vector < std :: vector < int > > & value ) ; " "std :: vector < std :: vector < int > > foo>> ( std :: vector < std :: vector < int > > & value ) { return value ; }"; ASSERT_EQUALS(exp, tok(code)); } void template76() { const char code[] = "namespace NS {\n" " template T foo(T& value) { return value; }\n" " template std::vector> foo>>(std::vector>& v);\n" "}\n" "std::vector> v;\n" "v = foo>>(v);\n"; const char exp[] = "namespace NS { " "std :: vector < std :: vector < int > > foo>> ( std :: vector < std :: vector < int > > & value ) ; " "} " "std :: vector < std :: vector < int > > v ; " "v = foo>> ( v ) ; " "std :: vector < std :: vector < int > > NS :: foo>> ( std :: vector < std :: vector < int > > & value ) { return value ; }"; ASSERT_EQUALS(exp, tok(code)); } void template77() { const char code[] = "template\n" "struct is_void : std::false_type { };\n" "template<>\n" "struct is_void : std::true_type { };\n" "int main() {\n" " std::cout << is_void::value << std::endl;\n" " std::cout << is_void::value << std::endl;\n" "}"; const char exp[] = "struct is_void ; " "struct is_void ; " "struct is_void : std :: true_type { } ; " "int main ( ) { " "std :: cout << is_void :: value << std :: endl ; " "std :: cout << is_void :: value << std :: endl ; " "} " "struct is_void : std :: false_type { } ;"; ASSERT_EQUALS(exp, tok(code)); } void template78() { const char code[] = "template \n" "struct Base { };\n" "struct S : Base ::Type { };"; const char exp[] = "struct Base ; " "struct S : Base :: Type { } ; " "struct Base { } ;"; ASSERT_EQUALS(exp, tok(code)); } void template79() { // #5133 const char code[] = "class Foo {\n" "public:\n" " template void foo() { bar(); }\n" "private:\n" " template void bar() { bazz(); }\n" " void bazz() { }\n" "};\n" "void some_func() {\n" " Foo x;\n" " x.foo();\n" "}"; const char exp[] = "class Foo { " "public: " "void foo ( ) ; " "private: " "void bar ( ) ; " "void bazz ( ) { } " "} ; " "void some_func ( ) { " "Foo x ; " "x . foo ( ) ; " "} " "void Foo :: foo ( ) { bar ( ) ; } " "void Foo :: bar ( ) { bazz ( ) ; }"; ASSERT_EQUALS(exp, tok(code)); } void template80() { const char code[] = "class Fred {\n" " template T foo(T t) const { return t; }\n" "};\n" "const void * p = Fred::foo(nullptr);"; const char exp[] = "class Fred { " "const void * foo ( const void * t ) const ; " "} ; " "const void * p ; p = Fred :: foo ( nullptr ) ; " "const void * Fred :: foo ( const void * t ) const { return t ; }"; ASSERT_EQUALS(exp, tok(code)); } void template81() { const char code[] = "template \n" "struct SortWith {\n" " SortWith(Type);\n" "};\n" "template \n" "SortWith::SortWith(Type) {}\n" "int main() {\n" " SortWith(0);\n" "}"; const char exp[] = "template < typename Type > " "struct SortWith { " "SortWith ( Type ) ; " "} ; " "SortWith :: SortWith ( int ) ; " "int main ( ) { " "SortWith ( 0 ) ; " "} " "SortWith :: SortWith ( int ) { }"; ASSERT_EQUALS(exp, tok(code)); } void template82() { // 8603 const char code[] = "typedef int comp;\n" "const int f16=16;\n" "template\n" "class tvec2 {};\n" "template\n" "class tvec3 {};\n" "namespace swizzle {\n" "template void swizzle(tvec2 v) { }\n" "template void swizzle(tvec3 v) { }\n" "}\n" "void foo() {\n" " using namespace swizzle;\n" " tvec2 tt2;\n" " swizzle<1>(tt2);\n" " tvec3 tt3;\n" " swizzle<2,3>(tt3);\n" "}"; const char exp[] = "const int f16 = 16 ; " "class tvec2 ; " "class tvec3 ; " "namespace swizzle { " "void swizzle<1> ( tvec2 v ) ; " "void swizzle<2,3> ( tvec3 v ) ; " "} " "void foo ( ) { " "using namespace swizzle ; " "tvec2 tt2 ; " "swizzle :: swizzle<1> ( tt2 ) ; " "tvec3 tt3 ; " "swizzle :: swizzle<2,3> ( tt3 ) ; " "} " "void swizzle :: swizzle<2,3> ( tvec3 v ) { } " "void swizzle :: swizzle<1> ( tvec2 v ) { } " "class tvec3 { } ; " "class tvec2 { } ;"; ASSERT_EQUALS(exp, tok(code)); } void template83() { // #8867 const char code[] = "template\n" "class MultiConsumer {\n" " MultiConsumer();\n" "};\n" "template\n" "MultiConsumer::MultiConsumer() : sizeBuffer(0) {}\n" "MultiReads::MultiReads() {\n" " mc = new MultiConsumer();\n" "}"; const char exp[] = "template < typename Task > " // TODO: this should be expanded "class MultiConsumer { " "MultiConsumer ( ) ; " "} ; " "MultiConsumer :: MultiConsumer ( ) ; " "MultiReads :: MultiReads ( ) { " "mc = new MultiConsumer ( ) ; " "} " "MultiConsumer :: MultiConsumer ( ) : sizeBuffer ( 0 ) { }"; ASSERT_EQUALS(exp, tok(code)); } void template84() { // #8880 { const char code[] = "template \n" "auto d() -> typename a::e {\n" " d();\n" "}"; const char exp[] = "template < class b , int c , class > " "auto d ( ) . a < decltype ( b { } ) > :: e { " "d < int , c , int > ( ) ; " "}"; ASSERT_EQUALS(exp, tok(code)); } { const char code[] = "template \n" "auto d() -> typename a::e {\n" " d();\n" "}" "void foo() { d(); }"; const char exp[] = "auto d ( ) . a < char > :: e ; " "auto d ( ) . a < int > :: e ; " "void foo ( ) { d ( ) ; } " "auto d ( ) . a < char > :: e { " "d ( ) ; " "} " "auto d ( ) . a < int > :: e { " "d ( ) ; " "}"; ASSERT_EQUALS(exp, tok(code)); } } void template85() { // #8902 - crash const char code[] = "template\n" "struct C\n" "{\n" " template::value)>::type* = nullptr>\n" " void foo();\n" "};\n" "extern template void C::foo();\n" "template\n" "template::value)>::type>\n" "void C::foo() {}"; // @todo the output is very wrong but we are only worried about the crash for now tok(code); } void template86() { // crash const char code[] = "struct S {\n" " S();\n" "};\n" "template \n" "struct U {\n" " static S u;\n" "};\n" "template \n" "S U::u;\n" "template S U::u;\n" "S &i = U::u;"; tok(code); } void template87() { const char code[] = "template\n" "T f1(T t) { return t; }\n" "template const char * f1(const char *);\n" "template const char & f1(const char &);"; const char exp[] = "const char * f1 ( const char * t ) ; " "const char & f1 ( const char & t ) ; " "const char * f1 ( const char * t ) { return t ; } " "const char & f1 ( const char & t ) { return t ; }"; ASSERT_EQUALS(exp, tok(code)); } void template88() { // #6183.cpp const char code[] = "class CTest {\n" "public:\n" " template \n" " static void Greeting(T val) {\n" " std::cout << val << std::endl;\n" " }\n" "private:\n" " static void SayHello() {\n" " std::cout << \"Hello World!\" << std::endl;\n" " }\n" "};\n" "template<>\n" "void CTest::Greeting(bool) {\n" " CTest::SayHello();\n" "}\n" "int main() {\n" " CTest::Greeting(true);\n" " return 0;\n" "}"; const char exp[] = "class CTest { " "public: " "static void Greeting ( bool ) ; " "template < typename T > " "static void Greeting ( T val ) { " "std :: cout << val << std :: endl ; " "} " "private: " "static void SayHello ( ) { " "std :: cout << \"Hello World!\" << std :: endl ; " "} " "} ; " "void CTest :: Greeting ( bool ) { " "CTest :: SayHello ( ) ; " "} " "int main ( ) { " "CTest :: Greeting ( true ) ; " "return 0 ; " "}"; ASSERT_EQUALS(exp, tok(code)); } void template89() { // #8917 const char code[] = "struct Fred {\n" " template static void foo() { }\n" "};\n" "template void Fred::foo();\n" "template void Fred::foo();\n" "template <> void Fred::foo() { }\n" "template <> void Fred::foo() { }"; const char exp[] = "struct Fred { " "static void foo ( ) ; " "static void foo ( ) ; " "static void foo ( ) ; " "static void foo ( ) ; " "} ; " "void Fred :: foo ( ) { } " "void Fred :: foo ( ) { } " "void Fred :: foo ( ) { } " "void Fred :: foo ( ) { }"; ASSERT_EQUALS(exp, tok(code)); } void template90() { // crash const char code[] = "template struct S1 {};\n" "void f(S1) {}\n" "template \n" "decltype(S1().~S1()) fun1() {};"; const char exp[] = "struct S1 ; " "void f ( S1 ) { } " "template < typename T > " "decltype ( S1 < T > ( ) . ~ S1 < T > ( ) ) fun1 ( ) { } ; " "struct S1 { } ;"; ASSERT_EQUALS(exp, tok(code)); } void template91() { { const char code[] = "template T foo(T t) { return t; }\n" "template<> char foo(char a) { return a; }\n" "template<> int foo(int a) { return a; }\n" "template float foo(float);\n" "template double foo(double);"; const char exp[] = "int foo ( int a ) ; " "char foo ( char a ) ; " "float foo ( float t ) ; " "double foo ( double t ) ; " "char foo ( char a ) { return a ; } " "int foo ( int a ) { return a ; } " "float foo ( float t ) { return t ; } " "double foo ( double t ) { return t ; }"; ASSERT_EQUALS(exp, tok(code)); } { const char code[] = "struct Fred {\n" " template T foo(T t) { return t; }\n" " template<> char foo(char a) { return a; }\n" " template<> int foo(int a) { return a; }\n" "};\n" "template float Fred::foo(float);\n" "template double Fred::foo(double);"; const char exp[] = "struct Fred { " "int foo ( int a ) ; " "char foo ( char a ) ; " "float foo ( float t ) ; " "double foo ( double t ) ; " "char foo ( char a ) { return a ; } " "int foo ( int a ) { return a ; } " "} ; " "float Fred :: foo ( float t ) { return t ; } " "double Fred :: foo ( double t ) { return t ; }"; ASSERT_EQUALS(exp, tok(code)); } { const char code[] = "namespace NS1 {\n" " namespace NS2 {\n" " template T foo(T t) { return t; }\n" " template<> char foo(char a) { return a; }\n" " template<> int foo(int a) { return a; }\n" " template short NS2::foo(short);\n" " template long NS1::NS2::foo(long);\n" " }\n" " template float NS2::foo(float);\n" " template bool NS1::NS2::foo(bool);\n" "}\n" "template double NS1::NS2::foo(double);"; const char exp[] = "namespace NS1 { " "namespace NS2 { " "int foo ( int a ) ; " "char foo ( char a ) ; " "short foo ( short t ) ; " "long foo ( long t ) ; " "float foo ( float t ) ; " "bool foo ( bool t ) ; " "double foo ( double t ) ; " "char foo ( char a ) { return a ; } " "int foo ( int a ) { return a ; } " "} " "} " "short NS1 :: NS2 :: foo ( short t ) { return t ; } " "long NS1 :: NS2 :: foo ( long t ) { return t ; } " "float NS1 :: NS2 :: foo ( float t ) { return t ; } " "bool NS1 :: NS2 :: foo ( bool t ) { return t ; } " "double NS1 :: NS2 :: foo ( double t ) { return t ; }"; ASSERT_EQUALS(exp, tok(code)); } { const char code[] = "namespace NS1 {\n" " namespace NS {\n" " template T foo(T t) { return t; }\n" " template<> char foo(char a) { return a; }\n" " template<> int foo(int a) { return a; }\n" " template short NS::foo(short);\n" " template long NS1::NS::foo(long);\n" " }\n" " template float NS::foo(float);\n" " template bool NS1::NS::foo(bool);\n" "}\n" "template double NS1::NS::foo(double);"; const char exp[] = "namespace NS1 { " "namespace NS { " "int foo ( int a ) ; " "char foo ( char a ) ; " "short foo ( short t ) ; " "long foo ( long t ) ; " "float foo ( float t ) ; " "bool foo ( bool t ) ; " "double foo ( double t ) ; " "char foo ( char a ) { return a ; } " "int foo ( int a ) { return a ; } " "} " "} " "short NS1 :: NS :: foo ( short t ) { return t ; } " "long NS1 :: NS :: foo ( long t ) { return t ; } " "float NS1 :: NS :: foo ( float t ) { return t ; } " "bool NS1 :: NS :: foo ( bool t ) { return t ; } " "double NS1 :: NS :: foo ( double t ) { return t ; }"; ASSERT_EQUALS(exp, tok(code)); } } void template92() { const char code[] = "template void foo(T const& t) { }\n" "template<> void foo(double const& d) { }\n" "template void foo(float const& f);\n" "int main() {\n" " foo(2);\n" " foo(3.14);\n" " foo(3.14f);\n" "}"; const char exp[] = "void foo ( const double & d ) ; " "void foo ( const float & t ) ; " "void foo ( const int & t ) ; " "void foo ( const double & d ) { } " "int main ( ) { " "foo ( 2 ) ; " "foo ( 3.14 ) ; " "foo ( 3.14f ) ; " "} " "void foo ( const float & t ) { } " "void foo ( const int & t ) { }"; ASSERT_EQUALS(exp, tok(code)); } void template93() { // crash const char code[] = "template \n" "void ForEach() { }\n" "template \n" "class Vector2 : public Vector {\n" " template \n" " void ForEach();\n" "public:\n" " void process();\n" "};\n" "template \n" "void Vector2::process() {\n" " ForEach();\n" "}\n" "Vector2 c;"; const char exp[] = "void ForEach ( ) ; " "class Vector2 ; " "Vector2 c ; " "class Vector2 : public Vector { " "template < typename Iterator > " "void ForEach ( ) ; " "public: " "void process ( ) ; " "} ; " "void Vector2 :: process ( ) { " "ForEach ( ) ; " "} " "void ForEach ( ) { " "}"; 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 template95() { // #7417 const char code[] = "template \n" "T Value = 123;\n" "template<>\n" "int Value = 456;\n" "float f = Value;\n" "int i = Value;"; const char exp[] = "float Value ; Value = 123 ; " "int Value ; Value = 456 ; " "float f ; f = Value ; " "int i ; i = Value ;"; ASSERT_EQUALS(exp, tok(code)); } void template96() { // #7854 { const char code[] = "template\n" " constexpr long fib = fib + fib;\n" "template<>\n" " constexpr long fib<0> = 0;\n" "template<>\n" " constexpr long fib<1> = 1;\n" "long f0 = fib<0>;\n" "long f1 = fib<1>;\n" "long f2 = fib<2>;\n" "long f3 = fib<3>;"; const char exp[] = "constexpr long fib<2> = fib<1> + fib<0> ; " "constexpr long fib<3> = fib<2> + fib<1> ; " "constexpr long fib<0> = 0 ; " "constexpr long fib<1> = 1 ; " "long f0 ; f0 = fib<0> ; " "long f1 ; f1 = fib<1> ; " "long f2 ; f2 = fib<2> ; " "long f3 ; f3 = fib<3> ;"; ASSERT_EQUALS(exp, tok(code)); } { const char code[] = "template\n" " constexpr long fib = fib + fib;\n" "template<>\n" " constexpr long fib<0> = 0;\n" "template<>\n" " constexpr long fib<1> = 1;\n" "long f5 = fib<5>;\n"; const char exp[] = "constexpr long fib<5> = fib<4> + fib<3> ; " "constexpr long fib<4> = fib<3> + fib<2> ; " "constexpr long fib<3> = fib<2> + fib<1> ; " "constexpr long fib<2> = fib<1> + fib<0> ; " "constexpr long fib<0> = 0 ; " "constexpr long fib<1> = 1 ; " "long f5 ; f5 = fib<5> ;"; ASSERT_EQUALS(exp, tok(code)); } } void template97() { const char code[] ="namespace NS1 {\n" " namespace NS2 {\n" " namespace NS3 {\n" " namespace NS4 {\n" " template\n" " class Fred {\n" " T * t;\n" " public:\n" " Fred() : t(nullptr) {}\n" " };\n" " }\n" " using namespace NS4;\n" " Fred fred_bool;\n" " NS4::Fred fred_char;\n" " }\n" " using namespace NS3;\n" " NS4::Fred fred_short;\n" " using namespace NS3::NS4;\n" " Fred fred_int;\n" " NS3::NS4::Fred fred_long;\n" " NS2::NS3::NS4::Fred fred_float;\n" " NS1::NS2::NS3::NS4::Fred fred_double;\n" " }\n" " using namespace NS2;\n" " NS3::NS4::Fred fred_float1;\n" " NS2::NS3::NS4::Fred fred_double1;\n" "}\n" "using namespace NS1::NS2::NS3::NS4;\n" "Fred fred_bool1;\n" "NS1::NS2::NS3::NS4::Fred fred_int1;"; const char exp[] = "namespace NS1 { " "namespace NS2 { " "namespace NS3 { " "namespace NS4 { " "class Fred ; " "class Fred ; " "class Fred ; " "class Fred ; " "class Fred ; " "class Fred ; " "class Fred ; " "} " "using namespace NS4 ; " "NS4 :: Fred fred_bool ; " "NS4 :: Fred fred_char ; " "} " "using namespace NS3 ; " "NS3 :: NS4 :: Fred fred_short ; " "using namespace NS3 :: NS4 ; " "NS3 :: NS4 :: Fred fred_int ; " "NS3 :: NS4 :: Fred fred_long ; " "NS2 :: NS3 :: NS4 :: Fred fred_float ; " "NS1 :: NS2 :: NS3 :: NS4 :: Fred fred_double ; " "} " "using namespace NS2 ; " "NS2 :: NS3 :: NS4 :: Fred fred_float1 ; " "NS2 :: NS3 :: NS4 :: Fred fred_double1 ; " "} " "using namespace NS1 :: NS2 :: NS3 :: NS4 ; " "NS1 :: NS2 :: NS3 :: NS4 :: Fred fred_bool1 ; " "NS1 :: NS2 :: NS3 :: NS4 :: Fred fred_int1 ; " "class NS1 :: NS2 :: NS3 :: NS4 :: Fred { " "bool * t ; " "public: " "Fred ( ) : t ( nullptr ) { } " "} ; " "class NS1 :: NS2 :: NS3 :: NS4 :: Fred { " "char * t ; " "public: " "Fred ( ) : t ( nullptr ) { } " "} ; " "class NS1 :: NS2 :: NS3 :: NS4 :: Fred { " "short * t ; " "public: " "Fred ( ) : t ( nullptr ) { } " "} ; " "class NS1 :: NS2 :: NS3 :: NS4 :: Fred { " "int * t ; " "public: " "Fred ( ) : t ( nullptr ) { } " "} ; " "class NS1 :: NS2 :: NS3 :: NS4 :: Fred { " "long * t ; " "public: " "Fred ( ) : t ( nullptr ) { } " "} ; " "class NS1 :: NS2 :: NS3 :: NS4 :: Fred { " "float * t ; " "public: " "Fred ( ) : t ( nullptr ) { } " "} ; " "class NS1 :: NS2 :: NS3 :: NS4 :: Fred { " "double * t ; " "public: " "Fred ( ) : t ( nullptr ) { } " "} ;"; ASSERT_EQUALS(exp, tok(code)); } void template98() { // #8959 const char code[] = "template \n" "using unique_ptr_with_deleter = std::unique_ptr>;\n" "class A {};\n" "static void func() {\n" " unique_ptr_with_deleter tmp(new A(), [](A* a) {\n" " delete a;\n" " });\n" "}"; const char exp[] = "class A { } ; " "static void func ( ) { " "std :: unique_ptr < A , std :: function < void ( A * ) > > tmp ( new A ( ) , [ ] ( A * a ) { " "delete a ; " "} ) ; " "}"; ASSERT_EQUALS(exp, tok(code)); } void template99() { // #8960 const char code[] = "template \n" "class Base {\n" "public:\n" " using ArrayType = std::vector>;\n" "};\n" "using A = Base;\n" "static A::ArrayType array;\n"; const char exp[] = "class Base ; " "static std :: vector < Base > array ; " "class Base { " "public: " "} ;"; ASSERT_EQUALS(exp, tok(code)); } void template100() { // #8967 const char code[] = "enum class Device { I2C0, I2C1 };\n" "template \n" "const char* deviceFile;\n" "template <>\n" "const char* deviceFile = \"/tmp/i2c-0\";\n"; const char exp[] = "enum class Device { I2C0 , I2C1 } ; " "template < Device D > " "const char * deviceFile ; " "const char * deviceFile ; deviceFile = \"/tmp/i2c-0\" ;"; ASSERT_EQUALS(exp, tok(code)); } void template101() { // #8968 const char code[] = "class A {\n" "public:\n" " using ArrayType = std::vector;\n" " void func(typename ArrayType::size_type i) {\n" " }\n" "};"; const char exp[] = "class A { " "public: " "void func ( std :: vector < int > :: size_type i ) { " "} " "} ;"; ASSERT_EQUALS(exp, tok(code)); ASSERT_EQUALS("", errout.str()); } void template102() { // #9005 const char code[] = "namespace ns {\n" "template \n" "struct is_floating_point\n" ": std::integral_constant::value || true>\n" "{};\n" "}\n" "void f() {\n" " if(std::is_floating_point::value) {}\n" "}"; const char exp[] = "namespace ns { " "template < class T > " "struct is_floating_point " ": std :: integral_constant < bool , std :: is_floating_point < T > :: value || true > " "{ } ; " "} " "void f ( ) { " "if ( std :: is_floating_point < float > :: value ) { } " "}"; ASSERT_EQUALS(exp, tok(code)); } void template103() { const char code[] = "namespace sample {\n" " template \n" " class Sample {\n" " public:\n" " T function(T t);\n" " };\n" " template \n" " T Sample::function(T t) {\n" " return t;\n" " }\n" "}\n" "sample::Sample s1;"; const char exp[] = "namespace sample { " "class Sample ; " "} " "sample :: Sample s1 ; " "class sample :: Sample { " "public: " "int function ( int t ) ; " "} ; " "int sample :: Sample :: function ( int t ) { " "return t ; " "}"; ASSERT_EQUALS(exp, tok(code)); } void template104() { // #9021 const char code[] = "template < int i >\n" "auto key ( ) { return hana :: test :: ct_eq < i > { } ; }\n" "template < int i >\n" "auto val ( ) { return hana :: test :: ct_eq < - i > { } ; }\n" "template < int i , int j >\n" "auto p ( ) { return :: minimal_product ( key < i > ( ) , val < j > ( ) ) ; }\n" "int main ( ) {\n" " BOOST_HANA_CONSTANT_CHECK ( hana :: equal (\n" " hana :: at_key ( hana :: make_map ( p < 0 , 0 > ( ) ) , key < 0 > ( ) ) ,\n" " val < 0 > ( ) ) ) ;\n" "}"; const char exp[] = "auto key<0> ( ) ; " "auto val<0> ( ) ; " "auto p<0,0> ( ) ; " "int main ( ) { " "BOOST_HANA_CONSTANT_CHECK ( hana :: equal ( " "hana :: at_key ( hana :: make_map ( p<0,0> ( ) ) , key<0> ( ) ) , " "val<0> ( ) ) ) ; " "} " "auto p<0,0> ( ) { return :: minimal_product ( key<0> ( ) , val<0> ( ) ) ; } " "auto val<0> ( ) { return hana :: test :: ct_eq < - 0 > { } ; } " "auto key<0> ( ) { return hana :: test :: ct_eq < 0 > { } ; }"; ASSERT_EQUALS(exp, tok(code)); } void template105() { // #9076 const char code[] = "template