@@ -318,6 +318,7 @@ class TestSimplifyTemplate : public TestFixture {
318318 TEST_CASE (templateTypeDeductionNested); // calls inside a body created by deduction are deduced too
319319 TEST_CASE (templateTypeDeductionOutOfLine); // member template defined out of line, class in a namespace
320320 TEST_CASE (templateTypeDeductionShadowedType); // the deduced type name means another type in the template's scope
321+ TEST_CASE (templateTypeDeductionRecursion); // recursive calls are deduced, not renamed to the current instantiation
321322 TEST_CASE (templateTypeDeductionEnum); // enum arguments deduce the enum, not its underlying type
322323 TEST_CASE (templateTypeDeductionArray); // array arguments: only the decayed dimension is a pointer
323324 TEST_CASE (templateTypeDeductionConstPointer); // "const T *": the parameter provides the pointee const
@@ -7507,6 +7508,60 @@ class TestSimplifyTemplate : public TestFixture {
75077508 }
75087509 }
75097510
7511+ void templateTypeDeductionRecursion ()
7512+ { // a call of the template inside its own body must not be renamed to the
7513+ // instantiation being expanded - the argument types may differ
7514+ { // the recursive call instantiates another type
7515+ const char code[] = " template<class T> int f2(T t) { long l = 0; return f2(l); }\n "
7516+ " int g(int i) { return f2(i); }" ;
7517+ const char exp[] = " int f2<int> ( int t ) ; "
7518+ " int f2<long> ( long t ) ; "
7519+ " int g ( int i ) { return f2<int> ( i ) ; } "
7520+ " int f2<int> ( int t ) { long l ; l = 0 ; return f2<long> ( l ) ; } "
7521+ " int f2<long> ( long t ) { long l ; l = 0 ; return f2<long> ( l ) ; }" ;
7522+ ASSERT_EQUALS (exp, tok (code));
7523+ ASSERT_EQUALS (exp, tok (code, dinit (CheckOptions, $.templateFullRebuild = true )));
7524+ }
7525+ { // explicit template arguments at the call site: same expansion
7526+ const char code[] = " template<class T> int f2(T t) { long l = 0; return f2(l); }\n "
7527+ " int g(int i) { return f2<int>(i); }" ;
7528+ const char exp[] = " int f2<int> ( int t ) ; "
7529+ " int f2<long> ( long t ) ; "
7530+ " int g ( int i ) { return f2<int> ( i ) ; } "
7531+ " int f2<int> ( int t ) { long l ; l = 0 ; return f2<long> ( l ) ; } "
7532+ " int f2<long> ( long t ) { long l ; l = 0 ; return f2<long> ( l ) ; }" ;
7533+ ASSERT_EQUALS (exp, tok (code));
7534+ }
7535+ { // a literal argument
7536+ const char code[] = " template<class T> int f(T t) { return f(\" x\" ); }\n "
7537+ " int g(int i) { return f(i); }" ;
7538+ const char exp[] = " int f<int> ( int t ) ; "
7539+ " int f<constchar*> ( const char * t ) ; "
7540+ " int g ( int i ) { return f<int> ( i ) ; } "
7541+ " int f<int> ( int t ) { return f<constchar*> ( \" x\" ) ; } "
7542+ " int f<constchar*> ( const char * t ) { return f<constchar*> ( \" x\" ) ; }" ;
7543+ ASSERT_EQUALS (exp, tok (code));
7544+ }
7545+ { // the recursion uses the same type
7546+ const char code[] = " template<class T> int f(T t) { if (t) return f(t - 1); return 0; }\n "
7547+ " int g(int i) { return f(i); }" ;
7548+ const char exp[] = " int f<int> ( int t ) ; "
7549+ " int g ( int i ) { return f<int> ( i ) ; } "
7550+ " int f<int> ( int t ) { if ( t ) { return f<int> ( t - 1 ) ; } return 0 ; }" ;
7551+ ASSERT_EQUALS (exp, tok (code));
7552+ ASSERT_EQUALS (exp, tok (code, dinit (CheckOptions, $.templateFullRebuild = true )));
7553+ }
7554+ { // a declaration that deduction does not handle (T&&): the recursive call is
7555+ // renamed to the instantiation as before, it would stay unresolved otherwise
7556+ const char code[] = " template<class T> int f(T&& t) { return f(1); }\n "
7557+ " int g(int i) { return f<int>(i); }" ;
7558+ const char exp[] = " int f<int> ( int && t ) ; "
7559+ " int g ( int i ) { return f<int> ( i ) ; } "
7560+ " int f<int> ( int && t ) { return f<int> ( 1 ) ; }" ;
7561+ ASSERT_EQUALS (exp, tok (code));
7562+ }
7563+ }
7564+
75107565 void templateTypeDeductionEnum ()
75117566 {
75127567 { // an enum variable has the ValueType of the underlying integer type - the enum
0 commit comments