4283 lines
204 KiB
C++
4283 lines
204 KiB
C++
/*
|
|
* Cppcheck - A tool for static C/C++ code analysis
|
|
* Copyright (C) 2007-2019 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#include "config.h"
|
|
#include "platform.h"
|
|
#include "settings.h"
|
|
#include "templatesimplifier.h"
|
|
#include "testsuite.h"
|
|
#include "token.h"
|
|
#include "tokenize.h"
|
|
|
|
struct InternalError;
|
|
|
|
|
|
class TestSimplifyTemplate : public TestFixture {
|
|
public:
|
|
TestSimplifyTemplate() : TestFixture("TestSimplifyTemplate") {
|
|
}
|
|
|
|
private:
|
|
Settings settings;
|
|
|
|
void run() OVERRIDE {
|
|
settings.addEnabled("portability");
|
|
|
|
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<class B> 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(template51); // #6172 - crash upon valid code
|
|
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(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_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 TemplateSimplifier::templateParameters
|
|
TEST_CASE(templateParameters);
|
|
|
|
TEST_CASE(templateNamePosition);
|
|
|
|
TEST_CASE(findTemplateDeclarationEnd);
|
|
|
|
TEST_CASE(expandSpecialized1);
|
|
TEST_CASE(expandSpecialized2);
|
|
TEST_CASE(expandSpecialized3); // #8671
|
|
TEST_CASE(expandSpecialized4);
|
|
|
|
TEST_CASE(templateAlias1);
|
|
TEST_CASE(templateAlias2);
|
|
TEST_CASE(templateAlias3); // #8315
|
|
TEST_CASE(templateAlias4); // #9070
|
|
TEST_CASE(templateAlias5);
|
|
|
|
// Test TemplateSimplifier::instantiateMatch
|
|
TEST_CASE(instantiateMatch);
|
|
TEST_CASE(templateParameterWithoutName); // #8602 Template default parameter without name yields syntax error
|
|
|
|
TEST_CASE(templateTypeDeduction1); // #8962
|
|
TEST_CASE(templateTypeDeduction2);
|
|
|
|
TEST_CASE(simplifyTemplateArgs);
|
|
|
|
TEST_CASE(template_variadic_1); // #9144
|
|
|
|
TEST_CASE(template_variable_1);
|
|
TEST_CASE(template_variable_2);
|
|
TEST_CASE(template_variable_3);
|
|
TEST_CASE(template_variable_4);
|
|
}
|
|
|
|
std::string tok(const char code[], bool debugwarnings = false, Settings::PlatformType type = Settings::Native) {
|
|
errout.str("");
|
|
|
|
settings.debugwarnings = debugwarnings;
|
|
settings.platform(type);
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
tokenizer.tokenize(istr, "test.cpp");
|
|
|
|
return tokenizer.tokens()->stringifyList(nullptr, true);
|
|
}
|
|
|
|
void template1() {
|
|
const char code[] = "template <class T> T f(T val) { T a; }\n"
|
|
"f<int>(10);";
|
|
|
|
const char expected[] = "int f<int> ( int val ) ; "
|
|
"f<int> ( 10 ) ; "
|
|
"int f<int> ( int val ) { int a ; }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template2() {
|
|
const char code[] = "template <class T> class Fred { T a; };\n"
|
|
"Fred<int> fred;";
|
|
|
|
const char expected[] = "class Fred<int> ; "
|
|
"Fred<int> fred ; "
|
|
"class Fred<int> { int a ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template3() {
|
|
const char code[] = "template <class T, int sz> class Fred { T data[sz]; };\n"
|
|
"Fred<float,4> fred;";
|
|
|
|
const char expected[] = "class Fred<float,4> ; "
|
|
"Fred<float,4> fred ; "
|
|
"class Fred<float,4> { float data [ 4 ] ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template4() {
|
|
const char code[] = "template <class T> class Fred { Fred(); };\n"
|
|
"Fred<float> fred;";
|
|
|
|
const char expected[] = "class Fred<float> ; "
|
|
"Fred<float> fred ; "
|
|
"class Fred<float> { Fred<float> ( ) ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template5() {
|
|
const char code[] = "template <class T> class Fred { };\n"
|
|
"template <class T> Fred<T>::Fred() { }\n"
|
|
"Fred<float> fred;";
|
|
|
|
const char expected[] = "class Fred<float> ; "
|
|
"Fred<float> fred ; "
|
|
"class Fred<float> { } ; "
|
|
"Fred<float> :: Fred<float> ( ) { }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template6() {
|
|
const char code[] = "template <class T> class Fred { };\n"
|
|
"Fred<float> fred1;\n"
|
|
"Fred<float> fred2;";
|
|
|
|
const char expected[] = "class Fred<float> ; "
|
|
"Fred<float> fred1 ; "
|
|
"Fred<float> fred2 ; "
|
|
"class Fred<float> { } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template7() {
|
|
// A template class that is not used => no simplification
|
|
{
|
|
const char code[] = "template <class T>\n"
|
|
"class ABC\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" typedef ABC<T> m;\n"
|
|
"};\n";
|
|
|
|
const char expected[] = "template < class T > class ABC { public: } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
{
|
|
const char code[] = "template <typename T> class ABC {\n"
|
|
"public:\n"
|
|
" typedef std::vector<T> type;\n"
|
|
"};\n"
|
|
"int main() {\n"
|
|
" ABC<int>::type v;\n"
|
|
" v.push_back(4);\n"
|
|
" return 0;\n"
|
|
"}\n";
|
|
|
|
const char wanted[] = "class ABC<int> ; "
|
|
"int main ( ) { "
|
|
"std :: vector < int > v ; "
|
|
"v . push_back ( 4 ) ; "
|
|
"return 0 ; "
|
|
"} "
|
|
"class ABC<int> { public: } ;";
|
|
|
|
const char current[] = "class ABC<int> ; "
|
|
"int main ( ) { "
|
|
"ABC<int> :: type v ; "
|
|
"v . push_back ( 4 ) ; "
|
|
"return 0 ; "
|
|
"} "
|
|
"class ABC<int> { public: } ;";
|
|
|
|
TODO_ASSERT_EQUALS(wanted, current, tok(code));
|
|
}
|
|
|
|
{
|
|
const char code[] = "template <typename T> class ABC {\n"
|
|
"public:\n"
|
|
" typedef std::vector<T> type;\n"
|
|
" void f()\n"
|
|
" {\n"
|
|
" ABC<int>::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<typename T> class A;\n"
|
|
"template<typename T> class B;\n"
|
|
"\n"
|
|
"typedef A<int> x;\n"
|
|
"typedef B<int> y;\n"
|
|
"\n"
|
|
"template<typename T> class A {\n"
|
|
" void f() {\n"
|
|
" B<T> a = B<T>::g();\n"
|
|
" T b = 0;\n"
|
|
" if (b)\n"
|
|
" b = 0;\n"
|
|
" }\n"
|
|
"};\n"
|
|
"\n"
|
|
"template<typename T> inline B<T> h() { return B<T>(); }\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<typename T> 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<int> ; "
|
|
"void f ( ) { A<int> a ; } ; "
|
|
"class A<int> { } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template10() {
|
|
const char code[] = "template <int ui, typename T> 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 <int ui, typename T> 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 <int x, int y, int z>\n"
|
|
"class A : public B<x, y, (x - y) ? ((y < z) ? 1 : -1) : 0>\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 <class T>\n"
|
|
"class AA {\n"
|
|
"public:\n"
|
|
" static AA<T> create(T* newObject);\n"
|
|
" static int size();\n"
|
|
"};\n"
|
|
"\n"
|
|
"class CC { public: CC(AA<BB>, int) {} };\n"
|
|
"\n"
|
|
"class XX {\n"
|
|
" AA<CC> y;\n"
|
|
"public:\n"
|
|
" XX();\n"
|
|
"};\n"
|
|
"\n"
|
|
"XX::XX():\n"
|
|
" y(AA<CC>::create(new CC(AA<BB>(), 0)))\n"
|
|
" {}\n"
|
|
"\n"
|
|
"int yy[AA<CC>::size()];";
|
|
const char expected[] = "class BB { } ; "
|
|
"class AA<BB> ; "
|
|
"class AA<CC> ; "
|
|
"class CC { public: CC ( AA<BB> , int ) { } } ; "
|
|
"class XX { "
|
|
"AA<CC> y ; "
|
|
"public: "
|
|
"XX ( ) ; "
|
|
"} ; "
|
|
"XX :: XX ( ) : "
|
|
"y ( AA<CC> :: create ( new CC ( AA<BB> ( ) , 0 ) ) ) "
|
|
"{ } "
|
|
"int yy [ AA<CC> :: size ( ) ] ; "
|
|
"class AA<BB> { "
|
|
"public: "
|
|
"static AA<BB> create ( BB * newObject ) ; "
|
|
"static int size ( ) ; "
|
|
"} ; "
|
|
"class AA<CC> { "
|
|
"public: "
|
|
"static AA<CC> create ( CC * newObject ) ; "
|
|
"static int size ( ) ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template14() {
|
|
const char code[] = "template <> void foo<int *>()\n"
|
|
"{ x(); }\n"
|
|
"\n"
|
|
"int main()\n"
|
|
"{\n"
|
|
"foo<int*>();\n"
|
|
"}\n";
|
|
const char expected[] = "void foo<int*> ( ) ; "
|
|
"void foo<int*> ( ) "
|
|
"{ x ( ) ; } "
|
|
"int main ( ) "
|
|
"{ foo<int*> ( ) ; }";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template15() { // recursive templates #3130 etc
|
|
const char code[] = "template <unsigned int i> void a()\n"
|
|
"{\n"
|
|
" a<i-1>();\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 <int n> struct vec {\n"
|
|
" vec() {}\n"
|
|
" vec(const vec<n-1>& 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 <unsigned int i> void a()\n"
|
|
"{ }\n"
|
|
"\n"
|
|
"template <unsigned int i> void b()\n"
|
|
"{ a<i>(); }\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<class T>\n"
|
|
"class Fred\n"
|
|
"{\n"
|
|
" template<class T>\n"
|
|
" static shared_ptr< Fred<T> > CreateFred()\n"
|
|
" {\n"
|
|
" }\n"
|
|
"};\n"
|
|
"\n"
|
|
"shared_ptr<int> 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 T> class foo { T a; };\n"
|
|
"foo<int> *f;";
|
|
|
|
const char expected[] = "class foo<int> ; "
|
|
"foo<int> * f ; "
|
|
"class foo<int> { int a ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template19() {
|
|
const char code[] = "template <typename T> T & foo()\n"
|
|
"{ static T temp; return temp; }\n"
|
|
"\n"
|
|
"void f ( )\n"
|
|
"{\n"
|
|
" char p = foo<char>();\n"
|
|
"}\n";
|
|
|
|
// The expected result..
|
|
const char expected[] = "char & foo<char> ( ) ; "
|
|
"void f ( ) "
|
|
"{"
|
|
" char p ; p = foo<char> ( ) ; "
|
|
"} "
|
|
"char & foo<char> ( ) { static char temp ; return temp ; }";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template20() {
|
|
// Ticket #1788 - the destructor implementation is lost
|
|
const char code[] = "template <class T> class A { public: ~A(); };\n"
|
|
"template <class T> A<T>::~A() {}\n"
|
|
"A<int> a;\n";
|
|
|
|
// The expected result..
|
|
const char expected[] = "class A<int> ; "
|
|
"A<int> a ; "
|
|
"class A<int> { public: ~ A<int> ( ) ; } ; "
|
|
"A<int> :: ~ A<int> ( ) { }";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template21() {
|
|
{
|
|
const char code[] = "template <class T> struct Fred { T a; };\n"
|
|
"Fred<int> fred;";
|
|
|
|
const char expected[] = "struct Fred<int> ; "
|
|
"Fred<int> fred ; "
|
|
"struct Fred<int> { int a ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
{
|
|
const char code[] = "template <class T, int sz> struct Fred { T data[sz]; };\n"
|
|
"Fred<float,4> fred;";
|
|
|
|
const char expected[] = "struct Fred<float,4> ; "
|
|
"Fred<float,4> fred ; "
|
|
"struct Fred<float,4> { float data [ 4 ] ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
{
|
|
const char code[] = "template <class T> struct Fred { Fred(); };\n"
|
|
"Fred<float> fred;";
|
|
|
|
const char expected[] = "struct Fred<float> ; "
|
|
"Fred<float> fred ; "
|
|
"struct Fred<float> { Fred<float> ( ) ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
{
|
|
const char code[] = "template <class T> struct Fred { };\n"
|
|
"Fred<float> fred1;\n"
|
|
"Fred<float> fred2;";
|
|
|
|
const char expected[] = "struct Fred<float> ; "
|
|
"Fred<float> fred1 ; "
|
|
"Fred<float> fred2 ; "
|
|
"struct Fred<float> { } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
}
|
|
|
|
void template22() {
|
|
const char code[] = "template <class T> struct Fred { T a; };\n"
|
|
"Fred<std::string> fred;";
|
|
|
|
const char expected[] = "struct Fred<std::string> ; "
|
|
"Fred<std::string> fred ; "
|
|
"struct Fred<std::string> { std :: string a ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template23() {
|
|
const char code[] = "template <class T> void foo() { }\n"
|
|
"void bar() {\n"
|
|
" std::cout << (foo<double>());\n"
|
|
"}";
|
|
|
|
const char expected[] = "void foo<double> ( ) ; "
|
|
"void bar ( ) {"
|
|
" std :: cout << ( foo<double> ( ) ) ; "
|
|
"} "
|
|
"void foo<double> ( ) { }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template24() {
|
|
// #2648
|
|
const char code[] = "template<int n> struct B\n"
|
|
"{\n"
|
|
" int a[n];\n"
|
|
"};\n"
|
|
"\n"
|
|
"template<int x> class bitset: B<sizeof(int)>\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<int n> struct B\n"
|
|
"{\n"
|
|
" int a[n];\n"
|
|
"};\n"
|
|
"\n"
|
|
"template<int x> 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<class T>\n"
|
|
"class A { public: T x; };\n"
|
|
"\n"
|
|
"template<class M>\n"
|
|
"class C: public A<char[M]> {};\n"
|
|
"\n"
|
|
"C<2> a;\n";
|
|
// TODO: expand A also
|
|
ASSERT_EQUALS("template < class T > class A { public: T x ; } ; class C<2> ; C<2> a ; class C<2> : public A < char [ 2 ] > { } ;", tok(code));
|
|
}
|
|
|
|
void template27() {
|
|
// #3350 - template inside macro call
|
|
const char code[] = "X(template<class T> class Fred);";
|
|
ASSERT_THROW(tok(code), InternalError);
|
|
}
|
|
|
|
void template28() {
|
|
// #3226 - inner template
|
|
const char code[] = "template<class A, class B> class Fred {};\n"
|
|
"Fred<int,Fred<int,int> > x;\n";
|
|
ASSERT_EQUALS("class Fred<int,int> ; "
|
|
"class Fred<int,Fred<int,int>> ; "
|
|
"Fred<int,Fred<int,int>> x ; "
|
|
"class Fred<int,int> { } ; "
|
|
"class Fred<int,Fred<int,int>> { } ;", tok(code));
|
|
}
|
|
|
|
void template30() {
|
|
// #3529 - template < template < ..
|
|
const char code[] = "template<template<class> 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<class T> struct A{}; A<int&> a;";
|
|
ASSERT_EQUALS("struct A<int&> ; "
|
|
"A<int&> a ; "
|
|
"struct A<int&> { } ;", tok(code));
|
|
|
|
// #7409 - rvalue
|
|
const char code2[] = "template<class T> struct A{}; A<int&&> a;";
|
|
ASSERT_EQUALS("struct A<int&&> ; "
|
|
"A<int&&> a ; "
|
|
"struct A<int&&> { } ;", tok(code2));
|
|
}
|
|
|
|
void template32() {
|
|
// #3818 - mismatching template not handled well
|
|
const char code[] = "template <class T1, class T2, class T3, class T4 > struct A { };\n"
|
|
"\n"
|
|
"template <class T>\n"
|
|
"struct B\n"
|
|
"{\n"
|
|
" public:\n"
|
|
" A < int, Pair<T, int>, int > a;\n" // mismatching parameters => don't instantiate
|
|
"};\n"
|
|
"\n"
|
|
"B<int> b;\n";
|
|
ASSERT_EQUALS("template < class T1 , class T2 , class T3 , class T4 > struct A { } ; "
|
|
"struct B<int> ; "
|
|
"B<int> b ; "
|
|
"struct B<int> { 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<class T> struct A { };\n"
|
|
"template<class T> struct B { };\n"
|
|
"template<class T> struct C { A<B<X<T> > > ab; };\n"
|
|
"C<int> c;";
|
|
ASSERT_EQUALS("struct A<B<X<int>>> ; "
|
|
"struct B<X<int>> ; "
|
|
"struct C<int> ; "
|
|
"C<int> c ; "
|
|
"struct C<int> { A<B<X<int>>> ab ; } ; "
|
|
"struct B<X<int>> { } ; " // <- redundant.. but nevermind
|
|
"struct A<B<X<int>>> { } ;", tok(code));
|
|
}
|
|
|
|
{
|
|
// #4544
|
|
const char code[] = "struct A { };\n"
|
|
"template<class T> struct B { };\n"
|
|
"template<class T> struct C { };\n"
|
|
"C< B<A> > c;";
|
|
ASSERT_EQUALS("struct A { } ; "
|
|
"template < class T > struct B { } ; " // <- redundant.. but nevermind
|
|
"struct C<B<A>> ; "
|
|
"C<B<A>> c ; "
|
|
"struct C<B<A>> { } ;",
|
|
tok(code));
|
|
}
|
|
}
|
|
|
|
void template34() {
|
|
// #3706 - namespace => hang
|
|
const char code[] = "namespace abc {\n"
|
|
"template <typename T> struct X { void f(X<T> &x) {} };\n"
|
|
"}\n"
|
|
"template <> int X<int>::Y(0);";
|
|
tok(code);
|
|
}
|
|
|
|
void template35() { // #4074 - "A<'x'> a;" is not recognized as template instantiation
|
|
const char code[] = "template <char c> 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 <class T> struct X { T t; };\n"
|
|
"template <class C> struct Y { Foo < X< Bar<C> > > _foo; };\n" // <- Bar is unknown
|
|
"Y<int> bar;";
|
|
ASSERT_EQUALS("struct X<Bar<int>> ; "
|
|
"struct Y<int> ; "
|
|
"Y<int> bar ; "
|
|
"struct Y<int> { Foo < X<Bar<int>> > _foo ; } ; "
|
|
"struct X<Bar<int>> { Bar < int > t ; } ;",
|
|
tok(code));
|
|
}
|
|
|
|
void template37() { // #4544 - A<class B> a;
|
|
{
|
|
const char code[] = "class A { };\n"
|
|
"template<class T> class B {};\n"
|
|
"B<class A> b1;\n"
|
|
"B<A> b2;";
|
|
ASSERT_EQUALS("class A { } ; class B<A> ; B<A> b1 ; B<A> b2 ; class B<A> { } ;",
|
|
tok(code));
|
|
}
|
|
{
|
|
const char code[] = "struct A { };\n"
|
|
"template<class T> class B {};\n"
|
|
"B<struct A> b1;\n"
|
|
"B<A> b2;";
|
|
ASSERT_EQUALS("struct A { } ; class B<A> ; B<A> b1 ; B<A> b2 ; class B<A> { } ;",
|
|
tok(code));
|
|
}
|
|
{
|
|
const char code[] = "enum A { };\n"
|
|
"template<class T> class B {};\n"
|
|
"B<enum A> b1;\n"
|
|
"B<A> b2;";
|
|
ASSERT_EQUALS("enum A { } ; class B<A> ; B<A> b1 ; B<A> b2 ; class B<A> { } ;",
|
|
tok(code));
|
|
}
|
|
}
|
|
|
|
void template_unhandled() {
|
|
// An unhandled template usage should be simplified..
|
|
ASSERT_EQUALS("x<int> ( ) ;", tok("x<int>();"));
|
|
}
|
|
|
|
void template38() { // #4832 - Crash on C++11 right angle brackets
|
|
const char code[] = "template <class T> class A {\n"
|
|
" T mT;\n"
|
|
"public:\n"
|
|
" void foo() {}\n"
|
|
"};\n"
|
|
"\n"
|
|
"int main() {\n"
|
|
" A<A<BLA>> gna1;\n"
|
|
" A<BLA> gna2;\n"
|
|
"}\n";
|
|
const char expected[] = "class A<BLA> ; "
|
|
"class A<A<BLA>> ; "
|
|
"int main ( ) { "
|
|
"A<A<BLA>> gna1 ; "
|
|
"A<BLA> gna2 ; "
|
|
"} "
|
|
"class A<BLA> { "
|
|
"BLA mT ; "
|
|
"public: "
|
|
"void foo ( ) { } "
|
|
"} ; "
|
|
"class A<A<BLA>> { "
|
|
"A<BLA> mT ; "
|
|
"public: "
|
|
"void foo ( ) { } "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template39() { // #4742 - Used to freeze in 1.60
|
|
const char code[] = "template<typename T> struct vector {"
|
|
" operator T() const;"
|
|
"};"
|
|
"void f() {"
|
|
" vector<vector<int>> v;"
|
|
" const vector<int> vi = static_cast<vector<int>>(v);"
|
|
"}";
|
|
tok(code);
|
|
}
|
|
|
|
void template40() { // #5055 - false negatives when there is template specialization outside struct
|
|
const char code[] = "struct A {"
|
|
" template<typename T> struct X { T t; };"
|
|
"};"
|
|
"template<> struct A::X<int> { int *t; };";
|
|
const char expected[] = "struct A { "
|
|
"struct X<int> ; "
|
|
"template < typename T > struct X { T t ; } ; "
|
|
"} ; "
|
|
"struct A :: X<int> { int * t ; } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template41() { // #4710 - const in template instantiation not handled perfectly
|
|
const char code1[] = "template<class T> struct X { };\n"
|
|
"void f(const X<int> x) { }";
|
|
ASSERT_EQUALS("struct X<int> ; "
|
|
"void f ( const X<int> x ) { } "
|
|
"struct X<int> { } ;", tok(code1));
|
|
|
|
const char code2[] = "template<class T> T f(T t) { return t; }\n"
|
|
"int x() { return f<int>(123); }";
|
|
ASSERT_EQUALS("int f<int> ( int t ) ; "
|
|
"int x ( ) { return f<int> ( 123 ) ; } "
|
|
"int f<int> ( int t ) { return t ; }", tok(code2));
|
|
}
|
|
|
|
void template42() { // #4878 cppcheck aborts in ext-blocks.cpp (clang testcode)
|
|
const char code[] = "template<typename ...Args>\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<A<C>>' not being treated as end of template instantiation
|
|
const char code[] = "template <typename T> struct E { typedef int Int; };\n"
|
|
"template <typename T> struct C { };\n"
|
|
"template <typename T> struct D { static int f() { return C<T>::f(); } };\n"
|
|
"template <typename T> inline int f2() { return D<T>::f(); }\n"
|
|
"template <typename T> int f1 (int x, T *) { int id = f2<T>(); return id; }\n"
|
|
"template <typename T> struct B { void f3(B<T> & other) { } };\n"
|
|
"struct A { };\n"
|
|
"template <> struct C<B<A>> {\n"
|
|
" static int f() { return f1<B<A>>(0, reinterpret_cast<B<A>*>(E<void*>::Int(-1))); }\n"
|
|
"};\n"
|
|
"int main(void) {\n"
|
|
" C<A> ca;\n"
|
|
" return 0;\n"
|
|
"}";
|
|
const char expected[] = "struct E<void*> ; "
|
|
"struct C<B<A>> ; "
|
|
"struct C<A> ; "
|
|
"struct D<B<A>> ; "
|
|
"int f2<B<A>> ( ) ; "
|
|
"int f1<B<A>> ( int x , B<A> * ) ; "
|
|
"struct B<A> ; "
|
|
"struct A { } ; "
|
|
"struct C<B<A>> { "
|
|
"static int f ( ) { "
|
|
"return f1<B<A>> ( 0 , reinterpret_cast < B<A> * > ( E<void*> :: Int ( -1 ) ) ) ; "
|
|
"} "
|
|
"} ; "
|
|
"int main ( ) { "
|
|
"C<A> ca ; "
|
|
"return 0 ; "
|
|
"} "
|
|
"struct B<A> { "
|
|
"void f3 ( B<A> & other ) { } "
|
|
"} ; "
|
|
"int f1<B<A>> ( int x , B<A> * ) { "
|
|
"int id ; id = f2<B<A>> ( ) ; "
|
|
"return id ; "
|
|
"} "
|
|
"int f2<B<A>> ( ) { "
|
|
"return D<B<A>> :: f ( ) ; "
|
|
"} "
|
|
"struct D<B<A>> { "
|
|
"static int f ( ) { "
|
|
"return C<B<A>> :: f ( ) ; "
|
|
"} "
|
|
"} ; "
|
|
"struct C<A> { } ; struct E<void*> { "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template44() { // #5297
|
|
const char code[] = "template<class T> struct StackContainer {"
|
|
" void foo(int i) {"
|
|
" if (0 >= 1 && i<0) {}"
|
|
" }"
|
|
"};"
|
|
"template<class T> class ZContainer : public StackContainer<T> {};"
|
|
"struct FGSTensor {};"
|
|
"class FoldedZContainer : public ZContainer<FGSTensor> {};";
|
|
const char expected[] = "struct StackContainer<FGSTensor> ; "
|
|
"class ZContainer<FGSTensor> ; "
|
|
"struct FGSTensor { } ; "
|
|
"class FoldedZContainer : public ZContainer<FGSTensor> { } ; "
|
|
"class ZContainer<FGSTensor> : public StackContainer<FGSTensor> { } ; "
|
|
"struct StackContainer<FGSTensor> { "
|
|
"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 <class T, int U> struct TypeMath { "
|
|
" static const int mult = sizeof(T) * U; "
|
|
"}; "
|
|
"template <class T> struct FOO { "
|
|
" enum { value = TypeMath<T, Constants::fourtytwo>::mult }; "
|
|
"}; "
|
|
"FOO<int> foo;";
|
|
const char expected[] = "namespace Constants { const int fourtytwo = 42 ; } "
|
|
"struct TypeMath<int,Constants::fourtytwo> ; "
|
|
"struct FOO<int> ; "
|
|
"FOO<int> foo ; "
|
|
"struct FOO<int> { "
|
|
"enum Anonymous0 { value = TypeMath<int,Constants::fourtytwo> :: mult } ; "
|
|
"} ; "
|
|
"struct TypeMath<int,Constants::fourtytwo> { "
|
|
"static const int mult = sizeof ( int ) * Constants :: fourtytwo ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code, true));
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template46() { // #5816
|
|
tok("template<class T, class U> struct A { static const int value = 0; }; "
|
|
"template <class T> struct B { "
|
|
" enum { value = A<typename T::type, int>::value }; "
|
|
"};");
|
|
ASSERT_EQUALS("", errout.str());
|
|
tok("template <class T, class U> struct A {}; "
|
|
"enum { e = sizeof(A<int, int>) }; "
|
|
"template <class T, class U> struct B {};");
|
|
ASSERT_EQUALS("", errout.str());
|
|
tok("template<class T, class U> struct A { static const int value = 0; }; "
|
|
"template<class T> struct B { typedef int type; }; "
|
|
"template <class T> struct C { "
|
|
" enum { value = A<typename B<T>::type, int>::value }; "
|
|
"};");
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template47() { // #6023
|
|
tok("template <typename T1, typename T2 = T3<T1> > class C1 {}; "
|
|
"class C2 : public C1<C2> {};");
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template48() { // #6134
|
|
tok("template <int> int f( { } ); "
|
|
"int foo = f<1>(0);");
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template49() { // #6237
|
|
const char code[] = "template <class T> class Fred { void f(); void g(); };\n"
|
|
"template <class T> void Fred<T>::f() { }\n"
|
|
"template <class T> void Fred<T>::g() { }\n"
|
|
"template void Fred<float>::f();\n"
|
|
"template void Fred<int>::g();\n";
|
|
|
|
const char expected[] = "class Fred<float> ; "
|
|
"class Fred<int> ; "
|
|
"class Fred<float> { void f ( ) ; void g ( ) ; } ; "
|
|
"void Fred<float> :: f ( ) { } "
|
|
"void Fred<float> :: g ( ) { } "
|
|
"class Fred<int> { void f ( ) ; void g ( ) ; } ; "
|
|
"void Fred<int> :: f ( ) { } "
|
|
"void Fred<int> :: g ( ) { }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template50() { // #4272
|
|
const char code[] = "template <class T> class Fred { void f(); };\n"
|
|
"template <class T> void Fred<T>::f() { }\n"
|
|
"template<> void Fred<float>::f() { }\n"
|
|
"template<> void Fred<int>::f() { }\n";
|
|
|
|
const char expected[] = "class Fred<float> ; "
|
|
"class Fred<int> ; "
|
|
"template < > void Fred<float> :: f ( ) { } "
|
|
"template < > void Fred<int> :: f ( ) { } "
|
|
"class Fred<float> { void f ( ) ; } ; "
|
|
"void Fred<float> :: f ( ) { } "
|
|
"class Fred<int> { void f ( ) ; } ; "
|
|
"void Fred<int> :: f ( ) { }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template51() { // #6172
|
|
tok("template<int N, int ... M> struct A { "
|
|
" static void foo() { "
|
|
" int i = N; "
|
|
" } "
|
|
"}; "
|
|
"void bar() { "
|
|
" A<0>::foo(); "
|
|
"}");
|
|
}
|
|
|
|
void template52() { // #6437
|
|
const char code[] = "template <int value> int sum() { "
|
|
" return value + sum<value/2>(); "
|
|
"} "
|
|
"template<int x, int y> int calculate_value() { "
|
|
" if (x != y) { "
|
|
" return sum<x - y>(); "
|
|
" } 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<int N> struct Factorial { "
|
|
" enum { value = N * Factorial<N - 1>::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<typename _Tp> _Tp* fn(); "
|
|
"template <class T> struct A { "
|
|
" template <class U, class S = decltype(fn<T>())> "
|
|
" struct B { }; "
|
|
"}; "
|
|
"A<int> 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 T> class AtSmartPtr : public ConstCastHelper<AtSmartPtr<const T>, T>\n"
|
|
"{\n"
|
|
" friend struct ConstCastHelper<AtSmartPtr<const T>, T>;\n"
|
|
" AtSmartPtr(const AtSmartPtr<T>& r);\n"
|
|
"};"));
|
|
|
|
// Similar problem can also happen with ...
|
|
ASSERT_EQUALS(
|
|
"struct A<int> ; "
|
|
"struct A<int...> ; "
|
|
"A<int> a ( 0 ) ; "
|
|
"struct A<int> { "
|
|
"A<int> ( int * p ) { ( A<int...> * ) ( p ) ; } "
|
|
"} ; "
|
|
"struct A<int...> { "
|
|
"A<int...> ( int * p ) { "
|
|
"( A<int...> * ) ( p ) ; "
|
|
"} } ;",
|
|
tok("template <typename... T> struct A\n"
|
|
"{\n"
|
|
" A(T* p) {\n"
|
|
" (A<T...>*)(p);\n"
|
|
" }\n"
|
|
"};\n"
|
|
"A<int> a(0);"));
|
|
}
|
|
|
|
void template56() { // #7117
|
|
const char code[] = "template<bool B> struct Foo { "
|
|
" std::array<int, B ? 1 : 2> mfoo; "
|
|
"}; "
|
|
"void foo() { "
|
|
" Foo<true> myFoo; "
|
|
"}";
|
|
const char expected[] = "struct Foo<true> ; "
|
|
"void foo ( ) { "
|
|
"Foo<true> myFoo ; "
|
|
"} struct Foo<true> { "
|
|
"std :: array < int , 1 > mfoo ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code, true));
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template57() { // #7891
|
|
const char code[] = "template<class T> struct Test { Test(T); };\n"
|
|
"Test<unsigned long> test( 0 );";
|
|
const char exp [] = "struct Test<unsignedlong> ; "
|
|
"Test<unsignedlong> test ( 0 ) ; "
|
|
"struct Test<unsignedlong> { Test<unsignedlong> ( unsigned long ) ; } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template58() { // #6021
|
|
const char code[] = "template <typename A>\n"
|
|
"void TestArithmetic() {\n"
|
|
" x(1 * CheckedNumeric<A>());\n"
|
|
"}\n"
|
|
"void foo() {\n"
|
|
" TestArithmetic<int>();\n"
|
|
"}";
|
|
const char exp[] = "void TestArithmetic<int> ( ) ; "
|
|
"void foo ( ) {"
|
|
" TestArithmetic<int> ( ) ; "
|
|
"} "
|
|
"void TestArithmetic<int> ( ) {"
|
|
" x ( 1 * CheckedNumeric < int > ( ) ) ; "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template59() { // #8051
|
|
const char code[] = "template<int N>\n"
|
|
"struct Factorial {\n"
|
|
" enum FacHelper { value = N * Factorial<N - 1>::value };\n"
|
|
"};\n"
|
|
"template <>\n"
|
|
"struct Factorial<0> {\n"
|
|
" enum FacHelper { value = 1 };\n"
|
|
"};\n"
|
|
"template<int DiagonalDegree>\n"
|
|
"int diagonalGroupTest() {\n"
|
|
" return Factorial<DiagonalDegree>::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 <typename T> struct S { typedef int type; };\n"
|
|
"template <typename T> void f() {}\n"
|
|
"template <typename T> void h() { f<typename S<T>::type(0)>(); }\n"
|
|
"\n"
|
|
"void j() { h<int>(); }";
|
|
const char exp[] = "struct S<int> ; "
|
|
"void f<S<int>::type(0)> ( ) ; "
|
|
"void h<int> ( ) ; "
|
|
"void j ( ) { h<int> ( ) ; } "
|
|
"void h<int> ( ) { f<S<int>::type(0)> ( ) ; } "
|
|
"struct S<int> { } ; "
|
|
"void f<S<int>::type(0)> ( ) { }";
|
|
const char act[] = "template < typename T > struct S { } ; "
|
|
"void f<S<int>::type(0)> ( ) ; "
|
|
"void h<int> ( ) ; "
|
|
"void j ( ) { h<int> ( ) ; } "
|
|
"void h<int> ( ) { f<S<int>::type(0)> ( ) ; } "
|
|
"void f<S<int>::type(0)> ( ) { }";
|
|
TODO_ASSERT_EQUALS(exp, act, tok(code));
|
|
}
|
|
|
|
void template61() { // hang in daca, code extracted from kodi
|
|
const char code[] = "template <typename T> struct Foo {};\n"
|
|
"template <typename T> struct Bar {\n"
|
|
" void f1(Bar<T> x) {}\n"
|
|
" Foo<Bar<T>> f2() { }\n"
|
|
"};\n"
|
|
"Bar<int> c;";
|
|
const char exp[] = "struct Foo<Bar<int>> ; "
|
|
"struct Bar<int> ; "
|
|
"Bar<int> c ; "
|
|
"struct Bar<int> {"
|
|
" void f1 ( Bar<int> x ) { }"
|
|
" Foo<Bar<int>> f2 ( ) { } "
|
|
"} ; "
|
|
"struct Foo<Bar<int>> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template62() { // #8314
|
|
const char code[] = "template <class T> struct C1 {};\n"
|
|
"template <class T> void f() { x = y ? C1<int>::allocate(1) : 0; }\n"
|
|
"template <class T, unsigned S> class C3 {};\n"
|
|
"template <class T, unsigned S> C3<T, S>::C3(const C3<T, S> &v) { C1<T *> c1; }\n"
|
|
"C3<int,6> c3;";
|
|
const char exp[] = "struct C1<int*> ; "
|
|
"class C3<int,6> ; "
|
|
"C3<int,6> c3 ; "
|
|
"class C3<int,6> { } ; "
|
|
"C3<int,6> :: C3<int,6> ( const C3<int,6> & v ) { C1<int*> c1 ; } "
|
|
"struct C1<int*> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template63() { // #8576
|
|
const char code[] = "template<class T> struct TestClass { T m_hi; };"
|
|
"TestClass<std::auto_ptr<v>> objTest3;";
|
|
const char exp[] = "struct TestClass<std::auto_ptr<v>> ; "
|
|
"TestClass<std::auto_ptr<v>> objTest3 ; "
|
|
"struct TestClass<std::auto_ptr<v>> { std :: auto_ptr < v > m_hi ; } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template64() { // #8683
|
|
const char code[] = "template <typename T>\n"
|
|
"bool foo(){return true;}\n"
|
|
"struct A {\n"
|
|
"template<int n>\n"
|
|
"void t_func()\n"
|
|
"{\n"
|
|
" if( n != 0 || foo<int>());\n"
|
|
"}\n"
|
|
"void t_caller()\n"
|
|
"{\n"
|
|
" t_func<0>();\n"
|
|
" t_func<1>();\n"
|
|
"}\n"
|
|
"};";
|
|
const char exp [] = "bool foo<int> ( ) ; "
|
|
"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<int> ( ) ) { ; } "
|
|
"} "
|
|
"void A :: t_func<1> ( ) "
|
|
"{ "
|
|
"if ( 1 != 0 || foo<int> ( ) ) { ; } "
|
|
"} "
|
|
"bool foo<int> ( ) { return true ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template65() { // #8321 (crash)
|
|
const char code[] = "namespace bpp\n"
|
|
"{\n"
|
|
"template<class N, class E, class DAGraphImpl>\n"
|
|
"class AssociationDAGraphImplObserver :\n"
|
|
" public AssociationGraphImplObserver<N, E, DAGraphImpl>\n"
|
|
"{};\n"
|
|
"template<class N, class E>\n"
|
|
"using AssociationDAGlobalGraphObserver = AssociationDAGraphImplObserver<N, E, DAGlobalGraph>;\n"
|
|
"}\n"
|
|
"using namespace bpp;\n"
|
|
"using namespace std;\n"
|
|
"int main() {\n"
|
|
" AssociationDAGlobalGraphObserver<string,unsigned int> grObs;\n"
|
|
" return 1;\n"
|
|
"}";
|
|
const char exp [] = "namespace bpp "
|
|
"{ "
|
|
"class AssociationDAGraphImplObserver<string,unsignedint,DAGlobalGraph> ; "
|
|
"} "
|
|
"using namespace bpp ; "
|
|
"int main ( ) { "
|
|
"bpp :: AssociationDAGraphImplObserver<string,unsignedint,DAGlobalGraph> grObs ; "
|
|
"return 1 ; "
|
|
"} class bpp :: AssociationDAGraphImplObserver<string,unsignedint,DAGlobalGraph> : "
|
|
"public AssociationGraphImplObserver < std :: string , unsigned int , DAGlobalGraph > "
|
|
"{ } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template66() { // #8725
|
|
const char code[] = "template <class T> struct Fred {\n"
|
|
" const int ** foo();\n"
|
|
"};\n"
|
|
"template <class T> const int ** Fred<T>::foo() { return nullptr; }\n"
|
|
"Fred<int> fred;";
|
|
const char exp [] = "struct Fred<int> ; "
|
|
"Fred<int> fred ; "
|
|
"struct Fred<int> { "
|
|
"const int * * foo ( ) ; "
|
|
"} ; "
|
|
"const int * * Fred<int> :: foo ( ) { return nullptr ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template67() { // ticket #8122
|
|
const char code[] = "template <class T> 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 <class T> Container<T>::Container() : mElements(nullptr), c(nullptr) {}\n"
|
|
"template <class T> Container<T>::Container(const Container & x) { nElements = x.nElements; c = x.c; }\n"
|
|
"template <class T> Container<T> & Container<T>::operator = (const Container & x) { mElements = x.mElements; c = x.c; return *this; }\n"
|
|
"template <class T> Container<T>::~Container() {}\n"
|
|
"Container<int> intContainer;";
|
|
|
|
const char expected[] = "struct Container<int> ; "
|
|
"Container<int> intContainer ; "
|
|
"struct Container<int> { "
|
|
"Container<int> ( ) ; "
|
|
"Container<int> ( const Container<int> & ) ; "
|
|
"Container<int> & operator= ( const Container<int> & ) ; "
|
|
"~ Container<int> ( ) ; "
|
|
"int * mElements ; "
|
|
"const Container<int> * c ; "
|
|
"} ; "
|
|
"Container<int> :: Container<int> ( ) : mElements ( nullptr ) , c ( nullptr ) { } "
|
|
"Container<int> :: Container<int> ( const Container<int> & x ) { nElements = x . nElements ; c = x . c ; } "
|
|
"Container<int> & Container<int> :: operator= ( const Container<int> & x ) { mElements = x . mElements ; c = x . c ; return * this ; } "
|
|
"Container<int> :: ~ Container<int> ( ) { }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template68() {
|
|
const char code[] = "template <class T> union Fred {\n"
|
|
" char dummy[sizeof(T)];\n"
|
|
" T value;\n"
|
|
"};\n"
|
|
"Fred<int> fred;";
|
|
const char exp [] = "union Fred<int> ; "
|
|
"Fred<int> fred ; "
|
|
"union Fred<int> { "
|
|
"char dummy [ sizeof ( int ) ] ; "
|
|
"int value ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template69() { // #8791
|
|
const char code[] = "class Test {\n"
|
|
" int test;\n"
|
|
" template <class T> T lookup() { return test; }\n"
|
|
" int Fun() { return lookup<int>(); }\n"
|
|
"};";
|
|
const char exp [] = "class Test { "
|
|
"int test ; "
|
|
"int lookup<int> ( ) ; "
|
|
"int Fun ( ) { return lookup<int> ( ) ; } "
|
|
"} ; "
|
|
"int Test :: lookup<int> ( ) { return test ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template70() { // #5289
|
|
const char code[] = "template<typename T, typename V, int KeySize = 0> class Bar;\n"
|
|
"template<>\n"
|
|
"class Bar<void, void> {\n"
|
|
"};\n"
|
|
"template<typename K, typename V, int KeySize>\n"
|
|
"class Bar : private Bar<void, void> {\n"
|
|
" void foo() { }\n"
|
|
"};";
|
|
const char exp [] = "template < typename T , typename V , int KeySize = 0 > class Bar ; "
|
|
"class Bar<void,void> ; "
|
|
"class Bar<void,void> { "
|
|
"} ; "
|
|
"template < typename K , typename V , int KeySize = 0 > "
|
|
"class Bar : private Bar<void,void> { "
|
|
"void foo ( ) { } "
|
|
"} ;";
|
|
const char act [] = "template < typename T , typename V , int KeySize = 0 > class Bar ; "
|
|
"class Bar<void,void> { "
|
|
"} ; "
|
|
"class Bar<void,void> ; "
|
|
"template < typename K , typename V , int KeySize = 0 > "
|
|
"class Bar : private Bar<void,void> { "
|
|
"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<XPropertyList> ; "
|
|
"Reference<XPropertyList> dostuff ( ) ; "
|
|
"class Reference<XPropertyList> { template < class XPropertyList > int i ( ) ; int * pInterface ; } ; "
|
|
"int Reference<XPropertyList> :: i ( ) { return f1 ( pInterface , XPropertyList :: static_type ( ) ) ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template72() {
|
|
const char code[] = "template <typename N, typename P> class Tokenizer;\n"
|
|
"const Tokenizer<Node, Path> *tokenizer() const;\n"
|
|
"template <typename N, typename P>\n"
|
|
"Tokenizer<N, P>::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<typename T>\n"
|
|
"void keep_range(T& value, const T mini, const T maxi){}\n"
|
|
"template void keep_range<float>(float& v, const float l, const float u);\n"
|
|
"template void keep_range<int>(int& v, const int l, const int u);";
|
|
const char exp[] = "void keep_range<float> ( float & value , const float mini , const float maxi ) ; "
|
|
"void keep_range<int> ( int & value , const int mini , const int maxi ) ; "
|
|
"void keep_range<float> ( float & value , const float mini , const float maxi ) { } "
|
|
"void keep_range<int> ( int & value , const int mini , const int maxi ) { }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template74() {
|
|
const char code[] = "template <class T> class BTlist { };\n"
|
|
"class PushBackStreamBuf {\n"
|
|
"public:\n"
|
|
" void pushBack(const BTlist<int> &vec);\n"
|
|
"};";
|
|
const char exp[] = "class BTlist<int> ; "
|
|
"class PushBackStreamBuf { "
|
|
"public: "
|
|
"void pushBack ( const BTlist<int> & vec ) ; "
|
|
"} ; "
|
|
"class BTlist<int> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template75() {
|
|
const char code[] = "template<typename T>\n"
|
|
"T foo(T& value){ return value; }\n"
|
|
"template std::vector<std::vector<int>> foo<std::vector<std::vector<int>>>(std::vector<std::vector<int>>& v);";
|
|
const char exp[] = "std :: vector < std :: vector < int > > foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & value ) ; "
|
|
"std :: vector < std :: vector < int > > foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & value ) { return value ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template76() {
|
|
const char code[] = "namespace NS {\n"
|
|
" template<typename T> T foo(T& value) { return value; }\n"
|
|
" template std::vector<std::vector<int>> foo<std::vector<std::vector<int>>>(std::vector<std::vector<int>>& v);\n"
|
|
"}\n"
|
|
"std::vector<std::vector<int>> v;\n"
|
|
"v = foo<std::vector<std::vector<int>>>(v);\n";
|
|
const char exp[] = "namespace NS { "
|
|
"std :: vector < std :: vector < int > > foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & value ) ; "
|
|
"} "
|
|
"std :: vector < std :: vector < int > > v ; "
|
|
"v = foo<std::vector<std::vector<int>>> ( v ) ; "
|
|
"std :: vector < std :: vector < int > > NS :: foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & value ) { return value ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template77() {
|
|
const char code[] = "template<typename T>\n"
|
|
"struct is_void : std::false_type { };\n"
|
|
"template<>\n"
|
|
"struct is_void<void> : std::true_type { };\n"
|
|
"int main() {\n"
|
|
" std::cout << is_void<char>::value << std::endl;\n"
|
|
" std::cout << is_void<void>::value << std::endl;\n"
|
|
"}";
|
|
const char exp[] = "struct is_void<void> ; "
|
|
"struct is_void<char> ; "
|
|
"struct is_void<void> : std :: true_type { } ; "
|
|
"int main ( ) { "
|
|
"std :: cout << is_void<char> :: value << std :: endl ; "
|
|
"std :: cout << is_void<void> :: value << std :: endl ; "
|
|
"} "
|
|
"struct is_void<char> : std :: false_type { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template78() {
|
|
const char code[] = "template <typename>\n"
|
|
"struct Base { };\n"
|
|
"struct S : Base <void>::Type { };";
|
|
const char exp[] = "struct Base<void> ; "
|
|
"struct S : Base<void> :: Type { } ; "
|
|
"struct Base<void> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template79() { // #5133
|
|
const char code[] = "class Foo {\n"
|
|
"public:\n"
|
|
" template<typename T> void foo() { bar<T>(); }\n"
|
|
"private:\n"
|
|
" template<typename T> void bar() { bazz(); }\n"
|
|
" void bazz() { }\n"
|
|
"};\n"
|
|
"void some_func() {\n"
|
|
" Foo x;\n"
|
|
" x.foo<int>();\n"
|
|
"}";
|
|
const char exp[] = "class Foo { "
|
|
"public: "
|
|
"void foo<int> ( ) ; "
|
|
"private: "
|
|
"void bar<int> ( ) ; "
|
|
"void bazz ( ) { } "
|
|
"} ; "
|
|
"void some_func ( ) { "
|
|
"Foo x ; "
|
|
"x . foo<int> ( ) ; "
|
|
"} "
|
|
"void Foo :: foo<int> ( ) { bar<int> ( ) ; } "
|
|
"void Foo :: bar<int> ( ) { bazz ( ) ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template80() {
|
|
const char code[] = "class Fred {\n"
|
|
" template <typename T> T foo(T t) const { return t; }\n"
|
|
"};\n"
|
|
"const void * p = Fred::foo<const void *>(nullptr);";
|
|
const char exp[] = "class Fred { "
|
|
"const void * foo<constvoid*> ( const void * t ) const ; "
|
|
"} ; "
|
|
"const void * p ; p = Fred :: foo<constvoid*> ( nullptr ) ; "
|
|
"const void * Fred :: foo<constvoid*> ( const void * t ) const { return t ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template81() {
|
|
const char code[] = "template <typename Type>\n"
|
|
"struct SortWith {\n"
|
|
" SortWith(Type);\n"
|
|
"};\n"
|
|
"template <typename Type>\n"
|
|
"SortWith<Type>::SortWith(Type) {}\n"
|
|
"int main() {\n"
|
|
" SortWith<int>(0);\n"
|
|
"}";
|
|
const char exp[] = "template < typename Type > "
|
|
"struct SortWith { "
|
|
"SortWith ( Type ) ; "
|
|
"} ; "
|
|
"SortWith<int> :: SortWith<int> ( int ) ; "
|
|
"int main ( ) { "
|
|
"SortWith<int> ( 0 ) ; "
|
|
"} "
|
|
"SortWith<int> :: SortWith<int> ( int ) { }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template82() { // 8603
|
|
const char code[] = "typedef int comp;\n"
|
|
"const int f16=16;\n"
|
|
"template<int x>\n"
|
|
"class tvec2 {};\n"
|
|
"template<int x>\n"
|
|
"class tvec3 {};\n"
|
|
"namespace swizzle {\n"
|
|
"template <comp> void swizzle(tvec2<f16> v) { }\n"
|
|
"template <comp x, comp y> void swizzle(tvec3<f16> v) { }\n"
|
|
"}\n"
|
|
"void foo() {\n"
|
|
" using namespace swizzle;\n"
|
|
" tvec2<f16> tt2;\n"
|
|
" swizzle<1>(tt2);\n"
|
|
" tvec3<f16> tt3;\n"
|
|
" swizzle<2,3>(tt3);\n"
|
|
"}";
|
|
const char exp[] = "const int f16 = 16 ; "
|
|
"class tvec2<f16> ; "
|
|
"class tvec3<f16> ; "
|
|
"namespace swizzle { "
|
|
"void swizzle<1> ( tvec2<f16> v ) ; "
|
|
"void swizzle<2,3> ( tvec3<f16> v ) ; "
|
|
"} "
|
|
"void foo ( ) { "
|
|
"using namespace swizzle ; "
|
|
"tvec2<f16> tt2 ; "
|
|
"swizzle :: swizzle<1> ( tt2 ) ; "
|
|
"tvec3<f16> tt3 ; "
|
|
"swizzle :: swizzle<2,3> ( tt3 ) ; "
|
|
"} "
|
|
"void swizzle :: swizzle<2,3> ( tvec3<f16> v ) { } "
|
|
"void swizzle :: swizzle<1> ( tvec2<f16> v ) { } "
|
|
"class tvec3<f16> { } ; "
|
|
"class tvec2<f16> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template83() { // #8867
|
|
const char code[] = "template<typename Task>\n"
|
|
"class MultiConsumer {\n"
|
|
" MultiConsumer();\n"
|
|
"};\n"
|
|
"template<typename Task>\n"
|
|
"MultiConsumer<Task>::MultiConsumer() : sizeBuffer(0) {}\n"
|
|
"MultiReads::MultiReads() {\n"
|
|
" mc = new MultiConsumer<reads_packet>();\n"
|
|
"}";
|
|
const char exp[] = "template < typename Task > " // TODO: this should be expanded
|
|
"class MultiConsumer { "
|
|
"MultiConsumer ( ) ; "
|
|
"} ; "
|
|
"MultiConsumer<reads_packet> :: MultiConsumer<reads_packet> ( ) ; "
|
|
"MultiReads :: MultiReads ( ) { "
|
|
"mc = new MultiConsumer<reads_packet> ( ) ; "
|
|
"} "
|
|
"MultiConsumer<reads_packet> :: MultiConsumer<reads_packet> ( ) : sizeBuffer ( 0 ) { }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template84() { // #8880
|
|
{
|
|
const char code[] = "template <class b, int c, class>\n"
|
|
"auto d() -> typename a<decltype(b{})>::e {\n"
|
|
" d<int, c, int>();\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 <class b, int c, class>\n"
|
|
"auto d() -> typename a<decltype(b{})>::e {\n"
|
|
" d<int, c, int>();\n"
|
|
"}"
|
|
"void foo() { d<char, 1, int>(); }";
|
|
const char exp[] = "auto d<char,1,int> ( ) . a < char > :: e ; "
|
|
"auto d<int,1,int> ( ) . a < int > :: e ; "
|
|
"void foo ( ) { d<char,1,int> ( ) ; } "
|
|
"auto d<char,1,int> ( ) . a < char > :: e { "
|
|
"d<int,1,int> ( ) ; "
|
|
"} "
|
|
"auto d<int,1,int> ( ) . a < int > :: e { "
|
|
"d<int,1,int> ( ) ; "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
}
|
|
|
|
void template85() { // #8902 - crash
|
|
const char code[] = "template<typename T>\n"
|
|
"struct C\n"
|
|
"{\n"
|
|
" template<typename U, typename std::enable_if<(!std::is_fundamental<U>::value)>::type* = nullptr>\n"
|
|
" void foo();\n"
|
|
"};\n"
|
|
"extern template void C<int>::foo<int, nullptr>();\n"
|
|
"template<typename T>\n"
|
|
"template<typename U, typename std::enable_if<(!std::is_fundamental<U>::value)>::type>\n"
|
|
"void C<T>::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 <typename T>\n"
|
|
"struct U {\n"
|
|
" static S<T> u;\n"
|
|
"};\n"
|
|
"template <typename T>\n"
|
|
"S<T> U<T>::u;\n"
|
|
"template S<int> U<int>::u;\n"
|
|
"S<int> &i = U<int>::u;";
|
|
tok(code);
|
|
}
|
|
|
|
void template87() {
|
|
const char code[] = "template<typename T>\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<constchar*> ( const char * t ) ; "
|
|
"const char & f1<constchar&> ( const char & t ) ; "
|
|
"const char * f1<constchar*> ( const char * t ) { return t ; } "
|
|
"const char & f1<constchar&> ( const char & t ) { return t ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template88() { // #6183.cpp
|
|
const char code[] = "class CTest {\n"
|
|
"public:\n"
|
|
" template <typename T>\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<bool>(true);\n"
|
|
" return 0;\n"
|
|
"}";
|
|
const char exp[] = "class CTest { "
|
|
"public: "
|
|
"static void Greeting<bool> ( 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> ( bool ) { "
|
|
"CTest :: SayHello ( ) ; "
|
|
"} "
|
|
"int main ( ) { "
|
|
"CTest :: Greeting<bool> ( true ) ; "
|
|
"return 0 ; "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template89() { // #8917
|
|
const char code[] = "struct Fred {\n"
|
|
" template <typename T> static void foo() { }\n"
|
|
"};\n"
|
|
"template void Fred::foo<char>();\n"
|
|
"template void Fred::foo<float>();\n"
|
|
"template <> void Fred::foo<bool>() { }\n"
|
|
"template <> void Fred::foo<int>() { }";
|
|
const char exp[] = "struct Fred { "
|
|
"static void foo<int> ( ) ; "
|
|
"static void foo<bool> ( ) ; "
|
|
"static void foo<char> ( ) ; "
|
|
"static void foo<float> ( ) ; "
|
|
"} ; "
|
|
"void Fred :: foo<bool> ( ) { } "
|
|
"void Fred :: foo<int> ( ) { } "
|
|
"void Fred :: foo<char> ( ) { } "
|
|
"void Fred :: foo<float> ( ) { }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template90() { // crash
|
|
const char code[] = "template <typename T> struct S1 {};\n"
|
|
"void f(S1<double>) {}\n"
|
|
"template <typename T>\n"
|
|
"decltype(S1<T>().~S1<T>()) fun1() {};";
|
|
const char exp[] = "struct S1<double> ; "
|
|
"void f ( S1<double> ) { } "
|
|
"template < typename T > "
|
|
"decltype ( S1 < T > ( ) . ~ S1 < T > ( ) ) fun1 ( ) { } ; "
|
|
"struct S1<double> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template91() {
|
|
{
|
|
const char code[] = "template<typename T> T foo(T t) { return t; }\n"
|
|
"template<> char foo<char>(char a) { return a; }\n"
|
|
"template<> int foo<int>(int a) { return a; }\n"
|
|
"template float foo<float>(float);\n"
|
|
"template double foo<double>(double);";
|
|
const char exp[] = "int foo<int> ( int a ) ; "
|
|
"char foo<char> ( char a ) ; "
|
|
"float foo<float> ( float t ) ; "
|
|
"double foo<double> ( double t ) ; "
|
|
"char foo<char> ( char a ) { return a ; } "
|
|
"int foo<int> ( int a ) { return a ; } "
|
|
"float foo<float> ( float t ) { return t ; } "
|
|
"double foo<double> ( double t ) { return t ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "struct Fred {\n"
|
|
" template<typename T> T foo(T t) { return t; }\n"
|
|
" template<> char foo<char>(char a) { return a; }\n"
|
|
" template<> int foo<int>(int a) { return a; }\n"
|
|
"};\n"
|
|
"template float Fred::foo<float>(float);\n"
|
|
"template double Fred::foo<double>(double);";
|
|
const char exp[] = "struct Fred { "
|
|
"int foo<int> ( int a ) ; "
|
|
"char foo<char> ( char a ) ; "
|
|
"float foo<float> ( float t ) ; "
|
|
"double foo<double> ( double t ) ; "
|
|
"char foo<char> ( char a ) { return a ; } "
|
|
"int foo<int> ( int a ) { return a ; } "
|
|
"} ; "
|
|
"float Fred :: foo<float> ( float t ) { return t ; } "
|
|
"double Fred :: foo<double> ( double t ) { return t ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "namespace NS1 {\n"
|
|
" namespace NS2 {\n"
|
|
" template<typename T> T foo(T t) { return t; }\n"
|
|
" template<> char foo<char>(char a) { return a; }\n"
|
|
" template<> int foo<int>(int a) { return a; }\n"
|
|
" }\n"
|
|
" template float NS2::foo<float>(float);\n"
|
|
"}\n"
|
|
"template double NS1::NS2::foo<double>(double);";
|
|
const char exp[] = "namespace NS1 { "
|
|
"namespace NS2 { "
|
|
"int foo<int> ( int a ) ; "
|
|
"char foo<char> ( char a ) ; "
|
|
"float foo<float> ( float t ) ; "
|
|
"double foo<double> ( double t ) ; "
|
|
"char foo<char> ( char a ) { return a ; } "
|
|
"int foo<int> ( int a ) { return a ; } "
|
|
"} "
|
|
"} "
|
|
"float NS1 :: NS2 :: foo<float> ( float t ) { return t ; } "
|
|
"double NS1 :: NS2 :: foo<double> ( double t ) { return t ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
}
|
|
|
|
void template92() {
|
|
const char code[] = "template<class T> void foo(T const& t) { }\n"
|
|
"template<> void foo<double>(double const& d) { }\n"
|
|
"template void foo<float>(float const& f);\n"
|
|
"int main() {\n"
|
|
" foo<int>(2);\n"
|
|
" foo<double>(3.14);\n"
|
|
" foo<float>(3.14f);\n"
|
|
"}";
|
|
const char exp[] = "void foo<double> ( const double & d ) ; "
|
|
"void foo<float> ( const float & t ) ; "
|
|
"void foo<int> ( const int & t ) ; "
|
|
"void foo<double> ( const double & d ) { } "
|
|
"int main ( ) { "
|
|
"foo<int> ( 2 ) ; "
|
|
"foo<double> ( 3.14 ) ; "
|
|
"foo<float> ( 3.14f ) ; "
|
|
"} "
|
|
"void foo<float> ( const float & t ) { } "
|
|
"void foo<int> ( const int & t ) { }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template93() { // crash
|
|
const char code[] = "template <typename Iterator>\n"
|
|
"void ForEach() { }\n"
|
|
"template <typename Type>\n"
|
|
"class Vector2 : public Vector {\n"
|
|
" template <typename Iterator>\n"
|
|
" void ForEach();\n"
|
|
"public:\n"
|
|
" void process();\n"
|
|
"};\n"
|
|
"template <typename Type>\n"
|
|
"void Vector2<Type>::process() {\n"
|
|
" ForEach<iterator>();\n"
|
|
"}\n"
|
|
"Vector2<string> c;";
|
|
const char exp[] = "void ForEach<iterator> ( ) ; "
|
|
"class Vector2<string> ; "
|
|
"Vector2<string> c ; "
|
|
"class Vector2<string> : public Vector { "
|
|
"template < typename Iterator > "
|
|
"void ForEach ( ) ; "
|
|
"public: "
|
|
"void process ( ) ; "
|
|
"} ; "
|
|
"void Vector2<string> :: process ( ) { "
|
|
"ForEach<iterator> ( ) ; "
|
|
"} "
|
|
"void ForEach<iterator> ( ) { "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template94() { // #8927 crash
|
|
const char code[] = "template <typename T>\n"
|
|
"class Array { };\n"
|
|
"template<typename T>\n"
|
|
"Array<T> foo() {};\n"
|
|
"template <> Array<double> foo<double>() { }\n"
|
|
"template <> Array<std::complex<float>> foo<std::complex<float>>() { }\n"
|
|
"template <> Array<float> foo<float>() { }\n"
|
|
"template < typename T >\n"
|
|
"Array<T> matmul() {\n"
|
|
" return foo<T>( );\n"
|
|
"}\n"
|
|
"template Array<std::complex<float>> matmul<std::complex<float>>();";
|
|
const char exp[] = "class Array<double> ; "
|
|
"class Array<std::complex<float>> ; "
|
|
"class Array<float> ; "
|
|
"Array<float> foo<float> ( ) ; "
|
|
"Array<std::complex<float>> foo<std::complex<float>> ( ) ; "
|
|
"Array<double> foo<double> ( ) ; "
|
|
"template < typename T > "
|
|
"Array < T > foo ( ) { } ; "
|
|
"Array<double> foo<double> ( ) { } "
|
|
"Array<std::complex<float>> foo<std::complex<float>> ( ) { } "
|
|
"Array<float> foo<float> ( ) { } "
|
|
"Array<std::complex<float>> matmul<std::complex<float>> ( ) ; "
|
|
"Array<std::complex<float>> matmul<std::complex<float>> ( ) { "
|
|
"return foo<std::complex<float>> ( ) ; "
|
|
"} "
|
|
"class Array<double> { } ; "
|
|
"class Array<std::complex<float>> { } ; "
|
|
"class Array<float> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template95() { // #7417
|
|
const char code[] = "template <typename T>\n"
|
|
"T Value = 123;\n"
|
|
"template<>\n"
|
|
"int Value<int> = 456;\n"
|
|
"float f = Value<float>;\n"
|
|
"int i = Value<int>;";
|
|
const char exp[] = "float Value<float> ; Value<float> = 123 ; "
|
|
"int Value<int> ; Value<int> = 456 ; "
|
|
"float f ; f = Value<float> ; "
|
|
"int i ; i = Value<int> ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template96() { // #7854
|
|
{
|
|
const char code[] = "template<unsigned int n>\n"
|
|
" constexpr long fib = fib<n-1> + fib<n-2>;\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[] = "const long fib<2> = fib<1> + fib<0> ; "
|
|
"const long fib<3> = fib<2> + fib<1> ; "
|
|
"const long fib<0> = 0 ; "
|
|
"const 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<unsigned int n>\n"
|
|
" constexpr long fib = fib<n-1> + fib<n-2>;\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[] = "const long fib<5> = fib<4> + fib<3> ; "
|
|
"const long fib<4> = fib<3> + fib<2> ; "
|
|
"const long fib<3> = fib<2> + fib<1> ; "
|
|
"const long fib<2> = fib<1> + fib<0> ; "
|
|
"const long fib<0> = 0 ; "
|
|
"const 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<class T>\n"
|
|
" class Fred {\n"
|
|
" T * t;\n"
|
|
" public:\n"
|
|
" Fred<T>() : t(nullptr) {}\n"
|
|
" };\n"
|
|
" }\n"
|
|
" using namespace NS4;\n"
|
|
" Fred<bool> fred_bool;\n"
|
|
" NS4::Fred<char> fred_char;\n"
|
|
" }\n"
|
|
" using namespace NS3;\n"
|
|
" NS4::Fred<short> fred_short;\n"
|
|
" using namespace NS3::NS4;\n"
|
|
" Fred<int> fred_int;\n"
|
|
" NS3::NS4::Fred<long> fred_long;\n"
|
|
" NS2::NS3::NS4::Fred<float> fred_float;\n"
|
|
" NS1::NS2::NS3::NS4::Fred<double> fred_double;\n"
|
|
" }\n"
|
|
" using namespace NS2;\n"
|
|
" NS3::NS4::Fred<float> fred_float1;\n"
|
|
" NS2::NS3::NS4::Fred<double> fred_double1;\n"
|
|
"}\n"
|
|
"using namespace NS1::NS2::NS3::NS4;\n"
|
|
"Fred<bool> fred_bool1;\n"
|
|
"NS1::NS2::NS3::NS4::Fred<int> fred_int1;";
|
|
const char exp[] = "namespace NS1 { "
|
|
"namespace NS2 { "
|
|
"namespace NS3 { "
|
|
"namespace NS4 { "
|
|
"class Fred<bool> ; "
|
|
"class Fred<char> ; "
|
|
"class Fred<short> ; "
|
|
"class Fred<int> ; "
|
|
"class Fred<long> ; "
|
|
"class Fred<float> ; "
|
|
"class Fred<double> ; "
|
|
"} "
|
|
"using namespace NS4 ; "
|
|
"NS4 :: Fred<bool> fred_bool ; "
|
|
"NS4 :: Fred<char> fred_char ; "
|
|
"} "
|
|
"using namespace NS3 ; "
|
|
"NS3 :: NS4 :: Fred<short> fred_short ; "
|
|
"using namespace NS3 :: NS4 ; "
|
|
"NS3 :: NS4 :: Fred<int> fred_int ; "
|
|
"NS3 :: NS4 :: Fred<long> fred_long ; "
|
|
"NS2 :: NS3 :: NS4 :: Fred<float> fred_float ; "
|
|
"NS1 :: NS2 :: NS3 :: NS4 :: Fred<double> fred_double ; "
|
|
"} "
|
|
"using namespace NS2 ; "
|
|
"NS2 :: NS3 :: NS4 :: Fred<float> fred_float1 ; "
|
|
"NS2 :: NS3 :: NS4 :: Fred<double> fred_double1 ; "
|
|
"} "
|
|
"using namespace NS1 :: NS2 :: NS3 :: NS4 ; "
|
|
"NS1 :: NS2 :: NS3 :: NS4 :: Fred<bool> fred_bool1 ; "
|
|
"NS1 :: NS2 :: NS3 :: NS4 :: Fred<int> fred_int1 ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<bool> { "
|
|
"bool * t ; "
|
|
"public: "
|
|
"Fred<bool> ( ) : t ( nullptr ) { } "
|
|
"} ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<char> { "
|
|
"char * t ; "
|
|
"public: "
|
|
"Fred<char> ( ) : t ( nullptr ) { } "
|
|
"} ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<short> { "
|
|
"short * t ; "
|
|
"public: "
|
|
"Fred<short> ( ) : t ( nullptr ) { } "
|
|
"} ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<int> { "
|
|
"int * t ; "
|
|
"public: "
|
|
"Fred<int> ( ) : t ( nullptr ) { } "
|
|
"} ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<long> { "
|
|
"long * t ; "
|
|
"public: "
|
|
"Fred<long> ( ) : t ( nullptr ) { } "
|
|
"} ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<float> { "
|
|
"float * t ; "
|
|
"public: "
|
|
"Fred<float> ( ) : t ( nullptr ) { } "
|
|
"} ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<double> { "
|
|
"double * t ; "
|
|
"public: "
|
|
"Fred<double> ( ) : t ( nullptr ) { } "
|
|
"} ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template98() { // #8959
|
|
const char code[] = "template <typename T>\n"
|
|
"using unique_ptr_with_deleter = std::unique_ptr<T, std::function<void(T*)>>;\n"
|
|
"class A {};\n"
|
|
"static void func() {\n"
|
|
" unique_ptr_with_deleter<A> 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 <typename T>\n"
|
|
"class Base {\n"
|
|
"public:\n"
|
|
" using ArrayType = std::vector<Base<T>>;\n"
|
|
"};\n"
|
|
"using A = Base<int>;\n"
|
|
"static A::ArrayType array;\n";
|
|
const char exp[] = "class Base<int> ; "
|
|
"static std :: vector < Base<int> > array ; "
|
|
"class Base<int> { "
|
|
"public: "
|
|
"} ;";
|
|
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template100() { // #8967
|
|
const char code[] = "enum class Device { I2C0, I2C1 };\n"
|
|
"template <Device D>\n"
|
|
"const char* deviceFile;\n"
|
|
"template <>\n"
|
|
"const char* deviceFile<Device::I2C0> = \"/tmp/i2c-0\";\n";
|
|
|
|
const char exp[] = "enum class Device { I2C0 , I2C1 } ; "
|
|
"template < Device D > "
|
|
"const char * deviceFile ; "
|
|
"const char * deviceFile<Device::I2C0> ; deviceFile<Device::I2C0> = \"/tmp/i2c-0\" ;";
|
|
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template101() { // #8968
|
|
const char code[] = "class A {\n"
|
|
"public:\n"
|
|
" using ArrayType = std::vector<int>;\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 <class T>\n"
|
|
"struct is_floating_point \n"
|
|
": std::integral_constant<bool, std::is_floating_point<T>::value || true>\n"
|
|
"{};\n"
|
|
"}\n"
|
|
"void f() {\n"
|
|
" if(std::is_floating_point<float>::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 <typename T>\n"
|
|
" class Sample {\n"
|
|
" public:\n"
|
|
" T function(T t);\n"
|
|
" };\n"
|
|
" template <typename T>\n"
|
|
" T Sample<T>::function(T t) {\n"
|
|
" return t;\n"
|
|
" }\n"
|
|
"}\n"
|
|
"sample::Sample<int> s1;";
|
|
const char exp[] = "namespace sample { "
|
|
"class Sample<int> ; "
|
|
"} "
|
|
"sample :: Sample<int> s1 ; "
|
|
"class sample :: Sample<int> { "
|
|
"public: "
|
|
"int function ( int t ) ; "
|
|
"} ; "
|
|
"int sample :: Sample<int> :: 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 <template <typename> class TOUT> class ObjectCache;\n"
|
|
"template <template <typename> class TOUT>\n"
|
|
"class ObjectCache { };\n"
|
|
"template <typename T> class Fred {};\n"
|
|
"ObjectCache<Fred> _cache;";
|
|
const char exp[] = "class ObjectCache<Fred> ; "
|
|
"ObjectCache<Fred> _cache ; "
|
|
"class ObjectCache<Fred> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template106() {
|
|
const char code[] = "template<class T, class U> class A {\n"
|
|
"public:\n"
|
|
" int x;\n"
|
|
"};\n"
|
|
"template<template<class T, class U> class V> class B {\n"
|
|
" V<char, char> i;\n"
|
|
"};\n"
|
|
"B<A> c;";
|
|
const char exp[] = "class A<char,char> ; "
|
|
"class B<A> ; "
|
|
"B<A> c ; "
|
|
"class B<A> { "
|
|
"A<char,char> i ; "
|
|
"} ; class A<char,char> { "
|
|
"public: "
|
|
"int x ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template107() { // #8663
|
|
const char code[] = "template <class T1, class T2>\n"
|
|
"void f() {\n"
|
|
" using T3 = typename T1::template T3<T2>;\n"
|
|
" T3 t;\n"
|
|
"}\n"
|
|
"struct C3 {\n"
|
|
" template <typename T>\n"
|
|
" class T3\n"
|
|
" {};\n"
|
|
"};\n"
|
|
"void foo() {\n"
|
|
" f<C3, long>();\n"
|
|
"}";
|
|
const char exp[] = "void f<C3,long> ( ) ; "
|
|
"struct C3 { "
|
|
"class T3<long> ; "
|
|
"} ; "
|
|
"void foo ( ) { "
|
|
"f<C3,long> ( ) ; "
|
|
"} "
|
|
"void f<C3,long> ( ) { "
|
|
"C3 :: T3<long> t ; "
|
|
"} "
|
|
"class C3 :: T3<long> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template108() { // #9109
|
|
{
|
|
const char code[] = "template <typename> struct a;\n"
|
|
"template <typename> struct b {};\n"
|
|
"template <typename> struct c;\n"
|
|
"template <typename d> struct e {\n"
|
|
" using f = a<b<typename c<d>::g>>;\n"
|
|
" bool h = f::h;\n"
|
|
"};\n"
|
|
"struct i {\n"
|
|
" e<int> j();\n"
|
|
"};\n";
|
|
const char exp[] = "template < typename > struct a ; "
|
|
"struct b<c<int>::g> ; "
|
|
"template < typename > struct c ; "
|
|
"struct e<int> ; "
|
|
"struct i { e<int> j ( ) ; "
|
|
"} ; "
|
|
"struct e<int> { bool h ; "
|
|
"h = a < b<c<int>::g> > :: h ; "
|
|
"} ; "
|
|
"struct b<c<int>::g> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "namespace {\n"
|
|
"template <typename> struct a;\n"
|
|
"template <typename> struct b {};\n"
|
|
"}\n"
|
|
"namespace {\n"
|
|
"template <typename> struct c;\n"
|
|
"template <typename d> struct e {\n"
|
|
" using f = a<b<typename c<d>::g>>;\n"
|
|
" bool h = f::h;\n"
|
|
"};\n"
|
|
"template <typename i> using j = typename e<i>::g;\n"
|
|
"}";
|
|
const char exp[] = "namespace { "
|
|
"template < typename > struct a ; "
|
|
"template < typename > struct b { } ; "
|
|
"} "
|
|
"namespace { "
|
|
"template < typename > struct c ; "
|
|
"template < typename d > struct e { "
|
|
"using f = a < b < c < d > :: g > > ; "
|
|
"bool h ; h = f :: h ; "
|
|
"} ; "
|
|
"template < typename i > using j = typename e < i > :: g ; "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "namespace {\n"
|
|
"template <typename> struct a;\n"
|
|
"template <typename> struct b {};\n"
|
|
"}\n"
|
|
"namespace {\n"
|
|
"template <typename> struct c;\n"
|
|
"template <typename d> struct e {\n"
|
|
" using f = a<b<typename c<d>::g>>;\n"
|
|
" bool h = f::h;\n"
|
|
"};\n"
|
|
"template <typename i> using j = typename e<i>::g;\n"
|
|
"}\n"
|
|
"j<int> foo;";
|
|
const char exp[] = "namespace { "
|
|
"template < typename > struct a ; "
|
|
"struct b<c<int>::g> ; "
|
|
"} "
|
|
"namespace { "
|
|
"template < typename > struct c ; "
|
|
"struct e<int> ; "
|
|
"} "
|
|
"e<int> :: g foo ; "
|
|
"struct e<int> { "
|
|
"bool h ; h = a < b<c<int>::g> > :: h ; "
|
|
"} ; "
|
|
"struct b<c<int>::g> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
}
|
|
|
|
void template109() { // #9144
|
|
{
|
|
const char code[] = "namespace a {\n"
|
|
"template <typename b, bool = __is_empty(b) && __is_final(b)> struct c;\n"
|
|
"}\n"
|
|
"template <typename...> struct e {};\n"
|
|
"static_assert(sizeof(e<>) == sizeof(e<c<int>, c<int>, int>), \"\");\n";
|
|
const char exp[] = "namespace a { "
|
|
"template < typename b , bool > struct c ; "
|
|
"} "
|
|
"struct e<> ; "
|
|
"struct e<c<int>,c<int>,int> ; "
|
|
"static_assert ( sizeof ( e<> ) == sizeof ( e<c<int>,c<int>,int> ) , \"\" ) ; "
|
|
"struct e<> { } ; "
|
|
"struct e<c<int>,c<int>,int> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "namespace a {\n"
|
|
"template <typename b, bool = __is_empty(b) && __is_final(b)> struct c;\n"
|
|
"}\n"
|
|
"template <typename...> struct e {};\n"
|
|
"static_assert(sizeof(e<>) == sizeof(e<a::c<int>, a::c<int>, int>), \"\");\n";
|
|
const char exp[] = "namespace a { "
|
|
"template < typename b , bool > struct c ; "
|
|
"} "
|
|
"struct e<> ; "
|
|
"struct e<a::c<int,std::is_empty<int>{}&&std::is_final<int>{}>,a::c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> ; "
|
|
"static_assert ( sizeof ( e<> ) == sizeof ( e<a::c<int,std::is_empty<int>{}&&std::is_final<int>{}>,a::c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> ) , \"\" ) ; "
|
|
"struct e<> { } ; "
|
|
"struct e<a::c<int,std::is_empty<int>{}&&std::is_final<int>{}>,a::c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <typename b, bool = __is_empty(b) && __is_final(b)> struct c;\n"
|
|
"template <typename...> struct e {};\n"
|
|
"static_assert(sizeof(e<>) == sizeof(e<c<int>, c<int>, int>), \"\");\n";
|
|
const char exp[] = "template < typename b , bool > struct c ; "
|
|
"struct e<> ; "
|
|
"struct e<c<int,std::is_empty<int>{}&&std::is_final<int>{}>,c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> ; "
|
|
"static_assert ( sizeof ( e<> ) == sizeof ( e<c<int,std::is_empty<int>{}&&std::is_final<int>{}>,c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> ) , \"\" ) ; "
|
|
"struct e<> { } ; "
|
|
"struct e<c<int,std::is_empty<int>{}&&std::is_final<int>{}>,c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <typename b, bool = __is_empty(b) && __is_final(b)> struct c{};\n"
|
|
"c<int> cc;\n";
|
|
const char exp[] = "struct c<int,std::is_empty<int>{}&&std::is_final<int>{}> ; "
|
|
"c<int,std::is_empty<int>{}&&std::is_final<int>{}> cc ; "
|
|
"struct c<int,std::is_empty<int>{}&&std::is_final<int>{}> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <typename b, bool = unknown1(b) && unknown2(b)> struct c{};\n"
|
|
"c<int> cc;\n";
|
|
const char exp[] = "struct c<int,unknown1(int)&&unknown2(int)> ; "
|
|
"c<int,unknown1(int)&&unknown2(int)> cc ; "
|
|
"struct c<int,unknown1(int)&&unknown2(int)> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
}
|
|
|
|
void template110() {
|
|
const char code[] = "template<typename T> using A = int;\n"
|
|
"template<typename T> using A<T*> = char;\n"
|
|
"template<> using A<char> = char;\n"
|
|
"template using A<char> = char;\n"
|
|
"using A<char> = char;";
|
|
const char exp[] = "template < typename T > using A = int ; "
|
|
"template < typename T > using A < T * > = char ; "
|
|
"template < > using A < char > = char ; "
|
|
"template using A < char > = char ; "
|
|
"using A < char > = char ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template111() { // crash
|
|
const char code[] = "template<typename T, typename U> struct pair;\n"
|
|
"template<typename T> using cell = pair<T*, cell<T>*>;";
|
|
const char exp[] = "template < typename T , typename U > struct pair ; "
|
|
"template < typename T > using cell = pair < T * , cell < T > * > ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template112() { // #9146 syntax error
|
|
const char code[] = "template <int> struct a;\n"
|
|
"template <class, class b> using c = typename a<int{b::d}>::e;\n"
|
|
"template <class> struct f;\n"
|
|
"template <class b> using g = typename f<c<int, b>>::e;";
|
|
const char exp[] = "template < int > struct a ; "
|
|
"template < class , class b > using c = typename a < int { b :: d } > :: e ; "
|
|
"template < class > struct f ; "
|
|
"template < class b > using g = typename f < c < int , b > > :: e ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template113() {
|
|
{
|
|
const char code[] = "template <class> class A { void f(); };\n"
|
|
"A<int> a;";
|
|
const char exp[] = "class A<int> ; "
|
|
"A<int> a ; "
|
|
"class A<int> { void f ( ) ; } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <struct> struct A { void f(); };\n"
|
|
"A<int> a;";
|
|
const char exp[] = "struct A<int> ; "
|
|
"A<int> a ; "
|
|
"struct A<int> { void f ( ) ; } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
}
|
|
|
|
void template114() { // #9155
|
|
{
|
|
const char code[] = "template <typename a, a> struct b {};\n"
|
|
"template <typename> struct c;\n"
|
|
"template <typename> struct d : b<bool, std::is_polymorphic<int>{}> {};\n"
|
|
"template <bool> struct e;\n"
|
|
"template <typename a> using f = typename e<c<d<a>>::g>::h;";
|
|
const char exp[] = "template < typename a , a > struct b { } ; "
|
|
"template < typename > struct c ; "
|
|
"template < typename > struct d : b < bool , std :: is_polymorphic < int > { } > { } ; "
|
|
"template < bool > struct e ; "
|
|
"template < typename a > using f = typename e < c < d < a > > :: g > :: h ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <typename a, a> struct b;\n"
|
|
"template <bool, typename> struct c;\n"
|
|
"template <typename a> struct d : b<bool, std::is_empty<a>{}> {};\n"
|
|
"template <typename a> using e = typename c<std::is_final<a>{}, d<a>>::f;\n";
|
|
const char exp[] = "template < typename a , a > struct b ; "
|
|
"template < bool , typename > struct c ; "
|
|
"template < typename a > struct d : b < bool , std :: is_empty < a > { } > { } ; "
|
|
"template < typename a > using e = typename c < std :: is_final < a > { } , d < a > > :: f ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
}
|
|
|
|
void template115() { // #9153
|
|
const char code[] = "namespace {\n"
|
|
" namespace b {\n"
|
|
" template <int c> struct B { using B<c / 2>::d; };\n"
|
|
" }\n"
|
|
" template <class, class> using e = typename b::B<int{}>;\n"
|
|
" namespace b {\n"
|
|
" template <class> struct f {};\n"
|
|
" }\n"
|
|
" template <class c> using g = b::f<e<int, c>>;\n"
|
|
"}\n"
|
|
"g<int> g1;";
|
|
const char exp[] = "namespace { "
|
|
"namespace b { "
|
|
"struct B<0> ; "
|
|
"} "
|
|
"namespace b { "
|
|
"struct f<b::B<0>> ; "
|
|
"} "
|
|
"} "
|
|
"b :: f<b::B<0>> g1 ; struct b :: B<0> { using B<0> :: d ; } ; "
|
|
"struct b :: f<b::B<0>> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template116() { // #9178
|
|
const char code[] = "template <class, class a> auto b() -> decltype(a{}.template b<void(int, int)>);\n"
|
|
"template <class, class a> auto b() -> decltype(a{}.template b<void(int, int)>){}";
|
|
const char exp[] = "template < class , class a > auto b ( ) . decltype ( a { } . template b < void ( int , int ) > ) ; "
|
|
"template < class , class a > auto b ( ) . decltype ( a { } . template b < void ( int , int ) > ) { }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template117() {
|
|
const char code[] = "template<typename T = void> struct X {};\n"
|
|
"X<X<>> x;";
|
|
const char exp[] = "struct X<void> ; "
|
|
"struct X<X<void>> ; "
|
|
"X<X<void>> x ; "
|
|
"struct X<void> { } ; "
|
|
"struct X<X<void>> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template118() {
|
|
const char code[] = "template<int> struct S { void f(int i); };\n"
|
|
"S<1> s;";
|
|
const char exp[] = "struct S<1> ; "
|
|
"S<1> s ; struct S<1> { "
|
|
"void f ( int i ) ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template119() { // #9186
|
|
{
|
|
const char code[] = "template <typename T>\n"
|
|
"constexpr auto func = [](auto x){ return T(x);};\n"
|
|
"template <typename T>\n"
|
|
"constexpr auto funcBraced = [](auto x){ return T{x};};\n"
|
|
"double f(int x) { return func<double>(x); }\n"
|
|
"double fBraced(int x) { return funcBraced<int>(x); }";
|
|
const char exp[] = "const auto func<double> = [ ] ( auto x ) { return double ( x ) ; } ; "
|
|
"const auto funcBraced<int> = [ ] ( auto x ) { return int { x } ; } ; "
|
|
"double f ( int x ) { return func<double> ( x ) ; } "
|
|
"double fBraced ( int x ) { return funcBraced<int> ( x ) ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <typename T>\n"
|
|
"constexpr auto func = [](auto x){ return T(x);};\n"
|
|
"void foo() {\n"
|
|
" func<int>(x);\n"
|
|
" func<double>(x);\n"
|
|
"}";
|
|
const char exp[] = "const auto func<int> = [ ] ( auto x ) { return int ( x ) ; } ; "
|
|
"const auto func<double> = [ ] ( auto x ) { return double ( x ) ; } ; "
|
|
"void foo ( ) { "
|
|
"func<int> ( x ) ; "
|
|
"func<double> ( x ) ; "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
}
|
|
|
|
void template120() {
|
|
const char code[] = "template<typename Tuple>\n"
|
|
"struct lambda_context {\n"
|
|
" template<typename Sig> struct result;\n"
|
|
" template<typename This, typename I>\n"
|
|
" struct result<This(terminal, placeholder)> : at<Tuple, I> {};\n"
|
|
"};\n"
|
|
"template<typename T>\n"
|
|
"struct lambda {\n"
|
|
" template<typename Sig> struct result;\n"
|
|
" template<typename This>\n"
|
|
" struct result<This()> : lambda_context<tuple<> > {};\n"
|
|
"};\n"
|
|
"lambda<int> l;";
|
|
const char exp[] = "template < typename Tuple > "
|
|
"struct lambda_context { "
|
|
"template < typename Sig > struct result ; "
|
|
"template < typename This , typename I > "
|
|
"struct result < This ( terminal , placeholder ) > : at < Tuple , I > { } ; "
|
|
"} ; "
|
|
"struct lambda<int> ; "
|
|
"lambda<int> l ; struct lambda<int> { "
|
|
"template < typename Sig > struct result ; "
|
|
"template < typename This > "
|
|
"struct result < This ( ) > : lambda_context < tuple < > > { } ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template121() { // #9193
|
|
const char code[] = "template <class VALUE_T, class LIST_T = std::list<VALUE_T>>\n"
|
|
"class TestList { };\n"
|
|
"TestList<std::shared_ptr<int>> m_test;";
|
|
const char exp[] = "class TestList<std::shared_ptr<int>,std::list<std::shared_ptr<int>>> ; "
|
|
"TestList<std::shared_ptr<int>,std::list<std::shared_ptr<int>>> m_test ; "
|
|
"class TestList<std::shared_ptr<int>,std::list<std::shared_ptr<int>>> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template122() { // #9147
|
|
const char code[] = "template <class...> struct a;\n"
|
|
"namespace {\n"
|
|
"template <class, class> struct b;\n"
|
|
"template <template <class> class c, class... f, template <class...> class d>\n"
|
|
"struct b<c<f...>, d<>>;\n"
|
|
"}\n"
|
|
"void e() { using c = a<>; }";
|
|
const char exp[] = "template < class . . . > struct a ; "
|
|
"namespace { "
|
|
"template < class , class > struct b ; "
|
|
"template < template < class > class c , class . . . f , template < class . . . > class d > "
|
|
"struct b < c < f . . . > , d < > > ; "
|
|
"} "
|
|
"void e ( ) { }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template123() { // #9183
|
|
const char code[] = "template <class...> struct a;\n"
|
|
"namespace {\n"
|
|
"template <class, class, class, class>\n"
|
|
"struct b;\n"
|
|
"template <template <class> class c, class... d, template <class> class e, class... f>\n"
|
|
"struct b<c<d...>, e<f...>>;\n"
|
|
"}\n"
|
|
"void fn1() {\n"
|
|
" using c = a<>;\n"
|
|
" using e = a<>;\n"
|
|
"}";
|
|
const char exp[] = "template < class . . . > struct a ; "
|
|
"namespace { "
|
|
"template < class , class , class , class > "
|
|
"struct b ; "
|
|
"template < template < class > class c , class . . . d , template < class > class e , class . . . f > "
|
|
"struct b < c < d . . . > , e < f . . . > > ; "
|
|
"} "
|
|
"void fn1 ( ) { "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template124() { // #9197
|
|
const char code[] = "template <bool> struct a;\n"
|
|
"template <bool b> using c = typename a<b>::d;\n"
|
|
"template <typename> struct e;\n"
|
|
"template <typename> struct h {\n"
|
|
" template <typename... f, c<h<e<typename f::d...>>::g>> void i();\n"
|
|
"};";
|
|
const char exp[] = "template < bool > struct a ; "
|
|
"template < bool b > using c = typename a < b > :: d ; "
|
|
"template < typename > struct e ; "
|
|
"template < typename > struct h { "
|
|
"template < typename . . . f , c < h < e < typename f :: d . . . > > :: g > > void i ( ) ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template125() {
|
|
ASSERT_THROW(tok("template<int M, int N>\n"
|
|
"class GCD {\n"
|
|
"public:\n"
|
|
" enum { val = (N == 0) ? M : GCD<N, M % N>::val };\n"
|
|
"};\n"
|
|
"int main() {\n"
|
|
" GCD< 1, 0 >::val;\n"
|
|
"}"), InternalError);
|
|
}
|
|
|
|
void template126() { // #9217
|
|
const char code[] = "template <typename b> using d = a<b>;\n"
|
|
"static_assert(i<d<l<b>>>{}, \"\");";
|
|
const char exp[] = "static_assert ( i < a < l < b > > > { } , \"\" ) ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
|
const char code[] = "template <typename T> struct C {};\n"
|
|
"template <typename T> struct S {a};\n"
|
|
"template <typename T> struct S<C<T>> {b};\n"
|
|
"S<int> s;";
|
|
const char exp[] = "template < typename T > struct C { } ; struct S<int> ; template < typename T > struct S < C < T > > { b } ; S<int> s ; struct S<int> { a } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template_specialization_2() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
|
const char code[] = "template <typename T> struct C {};\n"
|
|
"template <typename T> struct S {a};\n"
|
|
"template <typename T> struct S<C<T>> {b};\n"
|
|
"S<C<int>> s;";
|
|
const char exp[] = "template < typename T > struct C { } ; template < typename T > struct S { a } ; struct S<C<int>> ; S<C<int>> s ; struct S<C<int>> { b } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template_enum() {
|
|
const char code1[] = "template <class T>\n"
|
|
"struct Unconst {\n"
|
|
" typedef T type;\n"
|
|
"};\n"
|
|
"template <class T>\n"
|
|
"struct Unconst<const T> {\n"
|
|
" typedef T type;\n"
|
|
"};\n"
|
|
"template <class T>\n"
|
|
"struct Unconst<const T&> {\n"
|
|
" typedef T& type;\n"
|
|
"};\n"
|
|
"template <class T>\n"
|
|
"struct Unconst<T* const> {\n"
|
|
" typedef T* type;\n"
|
|
"};\n"
|
|
"template <class T1, class T2>\n"
|
|
"struct type_equal {\n"
|
|
" enum { value = 0 };\n"
|
|
"};\n"
|
|
"template <class T>\n"
|
|
"struct type_equal<T, T> {\n"
|
|
" enum { value = 1 };\n"
|
|
"};\n"
|
|
"template<class T>\n"
|
|
"struct template_is_const\n"
|
|
"{\n"
|
|
" enum {value = !type_equal<T, typename Unconst<T>::type>::value };\n"
|
|
"};";
|
|
const char exp1[] = "template < class T > struct Unconst { } ; "
|
|
"template < class T > struct Unconst < const T > { } ; "
|
|
"template < class T > struct Unconst < const T & > { } ; "
|
|
"template < class T > struct Unconst < T * const > { } ; "
|
|
"template < class T1 , class T2 > struct type_equal { enum Anonymous0 { value = 0 } ; } ; "
|
|
"template < class T > struct type_equal < T , T > { enum Anonymous1 { value = 1 } ; } ;";
|
|
ASSERT_EQUALS(exp1, tok(code1));
|
|
}
|
|
|
|
void template_default_parameter() {
|
|
{
|
|
const char code[] = "template <class T, int n=3>\n"
|
|
"class A\n"
|
|
"{ T ar[n]; };\n"
|
|
"\n"
|
|
"void f()\n"
|
|
"{\n"
|
|
" A<int,2> a1;\n"
|
|
" A<int> a2;\n"
|
|
"}\n";
|
|
const char expected[] = "class A<int,2> ; "
|
|
"class A<int,3> ; "
|
|
"void f ( ) "
|
|
"{"
|
|
" A<int,2> a1 ;"
|
|
" A<int,3> a2 ; "
|
|
"} "
|
|
"class A<int,2> "
|
|
"{ int ar [ 2 ] ; } ; "
|
|
"class A<int,3> "
|
|
"{ int ar [ 3 ] ; } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <class T, int n1=3, int n2=2>\n"
|
|
"class A\n"
|
|
"{ T ar[n1+n2]; };\n"
|
|
"\n"
|
|
"void f()\n"
|
|
"{\n"
|
|
" A<int> a1;\n"
|
|
" A<int,3> a2;\n"
|
|
"}\n";
|
|
|
|
const char expected[] = "class A<int,3,2> ; "
|
|
"void f ( ) "
|
|
"{"
|
|
" A<int,3,2> a1 ;"
|
|
" A<int,3,2> a2 ; "
|
|
"} "
|
|
"class A<int,3,2> "
|
|
"{ int ar [ 3 + 2 ] ; } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <class T, int n=3>\n"
|
|
"class A\n"
|
|
"{ T ar[n]; };\n"
|
|
"\n"
|
|
"void f()\n"
|
|
"{\n"
|
|
" A<int,(int)2> a1;\n"
|
|
" A<int> a2;\n"
|
|
"}\n";
|
|
const char expected[] = "class A<int,(int)2> ; "
|
|
"class A<int,3> ; "
|
|
"void f ( ) "
|
|
"{ "
|
|
"A<int,(int)2> a1 ; "
|
|
"A<int,3> a2 ; "
|
|
"} "
|
|
"class A<int,(int)2> "
|
|
"{ int ar [ ( int ) 2 ] ; } ; "
|
|
"class A<int,3> "
|
|
"{ int ar [ 3 ] ; } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "class A { }; "
|
|
"template<class T> class B { }; "
|
|
"template<class T1, class T2 = B<T1>> class C { }; "
|
|
"template<class T1 = A, typename T2 = B<A>> class D { };";
|
|
ASSERT_EQUALS("class A { } ; "
|
|
"template < class T > class B { } ; "
|
|
"template < class T1 , class T2 = B < T1 > > class C { } ; "
|
|
"template < class T1 = A , typename T2 = B < A > > class D { } ;", tok(code));
|
|
}
|
|
{
|
|
// #7548
|
|
const char code[] = "template<class T, class U> class DefaultMemory {}; "
|
|
"template<class Key, class Val, class Mem=DefaultMemory<Key,Val> > class thv_table_c {}; "
|
|
"thv_table_c<void *,void *> id_table_m;";
|
|
const char exp [] = "template < class T , class U > class DefaultMemory { } ; "
|
|
"class thv_table_c<void*,void*,DefaultMemory<void*,void*>> ; "
|
|
"thv_table_c<void*,void*,DefaultMemory<void*,void*>> id_table_m ; "
|
|
"class thv_table_c<void*,void*,DefaultMemory<void*,void*>> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
// #8890
|
|
const char code[] = "template <typename = void> struct a {\n"
|
|
" void c();\n"
|
|
"};\n"
|
|
"void f() {\n"
|
|
" a<> b;\n"
|
|
" b.a<>::c();\n"
|
|
"}";
|
|
ASSERT_EQUALS("struct a<void> ; "
|
|
"void f ( ) { "
|
|
"a<void> b ; "
|
|
"b . a<void> :: c ( ) ; "
|
|
"} "
|
|
"struct a<void> { "
|
|
"void c ( ) ; "
|
|
"} ;", tok(code));
|
|
}
|
|
{
|
|
// #8890
|
|
const char code[] = "template< typename T0 = void > class A;\n"
|
|
"template<>\n"
|
|
"class A< void > {\n"
|
|
" public:\n"
|
|
" A() { }\n"
|
|
" ~A() { }\n"
|
|
" void Print() { std::cout << \"A\" << std::endl; }\n"
|
|
"};\n"
|
|
"class B : public A<> {\n"
|
|
" public:\n"
|
|
" B() { }\n"
|
|
" ~B() { }\n"
|
|
"};\n"
|
|
"int main( int argc, char* argv[] ) {\n"
|
|
" B b;\n"
|
|
" b.A<>::Print();\n"
|
|
" return 0;\n"
|
|
"}";
|
|
ASSERT_EQUALS("class A<void> ; "
|
|
"template < typename T0 > class A ; "
|
|
"class A<void> { "
|
|
"public: "
|
|
"A<void> ( ) { } "
|
|
"~ A<void> ( ) { } "
|
|
"void Print ( ) { std :: cout << \"A\" << std :: endl ; } "
|
|
"} ; "
|
|
"class B : public A<void> { "
|
|
"public: "
|
|
"B ( ) { } "
|
|
"~ B ( ) { } "
|
|
"} ; "
|
|
"int main ( int argc , char * argv [ ] ) { "
|
|
"B b ; "
|
|
"b . A<void> :: Print ( ) ; "
|
|
"return 0 ; "
|
|
"}", tok(code));
|
|
}
|
|
}
|
|
|
|
void template_forward_declared_default_parameter() {
|
|
{
|
|
const char code[] = "template <class T, int n=3> class A;\n"
|
|
"template <class T, int n>\n"
|
|
"class A\n"
|
|
"{ T ar[n]; };\n"
|
|
"\n"
|
|
"void f()\n"
|
|
"{\n"
|
|
" A<int,2> a1;\n"
|
|
" A<int> a2;\n"
|
|
"}\n";
|
|
|
|
const char exp[] = "class A<int,2> ; "
|
|
"class A<int,3> ; "
|
|
"void f ( ) "
|
|
"{"
|
|
" A<int,2> a1 ;"
|
|
" A<int,3> a2 ; "
|
|
"} "
|
|
"class A<int,2> "
|
|
"{ int ar [ 2 ] ; } ; "
|
|
"class A<int,3> "
|
|
"{ int ar [ 3 ] ; } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <class, int = 3> class A;\n"
|
|
"template <class T, int n>\n"
|
|
"class A\n"
|
|
"{ T ar[n]; };\n"
|
|
"\n"
|
|
"void f()\n"
|
|
"{\n"
|
|
" A<int,2> a1;\n"
|
|
" A<int> a2;\n"
|
|
"}\n";
|
|
|
|
const char exp[] = "class A<int,2> ; "
|
|
"class A<int,3> ; "
|
|
"void f ( ) "
|
|
"{"
|
|
" A<int,2> a1 ;"
|
|
" A<int,3> a2 ; "
|
|
"} "
|
|
"class A<int,2> "
|
|
"{ int ar [ 2 ] ; } ; "
|
|
"class A<int,3> "
|
|
"{ int ar [ 3 ] ; } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<typename Lhs, int TriangularPart = (int(Lhs::Flags) & LowerTriangularBit)>\n"
|
|
"struct ei_solve_triangular_selector;\n"
|
|
"template<typename Lhs, int UpLo>\n"
|
|
"struct ei_solve_triangular_selector<Lhs,UpLo> {\n"
|
|
"};\n"
|
|
"template<typename Lhs, int TriangularPart>\n"
|
|
"struct ei_solve_triangular_selector { };";
|
|
|
|
const char exp[] = "template < typename Lhs , int TriangularPart = ( int ( Lhs :: Flags ) & LowerTriangularBit ) > "
|
|
"struct ei_solve_triangular_selector ; "
|
|
"template < typename Lhs , int UpLo > "
|
|
"struct ei_solve_triangular_selector < Lhs , UpLo > { "
|
|
"} ; "
|
|
"template < typename Lhs , int TriangularPart = ( int ( Lhs :: Flags ) & LowerTriangularBit ) > "
|
|
"struct ei_solve_triangular_selector { } ;";
|
|
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
}
|
|
|
|
void template_default_type() {
|
|
const char code[] = "template <typename T, typename U=T>\n"
|
|
"class A\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" void foo() {\n"
|
|
" int a;\n"
|
|
" a = static_cast<U>(a);\n"
|
|
" }\n"
|
|
"};\n"
|
|
"\n"
|
|
"template <typename T>\n"
|
|
"class B\n"
|
|
"{\n"
|
|
"protected:\n"
|
|
" A<int> a;\n"
|
|
"};\n"
|
|
"\n"
|
|
"class C\n"
|
|
" : public B<int>\n"
|
|
"{\n"
|
|
"};\n";
|
|
|
|
tok(code);
|
|
|
|
//ASSERT_EQUALS("[file1.cpp:15]: (error) Internal error: failed to instantiate template. The checking continues anyway.\n", errout.str());
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template_typename() {
|
|
{
|
|
const char code[] = "template <class T>\n"
|
|
"void foo(typename T::t *)\n"
|
|
"{ }";
|
|
|
|
// The expected result..
|
|
const char expected[] = "template < class T > void foo ( T :: t * ) { }";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
{
|
|
const char code[] = "void f() {\n"
|
|
" x(sizeof typename);\n"
|
|
" type = 0;\n"
|
|
"}";
|
|
|
|
ASSERT_EQUALS("void f ( ) { x ( sizeof ( typename ) ) ; type = 0 ; }", tok(code));
|
|
}
|
|
}
|
|
|
|
void template_constructor() {
|
|
// #3152 - if template constructor is removed then there might be
|
|
// "no constructor" false positives
|
|
const char code[] = "class Fred {\n"
|
|
" template<class T> explicit Fred(T t) { }\n"
|
|
"}";
|
|
ASSERT_EQUALS("class Fred { }", tok(code));
|
|
|
|
// #3532
|
|
const char code2[] = "class Fred {\n"
|
|
" template<class T> Fred(T t) { }\n"
|
|
"}";
|
|
ASSERT_EQUALS("class Fred { template < class T > Fred ( T t ) { } }", tok(code2));
|
|
}
|
|
|
|
void syntax_error_templates_1() {
|
|
// ok code.. using ">" for a comparison
|
|
tok("x<y>z> xyz;\n");
|
|
ASSERT_EQUALS("", errout.str());
|
|
|
|
// ok code
|
|
tok("template<class T> operator<(T a, T b) { }\n");
|
|
ASSERT_EQUALS("", errout.str());
|
|
|
|
// ok code (ticket #1984)
|
|
tok("void f(a) int a;\n"
|
|
"{ ;x<y; }");
|
|
ASSERT_EQUALS("", errout.str());
|
|
|
|
// ok code (ticket #1985)
|
|
tok("void f()\n"
|
|
"try { ;x<y; }");
|
|
ASSERT_EQUALS("", errout.str());
|
|
|
|
// ok code (ticket #3183)
|
|
tok("MACRO(({ i < x }))");
|
|
ASSERT_EQUALS("", errout.str());
|
|
|
|
// bad code.. missing ">"
|
|
ASSERT_THROW(tok("x<y<int> xyz;\n"), InternalError);
|
|
|
|
// bad code
|
|
ASSERT_THROW(tok("typedef\n"
|
|
" typename boost::mpl::if_c<\n"
|
|
" _visitableIndex < boost::mpl::size< typename _Visitables::ConcreteVisitables >::value\n"
|
|
" , ConcreteVisitable\n"
|
|
" , Dummy< _visitableIndex >\n"
|
|
" >::type ConcreteVisitableOrDummy;\n"), InternalError);
|
|
|
|
// code is ok, don't show syntax error
|
|
tok("struct A {int a;int b};\n"
|
|
"class Fred {"
|
|
"public:\n"
|
|
" Fred() : a({1,2}) {\n"
|
|
" for (int i=0;i<6;i++);\n" // <- no syntax error
|
|
" }\n"
|
|
"private:\n"
|
|
" A a;\n"
|
|
"};\n");
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template_member_ptr() { // Ticket #5786
|
|
tok("struct A {}; "
|
|
"struct B { "
|
|
"template <void (A::*)() const> struct BB {}; "
|
|
"template <bool BT> static bool foo(int) { return true; } "
|
|
"void bar() { bool b = foo<true>(0); }"
|
|
"};");
|
|
tok("struct A {}; "
|
|
"struct B { "
|
|
"template <void (A::*)() volatile> struct BB {}; "
|
|
"template <bool BT> static bool foo(int) { return true; } "
|
|
"void bar() { bool b = foo<true>(0); }"
|
|
"};");
|
|
tok("struct A {}; "
|
|
"struct B { "
|
|
"template <void (A::*)() const volatile> struct BB {}; "
|
|
"template <bool BT> static bool foo(int) { return true; } "
|
|
"void bar() { bool b = foo<true>(0); }"
|
|
"};");
|
|
tok("struct A {}; "
|
|
"struct B { "
|
|
"template <void (A::*)() volatile const> struct BB {}; "
|
|
"template <bool BT> static bool foo(int) { return true; } "
|
|
"void bar() { bool b = foo<true>(0); }"
|
|
"};");
|
|
}
|
|
|
|
void template_namespace_1() {
|
|
// #6570
|
|
const char code[] = "namespace {\n"
|
|
" template<class T> void Fred(T value) { }\n"
|
|
"}\n"
|
|
"Fred<int>(123);";
|
|
ASSERT_EQUALS("namespace { "
|
|
"void Fred<int> ( int value ) ; "
|
|
"} "
|
|
"Fred<int> ( 123 ) ; "
|
|
"void Fred<int> ( int value ) { }", tok(code));
|
|
}
|
|
|
|
void template_namespace_2() {
|
|
// #8283
|
|
const char code[] = "namespace X {\n"
|
|
" template<class T> struct S { };\n"
|
|
"}\n"
|
|
"X::S<int> s;";
|
|
ASSERT_EQUALS("namespace X { "
|
|
"struct S<int> ; "
|
|
"} "
|
|
"X :: S<int> s ; "
|
|
"struct X :: S<int> { } ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_3() {
|
|
const char code[] = "namespace test16 {\n"
|
|
" template <class T> struct foo {\n"
|
|
" static void *bar();\n"
|
|
" };\n"
|
|
" void *test() { return foo<int>::bar(); }\n"
|
|
"}";
|
|
ASSERT_EQUALS("namespace test16 {"
|
|
" struct foo<int> ;"
|
|
" void * test ( ) {"
|
|
" return foo<int> :: bar ( ) ;"
|
|
" } "
|
|
"} "
|
|
"struct test16 :: foo<int> {"
|
|
" static void * bar ( ) ; "
|
|
"} ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_4() {
|
|
const char code[] = "namespace foo {\n"
|
|
" template<class T> class A { void dostuff() {} };\n"
|
|
" struct S : public A<int> {\n"
|
|
" void f() {\n"
|
|
" A<int>::dostuff();\n"
|
|
" }\n"
|
|
" };\n"
|
|
"}";
|
|
ASSERT_EQUALS("namespace foo {"
|
|
" class A<int> ;"
|
|
" struct S : public A<int> {"
|
|
" void f ( ) {"
|
|
" A<int> :: dostuff ( ) ;"
|
|
" }"
|
|
" } ; "
|
|
"} "
|
|
"class foo :: A<int> { void dostuff ( ) { } } ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_5() {
|
|
const char code[] = "template<class C> struct S {};\n"
|
|
"namespace X { S<int> s; }";
|
|
ASSERT_EQUALS("struct S<int> ; "
|
|
"namespace X { S<int> s ; } "
|
|
"struct S<int> { } ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_6() {
|
|
const char code[] = "namespace NS {\n"
|
|
"template <typename T> union C {\n"
|
|
" char dummy[sizeof(T)];\n"
|
|
" T value;\n"
|
|
" C();\n"
|
|
" ~C();\n"
|
|
" C(const C &);\n"
|
|
" C & operator = (const C &);\n"
|
|
"};\n"
|
|
"}\n"
|
|
"NS::C<int> intC;\n"
|
|
"template <typename T> NS::C<T>::C() {}\n"
|
|
"template <typename T> NS::C<T>::~C() {}\n"
|
|
"template <typename T> NS::C<T>::C(const NS::C<T> &) {}\n"
|
|
"template <typename T> NS::C<T> & NS::C<T>::operator=(const NS::C<T> &) {}";
|
|
ASSERT_EQUALS("namespace NS { "
|
|
"union C<int> ; "
|
|
"} "
|
|
"NS :: C<int> intC ; union NS :: C<int> { "
|
|
"char dummy [ sizeof ( int ) ] ; "
|
|
"int value ; "
|
|
"C<int> ( ) ; "
|
|
"~ C<int> ( ) ; "
|
|
"C<int> ( const NS :: C<int> & ) ; "
|
|
"NS :: C<int> & operator= ( const NS :: C<int> & ) ; "
|
|
"} ; "
|
|
"NS :: C<int> :: C<int> ( ) { } "
|
|
"NS :: C<int> :: ~ C<int> ( ) { } "
|
|
"NS :: C<int> :: C<int> ( const NS :: C<int> & ) { } "
|
|
"NS :: C<int> & NS :: C<int> :: operator= ( const NS :: C<int> & ) { }", tok(code));
|
|
}
|
|
|
|
void template_namespace_7() { // #8768
|
|
const char code[] = "namespace N1 {\n"
|
|
"namespace N2 {\n"
|
|
" struct C { };\n"
|
|
" template <class T> struct CT { };\n"
|
|
" C c1;\n"
|
|
" CT<int> ct1;\n"
|
|
"}\n"
|
|
"N2::C c2;\n"
|
|
"N2::CT<int> ct2;\n"
|
|
"}\n"
|
|
"N1::N2::C c3;\n"
|
|
"N1::N2::CT<int> ct3;";
|
|
ASSERT_EQUALS("namespace N1 { "
|
|
"namespace N2 { "
|
|
"struct C { } ; "
|
|
"struct CT<int> ; "
|
|
"C c1 ; "
|
|
"CT<int> ct1 ; "
|
|
"} "
|
|
"N2 :: C c2 ; "
|
|
"N2 :: CT<int> ct2 ; "
|
|
"} "
|
|
"N1 :: N2 :: C c3 ; "
|
|
"N1 :: N2 :: CT<int> ct3 ; struct N1 :: N2 :: CT<int> { } ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_8() { // #8768
|
|
const char code[] = "namespace NS1 {\n"
|
|
"namespace NS2 {\n"
|
|
" template <typename T>\n"
|
|
" struct Fred {\n"
|
|
" Fred();\n"
|
|
" Fred(const Fred &);\n"
|
|
" Fred & operator = (const Fred &);\n"
|
|
" ~Fred();\n"
|
|
" };\n"
|
|
" template <typename T>\n"
|
|
" Fred<T>::Fred() { }\n"
|
|
" template <typename T>\n"
|
|
" Fred<T>::Fred(const Fred<T> & f) { }\n"
|
|
" template <typename T>\n"
|
|
" Fred<T> & Fred<T>::operator = (const Fred<T> & f) { }\n"
|
|
" template <typename T>\n"
|
|
" Fred<T>::~Fred() { }\n"
|
|
"}\n"
|
|
"}\n"
|
|
"NS1::NS2::Fred<int> fred;";
|
|
ASSERT_EQUALS("namespace NS1 { "
|
|
"namespace NS2 { "
|
|
"struct Fred<int> ; "
|
|
"} "
|
|
"} "
|
|
"NS1 :: NS2 :: Fred<int> fred ; struct NS1 :: NS2 :: Fred<int> { "
|
|
"Fred<int> ( ) ; "
|
|
"Fred<int> ( const NS1 :: NS2 :: Fred<int> & ) ; "
|
|
"NS1 :: NS2 :: Fred<int> & operator= ( const NS1 :: NS2 :: Fred<int> & ) ; "
|
|
"~ Fred<int> ( ) ; "
|
|
"} ; "
|
|
"NS1 :: NS2 :: Fred<int> :: Fred<int> ( ) { } "
|
|
"NS1 :: NS2 :: Fred<int> :: Fred<int> ( const NS1 :: NS2 :: Fred<int> & f ) { } "
|
|
"NS1 :: NS2 :: Fred<int> & NS1 :: NS2 :: Fred<int> :: operator= ( const NS1 :: NS2 :: Fred<int> & f ) { } "
|
|
"NS1 :: NS2 :: Fred<int> :: ~ Fred<int> ( ) { }", tok(code));
|
|
}
|
|
|
|
void template_namespace_9() {
|
|
const char code[] = "namespace NS {\n"
|
|
"template<int type> struct Barney;\n"
|
|
"template<> struct Barney<1> { };\n"
|
|
"template<int type>\n"
|
|
"class Fred {\n"
|
|
"public:\n"
|
|
" Fred();\n"
|
|
"private:\n"
|
|
" Barney<type> m_data;\n"
|
|
"};\n"
|
|
"template class Fred<1>;\n"
|
|
"}\n";
|
|
ASSERT_EQUALS("namespace NS { "
|
|
"struct Barney<1> ; "
|
|
"template < int type > struct Barney ; "
|
|
"struct Barney<1> { } ; "
|
|
"class Fred<1> ; "
|
|
"} "
|
|
"class NS :: Fred<1> { "
|
|
"public: "
|
|
"Fred<1> ( ) ; "
|
|
"private: "
|
|
"Barney<1> m_data ; "
|
|
"} ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_10() {
|
|
const char code[] = "namespace NS1 {\n"
|
|
"namespace NS2 {\n"
|
|
"template<class T>\n"
|
|
"class Fred {\n"
|
|
" T * t;\n"
|
|
"public:\n"
|
|
" Fred<T>() : t(nullptr) {}\n"
|
|
"};\n"
|
|
"}\n"
|
|
"}\n"
|
|
"NS1::NS2::Fred<int> fred;";
|
|
ASSERT_EQUALS("namespace NS1 { "
|
|
"namespace NS2 { "
|
|
"class Fred<int> ; "
|
|
"} "
|
|
"} "
|
|
"NS1 :: NS2 :: Fred<int> fred ; class NS1 :: NS2 :: Fred<int> "
|
|
"{ "
|
|
"int * t ; "
|
|
"public: "
|
|
"Fred<int> ( ) : t ( nullptr ) { } "
|
|
"} ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_11() {// #7145
|
|
const char code[] = "namespace MyNamespace {\n"
|
|
"class TestClass {\n"
|
|
"public:\n"
|
|
" TestClass() {\n"
|
|
" SomeFunction();\n"
|
|
" TemplatedMethod< int >( 0 );\n"
|
|
" }\n"
|
|
" void SomeFunction() { }\n"
|
|
"private:\n"
|
|
" template< typename T > T TemplatedMethod(T);\n"
|
|
"};\n"
|
|
"template< typename T > T TestClass::TemplatedMethod(T t) { return t; }\n"
|
|
"}";
|
|
ASSERT_EQUALS("namespace MyNamespace { "
|
|
"class TestClass { "
|
|
"public: "
|
|
"TestClass ( ) { "
|
|
"SomeFunction ( ) ; "
|
|
"TemplatedMethod<int> ( 0 ) ; "
|
|
"} "
|
|
"void SomeFunction ( ) { } "
|
|
"private: "
|
|
"int TemplatedMethod<int> ( int ) ; "
|
|
"} ; "
|
|
"} int MyNamespace :: TestClass :: TemplatedMethod<int> ( int t ) { return t ; }", tok(code));
|
|
}
|
|
|
|
unsigned int templateParameters(const char code[]) {
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
tokenizer.createTokens(istr, "test.cpp");
|
|
tokenizer.createLinks();
|
|
tokenizer.mTemplateSimplifier->fixAngleBrackets();
|
|
|
|
for (const Token *tok1 = tokenizer.tokens(); tok1; tok1 = tok1->next()) {
|
|
if (tok1->str() == "var1")
|
|
(const_cast<Token *>(tok1))->varId(1);
|
|
}
|
|
|
|
return TemplateSimplifier::templateParameters(tokenizer.tokens()->next());
|
|
}
|
|
|
|
void templateParameters() {
|
|
// Test that the function TemplateSimplifier::templateParameters works
|
|
ASSERT_EQUALS(1U, templateParameters("X<struct C> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("X<union C> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("X<const int> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("X<int const *> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("X<const struct C> x;"));
|
|
ASSERT_EQUALS(0U, templateParameters("X<len>>x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("X<typename> x;"));
|
|
ASSERT_EQUALS(0U, templateParameters("X<...> x;"));
|
|
ASSERT_EQUALS(0U, templateParameters("X<class T...> x;")); // Invalid syntax
|
|
ASSERT_EQUALS(1U, templateParameters("X<class... T> x;"));
|
|
ASSERT_EQUALS(0U, templateParameters("X<class, typename T...> x;")); // Invalid syntax
|
|
ASSERT_EQUALS(2U, templateParameters("X<class, typename... T> x;"));
|
|
ASSERT_EQUALS(2U, templateParameters("X<int(&)(), class> x;"));
|
|
ASSERT_EQUALS(3U, templateParameters("X<char, int(*)(), bool> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("X<int...> x;"));
|
|
ASSERT_EQUALS(2U, templateParameters("X<class, typename...> x;"));
|
|
ASSERT_EQUALS(2U, templateParameters("X<1, T> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("X<i == 0> x;"));
|
|
ASSERT_EQUALS(2U, templateParameters("X<int, i>=0> x;"));
|
|
ASSERT_EQUALS(3U, templateParameters("X<int, i>=0, i - 2> x;"));
|
|
ASSERT_EQUALS(0U, templateParameters("var1<1> x;"));
|
|
ASSERT_EQUALS(0U, templateParameters("X<1>2;"));
|
|
ASSERT_EQUALS(2U, templateParameters("template<typename...B,typename=SameSize<B...>> x;"));
|
|
ASSERT_EQUALS(2U, templateParameters("template<typename...B,typename=SameSize<B...> > x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("template<template<typename>...Foo> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("template<template<typename>> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("template<template<template<typename>>> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("template<template<template<template<typename>>>> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("template<template<template<template<template<typename>>>>> x;"));
|
|
ASSERT_EQUALS(2U, templateParameters("template<template<typename>,int> x;"));
|
|
ASSERT_EQUALS(2U, templateParameters("template<template<template<typename>>,int> x;"));
|
|
ASSERT_EQUALS(2U, templateParameters("template<template<template<template<typename>>>,int> x;"));
|
|
ASSERT_EQUALS(2U, templateParameters("template<template<template<template<template<typename>>>>,int> x;"));
|
|
ASSERT_EQUALS(2U, templateParameters("template<template<typename>...Foo,template<template<template<typename>>>> x;"));
|
|
ASSERT_EQUALS(3U, templateParameters("template<template<typename>...Foo,int,template<template<template<typename>>>> x;"));
|
|
ASSERT_EQUALS(4U, templateParameters("template<template<typename>...Foo,int,template<template<template<typename>>>,int> x;"));
|
|
}
|
|
|
|
// Helper function to unit test TemplateSimplifier::getTemplateNamePosition
|
|
int templateNamePositionHelper(const char code[], unsigned offset = 0) {
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
tokenizer.createTokens(istr, "test.cpp");
|
|
tokenizer.createLinks();
|
|
tokenizer.mTemplateSimplifier->fixAngleBrackets();
|
|
|
|
const Token *_tok = tokenizer.tokens();
|
|
for (unsigned i = 0 ; i < offset ; ++i)
|
|
_tok = _tok->next();
|
|
return tokenizer.mTemplateSimplifier->getTemplateNamePosition(_tok);
|
|
}
|
|
|
|
void templateNamePosition() {
|
|
// Template class
|
|
ASSERT_EQUALS(2, templateNamePositionHelper("template<class T> class A {};", 4));
|
|
ASSERT_EQUALS(2, templateNamePositionHelper("template<class T> struct A {};", 4));
|
|
ASSERT_EQUALS(2, templateNamePositionHelper("template<class T> class A : B {};", 4));
|
|
ASSERT_EQUALS(2, templateNamePositionHelper("template<class T> struct A : B {};", 4));
|
|
// Template function definitions
|
|
ASSERT_EQUALS(2, templateNamePositionHelper("template<class T> unsigned foo() { return 0; }", 4));
|
|
ASSERT_EQUALS(3, templateNamePositionHelper("template<class T> unsigned* foo() { return 0; }", 4));
|
|
ASSERT_EQUALS(4, templateNamePositionHelper("template<class T> unsigned** foo() { return 0; }", 4));
|
|
|
|
ASSERT_EQUALS(3, templateNamePositionHelper("template<class T> const unsigned foo() { return 0; }", 4));
|
|
ASSERT_EQUALS(4, templateNamePositionHelper("template<class T> const unsigned& foo() { return 0; }", 4));
|
|
ASSERT_EQUALS(5, templateNamePositionHelper("template<class T> const unsigned** foo() { return 0; }", 4));
|
|
|
|
ASSERT_EQUALS(4, templateNamePositionHelper("template<class T> std::string foo() { static str::string str; return str; }", 4));
|
|
ASSERT_EQUALS(5, templateNamePositionHelper("template<class T> std::string & foo() { static str::string str; return str; }", 4));
|
|
ASSERT_EQUALS(6, templateNamePositionHelper("template<class T> const std::string & foo() { static str::string str; return str; }", 4));
|
|
|
|
ASSERT_EQUALS(9, templateNamePositionHelper("template<class T> std::map<int, int> foo() { static std::map<int, int> m; return m; }", 4));
|
|
ASSERT_EQUALS(10, templateNamePositionHelper("template<class T> std::map<int, int> & foo() { static std::map<int, int> m; return m; }", 4));
|
|
ASSERT_EQUALS(11, templateNamePositionHelper("template<class T> const std::map<int, int> & foo() { static std::map<int, int> m; return m; }", 4));
|
|
// Class template members
|
|
ASSERT_EQUALS(4, templateNamePositionHelper(
|
|
"class A { template<class T> unsigned foo(); }; "
|
|
"template<class T> unsigned A::foo() { return 0; }", 19));
|
|
ASSERT_EQUALS(5, templateNamePositionHelper(
|
|
"class A { template<class T> const unsigned foo(); }; "
|
|
"template<class T> const unsigned A::foo() { return 0; }", 20));
|
|
ASSERT_EQUALS(7, templateNamePositionHelper(
|
|
"class A { class B { template<class T> const unsigned foo(); }; } ; "
|
|
"template<class T> const unsigned A::B::foo() { return 0; }", 25));
|
|
ASSERT_EQUALS(8, templateNamePositionHelper(
|
|
"class A { class B { template<class T> const unsigned * foo(); }; } ; "
|
|
"template<class T> const unsigned * A::B::foo() { return 0; }", 26));
|
|
ASSERT_EQUALS(9, templateNamePositionHelper(
|
|
"class A { class B { template<class T> const unsigned ** foo(); }; } ; "
|
|
"template<class T> const unsigned ** A::B::foo() { return 0; }", 27));
|
|
// Template class member
|
|
ASSERT_EQUALS(6, templateNamePositionHelper(
|
|
"template<class T> class A { A(); }; "
|
|
"template<class T> A<T>::A() {}", 18));
|
|
ASSERT_EQUALS(8, templateNamePositionHelper(
|
|
"template<class T, class U> class A { A(); }; "
|
|
"template<class T, class U> A<T, U>::A() {}", 24));
|
|
ASSERT_EQUALS(7, templateNamePositionHelper(
|
|
"template<class T> class A { unsigned foo(); }; "
|
|
"template<class T> unsigned A<T>::foo() { return 0; }", 19));
|
|
ASSERT_EQUALS(9, templateNamePositionHelper(
|
|
"template<class T, class U> class A { unsigned foo(); }; "
|
|
"template<class T, class U> unsigned A<T, U>::foo() { return 0; }", 25));
|
|
ASSERT_EQUALS(12, templateNamePositionHelper(
|
|
"template<> unsigned A<int, v<char> >::foo() { return 0; }", 2));
|
|
}
|
|
|
|
// Helper function to unit test TemplateSimplifier::findTemplateDeclarationEnd
|
|
bool findTemplateDeclarationEndHelper(const char code[], const char pattern[], unsigned offset = 0) {
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
tokenizer.createTokens(istr, "test.cpp");
|
|
tokenizer.createLinks();
|
|
tokenizer.mTemplateSimplifier->fixAngleBrackets();
|
|
|
|
const Token *_tok = tokenizer.tokens();
|
|
for (unsigned i = 0 ; i < offset ; ++i)
|
|
_tok = _tok->next();
|
|
|
|
const Token *tok1 = tokenizer.mTemplateSimplifier->findTemplateDeclarationEnd(_tok);
|
|
|
|
return (tok1 == Token::findsimplematch(tokenizer.list.front(), pattern));
|
|
}
|
|
|
|
void findTemplateDeclarationEnd() {
|
|
ASSERT(findTemplateDeclarationEndHelper("template <typename T> class Fred { }; int x;", "; int x ;"));
|
|
ASSERT(findTemplateDeclarationEndHelper("template <typename T> void Fred() { } int x;", "} int x ;"));
|
|
ASSERT(findTemplateDeclarationEndHelper("template <typename T> int Fred = 0; int x;", "; int x ;"));
|
|
ASSERT(findTemplateDeclarationEndHelper("template <typename T> constexpr auto func = [](auto x){ return T(x);}; int x;", "; int x ;"));
|
|
ASSERT(findTemplateDeclarationEndHelper("template <class, class a> auto b() -> decltype(a{}.template b<void(int, int)>); int x;", "; int x ;"));
|
|
ASSERT(findTemplateDeclarationEndHelper("template <class, class a> auto b() -> decltype(a{}.template b<void(int, int)>){} int x;", "} int x ;"));
|
|
ASSERT(findTemplateDeclarationEndHelper("template <typename... f, c<h<e<typename f::d...>>::g>> void i(); int x;", "; int x ;"));
|
|
ASSERT(findTemplateDeclarationEndHelper("template <typename... f, c<h<e<typename f::d...>>::g>> void i(){} int x;", "} int x ;"));
|
|
}
|
|
|
|
void expandSpecialized1() {
|
|
ASSERT_EQUALS("class A<int> { } ;", tok("template<> class A<int> {};"));
|
|
ASSERT_EQUALS("class A<int> : public B { } ;", tok("template<> class A<int> : public B {};"));
|
|
ASSERT_EQUALS("class A<int> { A<int> ( ) ; ~ A<int> ( ) ; } ;", tok("template<> class A<int> { A(); ~A(); };"));
|
|
ASSERT_EQUALS("class A<int> { A<int> ( ) { } ~ A<int> ( ) { } } ;", tok("template<> class A<int> { A() {} ~A() {} };"));
|
|
ASSERT_EQUALS("class A<int> { A<int> ( ) ; ~ A<int> ( ) ; } ; A<int> :: A<int> ( ) { } ~ A<int> :: A<int> ( ) { }",
|
|
tok("template<> class A<int> { A(); ~A(); }; A<int>::A() { } ~A<int>::A() {}"));
|
|
ASSERT_EQUALS("class A<int> { A<int> ( ) ; A<int> ( const A<int> & ) ; A<int> foo ( ) ; } ; A<int> :: A<int> ( ) { } A<int> :: A<int> ( const A<int> & ) { } A<int> A<int> :: foo ( ) { A<int> a ; return a ; }",
|
|
tok("template<> class A<int> { A(); A(const A &) ; A foo(); }; A<int>::A() { } A<int>::A(const A &) { } A<int> A<int>::foo() { A a; return a; }"));
|
|
}
|
|
|
|
void expandSpecialized2() {
|
|
{
|
|
const char code[] = "template <>\n"
|
|
"class C<float> {\n"
|
|
"public:\n"
|
|
" C() { }\n"
|
|
" C(const C &) { }\n"
|
|
" ~C() { }\n"
|
|
" C & operator=(const C &) { return *this; }\n"
|
|
"};\n"
|
|
"C<float> b;\n";
|
|
const char expected[] = "class C<float> { "
|
|
"public: "
|
|
"C<float> ( ) { } "
|
|
"C<float> ( const C<float> & ) { } "
|
|
"~ C<float> ( ) { } "
|
|
"C<float> & operator= ( const C<float> & ) { return * this ; } "
|
|
"} ; "
|
|
"C<float> b ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <>\n"
|
|
"class C<float> {\n"
|
|
"public:\n"
|
|
" C() { }\n"
|
|
" C(const C &) { }\n"
|
|
" ~C() { }\n"
|
|
" C & operator=(const C &) { return *this; }\n"
|
|
"};";
|
|
const char expected[] = "class C<float> { "
|
|
"public: "
|
|
"C<float> ( ) { } "
|
|
"C<float> ( const C<float> & ) { } "
|
|
"~ C<float> ( ) { } "
|
|
"C<float> & operator= ( const C<float> & ) { return * this ; } "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <>\n"
|
|
"class C<float> {\n"
|
|
"public:\n"
|
|
" C();\n"
|
|
" C(const C &);\n"
|
|
" ~C();\n"
|
|
" C & operator=(const C &);\n"
|
|
"};\n"
|
|
"C::C() { }\n"
|
|
"C::C(const C &) { }\n"
|
|
"C::~C() { }\n"
|
|
"C & C::operator=(const C &) { return *this; }\n"
|
|
"C<float> b;\n";
|
|
const char expected[] = "class C<float> { "
|
|
"public: "
|
|
"C<float> ( ) ; "
|
|
"C<float> ( const C<float> & ) ; "
|
|
"~ C<float> ( ) ; "
|
|
"C<float> & operator= ( const C<float> & ) ; "
|
|
"} ; "
|
|
"C<float> :: C<float> ( ) { } "
|
|
"C<float> :: C<float> ( const C<float> & ) { } "
|
|
"C<float> :: ~ C<float> ( ) { } "
|
|
"C<float> & C<float> :: operator= ( const C<float> & ) { return * this ; } "
|
|
"C<float> b ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <>\n"
|
|
"class C<float> {\n"
|
|
"public:\n"
|
|
" C();\n"
|
|
" C(const C &);\n"
|
|
" ~C();\n"
|
|
" C & operator=(const C &);\n"
|
|
"};\n"
|
|
"C::C() { }\n"
|
|
"C::C(const C &) { }\n"
|
|
"C::~C() { }\n"
|
|
"C & C::operator=(const C &) { return *this; }";
|
|
const char expected[] = "class C<float> { "
|
|
"public: "
|
|
"C<float> ( ) ; "
|
|
"C<float> ( const C<float> & ) ; "
|
|
"~ C<float> ( ) ; "
|
|
"C<float> & operator= ( const C<float> & ) ; "
|
|
"} ; "
|
|
"C<float> :: C<float> ( ) { } "
|
|
"C<float> :: C<float> ( const C<float> & ) { } "
|
|
"C<float> :: ~ C<float> ( ) { } "
|
|
"C<float> & C<float> :: operator= ( const C<float> & ) { return * this ; }";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
}
|
|
|
|
void expandSpecialized3() { // #8671
|
|
const char code[] = "template <> struct OutputU16<unsigned char> final {\n"
|
|
" explicit OutputU16(std::basic_ostream<unsigned char> &t) : outputStream_(t) {}\n"
|
|
" void operator()(unsigned short) const;\n"
|
|
"private:\n"
|
|
" std::basic_ostream<unsigned char> &outputStream_;\n"
|
|
"};";
|
|
const char expected[] = "struct OutputU16<unsignedchar> final { "
|
|
"explicit OutputU16<unsignedchar> ( std :: basic_ostream < unsigned char > & t ) : outputStream_ ( t ) { } "
|
|
"void operator() ( unsigned short ) const ; "
|
|
"private: "
|
|
"std :: basic_ostream < unsigned char > & outputStream_ ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void expandSpecialized4() {
|
|
{
|
|
const char code[] = "template<> class C<char> { };\n"
|
|
"map<int> m;";
|
|
const char expected[] = "class C<char> { } ; "
|
|
"map < int > m ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<> class C<char> { };\n"
|
|
"map<int> m;\n"
|
|
"C<char> c;";
|
|
const char expected[] = "class C<char> { } ; "
|
|
"map < int > m ; "
|
|
"C<char> c ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<typename T> class C { };\n"
|
|
"template<> class C<char> { };\n"
|
|
"map<int> m;\n";
|
|
const char expected[] = "class C<char> ; "
|
|
"template < typename T > class C { } ; "
|
|
"class C<char> { } ; "
|
|
"map < int > m ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<typename T> class C { };\n"
|
|
"template<> class C<char> { };\n"
|
|
"map<int> m;\n"
|
|
"C<int> i;";
|
|
const char expected[] = "class C<char> ; "
|
|
"class C<int> ; "
|
|
"class C<char> { } ; "
|
|
"map < int > m ; "
|
|
"C<int> i ; "
|
|
"class C<int> { } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<typename T> class C { };\n"
|
|
"template<> class C<char> { };\n"
|
|
"map<int> m;\n"
|
|
"C<int> i;\n"
|
|
"C<char> c;";
|
|
const char expected[] = "class C<char> ; "
|
|
"class C<int> ; "
|
|
"class C<char> { } ; "
|
|
"map < int > m ; "
|
|
"C<int> i ; "
|
|
"C<char> c ; "
|
|
"class C<int> { } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
}
|
|
|
|
void templateAlias1() {
|
|
const char code[] = "template<class T, int N> struct Foo {};\n"
|
|
"template<class T> using Bar = Foo<T,3>;\n"
|
|
"Bar<int> b;\n";
|
|
|
|
const char expected[] = "struct Foo<int,3> ; "
|
|
"Foo<int,3> b ; "
|
|
"struct Foo<int,3> { } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void templateAlias2() {
|
|
const char code[] = "namespace A { template<class T, int N> struct Foo {}; }\n"
|
|
"template<class T> using Bar = A::Foo<T,3>;\n"
|
|
"Bar<int> b;\n";
|
|
|
|
const char expected[] = "namespace A { struct Foo<int,3> ; } "
|
|
"A :: Foo<int,3> b ; "
|
|
"struct A :: Foo<int,3> { } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void templateAlias3() { // #8315
|
|
const char code[] = "template <int> struct Tag {};\n"
|
|
"template <int ID> using SPtr = std::shared_ptr<void(Tag<ID>)>;\n"
|
|
"SPtr<0> s;";
|
|
const char expected[] = "struct Tag<0> ; "
|
|
"std :: shared_ptr < void ( Tag<0> ) > s ; "
|
|
"struct Tag<0> { } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void templateAlias4() { // #9070
|
|
const char code[] = "template <class T>\n"
|
|
"using IntrusivePtr = boost::intrusive_ptr<T>;\n"
|
|
"template <class T> class Vertex { };\n"
|
|
"IntrusivePtr<Vertex<int>> p;";
|
|
const char expected[] = "class Vertex<int> ; "
|
|
"boost :: intrusive_ptr < Vertex<int> > p ; "
|
|
"class Vertex<int> { } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void templateAlias5() {
|
|
const char code[] = "template<typename T> using A = int;\n"
|
|
"template<typename T> using B = T;\n"
|
|
"A<char> a;\n"
|
|
"B<char> b;";
|
|
const char expected[] = "int a ; "
|
|
"char b ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
unsigned int instantiateMatch(const char code[], const std::size_t numberOfArguments, const char patternAfter[]) {
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
tokenizer.tokenize(istr, "test.cpp", "");
|
|
|
|
return TemplateSimplifier::instantiateMatch(tokenizer.tokens(), numberOfArguments, patternAfter);
|
|
}
|
|
|
|
void instantiateMatch() {
|
|
// Ticket #8175
|
|
ASSERT_EQUALS(false,
|
|
instantiateMatch("ConvertHelper < From, To > c ;",
|
|
2, ":: %name% ("));
|
|
ASSERT_EQUALS(true,
|
|
instantiateMatch("ConvertHelper < From, To > :: Create ( ) ;",
|
|
2, ":: %name% ("));
|
|
ASSERT_EQUALS(false,
|
|
instantiateMatch("integral_constant < bool, sizeof ( ConvertHelper < From, To > :: Create ( ) ) > ;",
|
|
2, ":: %name% ("));
|
|
ASSERT_EQUALS(false,
|
|
instantiateMatch("integral_constant < bool, sizeof ( ns :: ConvertHelper < From, To > :: Create ( ) ) > ;",
|
|
2, ":: %name% ("));
|
|
}
|
|
|
|
void templateParameterWithoutName() {
|
|
ASSERT_EQUALS(1U, templateParameters("template<typename = void> struct s;"));
|
|
ASSERT_EQUALS(1U, templateParameters("template<template<typename = float> typename T> struct A {\n"
|
|
" void f();\n"
|
|
" void g();\n"
|
|
"};n"));
|
|
}
|
|
|
|
void templateTypeDeduction1() { // #8962
|
|
const char code[] = "template<typename T>\n"
|
|
"void f(T n) { (void)n; }\n"
|
|
"static void func() {\n"
|
|
" f(0);\n"
|
|
" f(0u);\n"
|
|
" f(0U);\n"
|
|
" f(0l);\n"
|
|
" f(0L);\n"
|
|
" f(0ul);\n"
|
|
" f(0UL);\n"
|
|
" f(0ll);\n"
|
|
" f(0LL);\n"
|
|
" f(0ull);\n"
|
|
" f(0ULL);\n"
|
|
" f(0.0);\n"
|
|
" f(0.0f);\n"
|
|
" f(0.0F);\n"
|
|
" f(0.0l);\n"
|
|
" f(0.0L);\n"
|
|
" f('c');\n"
|
|
" f(L'c');\n"
|
|
" f(\"string\");\n"
|
|
" f(L\"string\");\n"
|
|
" f(true);\n"
|
|
" f(false);\n"
|
|
"}";
|
|
const char expected[] = "void f<int> ( int n ) ; "
|
|
"void f<unsignedint> ( unsigned int n ) ; "
|
|
"void f<long> ( long n ) ; "
|
|
"void f<unsignedlong> ( unsigned long n ) ; "
|
|
"void f<longlong> ( long long n ) ; "
|
|
"void f<unsignedlonglong> ( unsigned long long n ) ; "
|
|
"void f<double> ( double n ) ; "
|
|
"void f<float> ( float n ) ; "
|
|
"void f<longdouble> ( long double n ) ; "
|
|
"void f<char> ( char n ) ; "
|
|
"void f<wchar_t> ( wchar_t n ) ; "
|
|
"void f<constchar*> ( const char * n ) ; "
|
|
"void f<constwchar_t*> ( const wchar_t * n ) ; "
|
|
"void f<bool> ( bool n ) ; "
|
|
"static void func ( ) { "
|
|
"f<int> ( 0 ) ; "
|
|
"f<unsignedint> ( 0u ) ; "
|
|
"f<unsignedint> ( 0U ) ; "
|
|
"f<long> ( 0l ) ; "
|
|
"f<long> ( 0L ) ; "
|
|
"f<unsignedlong> ( 0ul ) ; "
|
|
"f<unsignedlong> ( 0UL ) ; "
|
|
"f<longlong> ( 0ll ) ; "
|
|
"f<longlong> ( 0LL ) ; "
|
|
"f<unsignedlonglong> ( 0ull ) ; "
|
|
"f<unsignedlonglong> ( 0ULL ) ; "
|
|
"f<double> ( 0.0 ) ; "
|
|
"f<float> ( 0.0f ) ; "
|
|
"f<float> ( 0.0F ) ; "
|
|
"f<longdouble> ( 0.0l ) ; "
|
|
"f<longdouble> ( 0.0L ) ; "
|
|
"f<char> ( 'c' ) ; "
|
|
"f<wchar_t> ( L'c' ) ; "
|
|
"f<constchar*> ( \"string\" ) ; "
|
|
"f<constwchar_t*> ( L\"string\" ) ; "
|
|
"f<bool> ( true ) ; "
|
|
"f<bool> ( false ) ; "
|
|
"} "
|
|
"void f<int> ( int n ) { ( void ) n ; } "
|
|
"void f<unsignedint> ( unsigned int n ) { ( void ) n ; } "
|
|
"void f<long> ( long n ) { ( void ) n ; } "
|
|
"void f<unsignedlong> ( unsigned long n ) { ( void ) n ; } "
|
|
"void f<longlong> ( long long n ) { ( void ) n ; } "
|
|
"void f<unsignedlonglong> ( unsigned long long n ) { ( void ) n ; } "
|
|
"void f<double> ( double n ) { ( void ) n ; } "
|
|
"void f<float> ( float n ) { ( void ) n ; } "
|
|
"void f<longdouble> ( long double n ) { ( void ) n ; } "
|
|
"void f<char> ( char n ) { ( void ) n ; } "
|
|
"void f<wchar_t> ( wchar_t n ) { ( void ) n ; } "
|
|
"void f<constchar*> ( const char * n ) { ( void ) n ; } "
|
|
"void f<constwchar_t*> ( const wchar_t * n ) { ( void ) n ; } "
|
|
"void f<bool> ( bool n ) { ( void ) n ; }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void templateTypeDeduction2() {
|
|
const char code[] = "template<typename T, typename U>\n"
|
|
"void f(T t, U u) { }\n"
|
|
"static void func() {\n"
|
|
" f(0, 0.0);\n"
|
|
" f(0.0, 0);\n"
|
|
"}";
|
|
|
|
const char expected[] = "void f<int,double> ( int t , double u ) ; "
|
|
"void f<double,int> ( double t , int u ) ; "
|
|
"static void func ( ) { "
|
|
"f<int,double> ( 0 , 0.0 ) ; "
|
|
"f<double,int> ( 0.0, 0 ) ; "
|
|
"void f<int,double> ( int t , double u ) { } "
|
|
"void f<double,int> ( double t , int u ) { } ";
|
|
|
|
const char actual[] = "template < typename T , typename U > "
|
|
"void f ( T t , U u ) { } "
|
|
"static void func ( ) { "
|
|
"f ( 0 , 0.0 ) ; "
|
|
"f ( 0.0 , 0 ) ; "
|
|
"}";
|
|
|
|
TODO_ASSERT_EQUALS(expected, actual, tok(code));
|
|
}
|
|
|
|
void simplifyTemplateArgs() {
|
|
ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template<int N> foo = N; foo < ( 2 ) >;"));
|
|
ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template<int N> foo = N; foo < 1 + 1 >;"));
|
|
ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template<int N> foo = N; foo < ( 1 + 1 ) >;"));
|
|
|
|
ASSERT_EQUALS("foo<2,2> = 4 ; foo<2,2> ;", tok("template<int N, int M> foo = N * M; foo < ( 2 ), ( 2 ) >;"));
|
|
ASSERT_EQUALS("foo<2,2> = 4 ; foo<2,2> ;", tok("template<int N, int M> foo = N * M; foo < 1 + 1, 1 + 1 >;"));
|
|
ASSERT_EQUALS("foo<2,2> = 4 ; foo<2,2> ;", tok("template<int N, int M> foo = N * M; foo < ( 1 + 1 ), ( 1 + 1 ) >;"));
|
|
|
|
ASSERT_EQUALS("foo<true> = true ; foo<true> ;", tok("template<bool N> foo = N; foo < true ? true : false >;"));
|
|
ASSERT_EQUALS("foo<false> = false ; foo<false> ;", tok("template<bool N> foo = N; foo < false ? true : false >;"));
|
|
ASSERT_EQUALS("foo<true> = true ; foo<true> ;", tok("template<bool N> foo = N; foo < 1 ? true : false >;"));
|
|
ASSERT_EQUALS("foo<false> = false ; foo<false> ;", tok("template<bool N> foo = N; foo < 0 ? true : false >;"));
|
|
ASSERT_EQUALS("foo<true> = true ; foo<true> ;", tok("template<bool N> foo = N; foo < (1 + 1 ) ? true : false >;"));
|
|
ASSERT_EQUALS("foo<false> = false ; foo<false> ;", tok("template<bool N> foo = N; foo < ( 1 - 1) ? true : false >;"));
|
|
}
|
|
|
|
void template_variadic_1() { // #9144
|
|
const char code[] = "template <typename...> struct e {};\n"
|
|
"static_assert(sizeof(e<>) == sizeof(e<int,int>), \"\");";
|
|
const char expected[] = "struct e<> ; struct e<int,int> ; "
|
|
"static_assert ( sizeof ( e<> ) == sizeof ( e<int,int> ) , \"\" ) ; "
|
|
"struct e<> { } ; struct e<int,int> { } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template_variable_1() {
|
|
{
|
|
const char code[] = "template <int N> const int foo = N*N;\n"
|
|
"int x = foo<7>;";
|
|
const char expected[] = "const int foo<7> = 49 ; "
|
|
"int x ; x = foo<7> ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <int> const int foo = 7;\n"
|
|
"int x = foo<7>;";
|
|
const char expected[] = "const int foo<7> = 7 ; "
|
|
"int x ; x = foo<7> ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <int N = 7> const int foo = N*N;\n"
|
|
"int x = foo<7>;";
|
|
const char expected[] = "const int foo<7> = 49 ; "
|
|
"int x ; x = foo<7> ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <int N = 7> const int foo = N*N;\n"
|
|
"int x = foo<>;";
|
|
const char expected[] = "const int foo<7> = 49 ; "
|
|
"int x ; x = foo<7> ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
}
|
|
|
|
void template_variable_2() {
|
|
{
|
|
const char code[] = "template<class T> constexpr T pi = T(3.1415926535897932385L);\n"
|
|
"float x = pi<float>;";
|
|
const char expected[] = "const float pi<float> = float ( 3.1415926535897932385L ) ; "
|
|
"float x ; x = pi<float> ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<class> constexpr float pi = float(3.1415926535897932385L);\n"
|
|
"float x = pi<float>;";
|
|
const char expected[] = "const float pi<float> = float ( 3.1415926535897932385L ) ; "
|
|
"float x ; x = pi<float> ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<class T = float> constexpr T pi = T(3.1415926535897932385L);\n"
|
|
"float x = pi<float>;";
|
|
const char expected[] = "const float pi<float> = float ( 3.1415926535897932385L ) ; "
|
|
"float x ; x = pi<float> ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<class T = float> constexpr T pi = T(3.1415926535897932385L);\n"
|
|
"float x = pi<>;";
|
|
const char expected[] = "const float pi<float> = float ( 3.1415926535897932385L ) ; "
|
|
"float x ; x = pi<float> ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
}
|
|
|
|
void template_variable_3() {
|
|
{
|
|
const char code[] = "template<class T, int N> constexpr T foo = T(N*N);\n"
|
|
"float x = foo<float,7>;";
|
|
const char expected[] = "const float foo<float,7> = float ( 49 ) ; "
|
|
"float x ; x = foo<float,7> ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<class,int> constexpr float foo = float(7);\n"
|
|
"float x = foo<float,7>;";
|
|
const char expected[] = "const float foo<float,7> = float ( 7 ) ; "
|
|
"float x ; x = foo<float,7> ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<class T = float, int N = 7> constexpr T foo = T(7);\n"
|
|
"double x = foo<double, 14>;";
|
|
const char expected[] = "const double foo<double,14> = double ( 7 ) ; "
|
|
"double x ; x = foo<double,14> ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<class T = float, int N = 7> constexpr T foo = T(7);\n"
|
|
"float x = foo<>;";
|
|
const char expected[] = "const float foo<float,7> = float ( 7 ) ; "
|
|
"float x ; x = foo<float,7> ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<class T = float, int N = 7> constexpr T foo = T(7);\n"
|
|
"double x = foo<double>;";
|
|
const char expected[] = "const double foo<double,7> = double ( 7 ) ; "
|
|
"double x ; x = foo<double,7> ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
}
|
|
|
|
void template_variable_4() {
|
|
const char code[] = "template<typename T> void test() { }\n"
|
|
"template<typename T> decltype(test<T>)* foo = &(test<T>);\n"
|
|
"void bar() { foo<int>(); }";
|
|
const char expected[] = "void test<int> ( ) ; "
|
|
"decltype ( test<int> ) * foo<int> = & ( test<int> ) ; "
|
|
"void bar ( ) { foo<int> ( ) ; } "
|
|
"void test<int> ( ) { }";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
};
|
|
|
|
REGISTER_TEST(TestSimplifyTemplate)
|