@@ -315,6 +315,7 @@ class TestSimplifyTemplate : public TestFixture {
315315 TEST_CASE (templateTypeDeductionRedeclared); // twice declared template: the surviving declaration stays valid
316316 TEST_CASE (templateTypeDeductionFullRebuild); // --template-full-rebuild gives the same result
317317 TEST_CASE (templateTypeDeductionMultiPass); // a pending deduction survives later simplifier passes
318+ TEST_CASE (templateTypeDeductionNested); // calls inside a body created by deduction are deduced too
318319 TEST_CASE (templateTypeDeductionEnum); // enum arguments deduce the enum, not its underlying type
319320 TEST_CASE (templateTypeDeductionArray); // array arguments: only the decayed dimension is a pointer
320321 TEST_CASE (templateTypeDeductionConstPointer); // "const T *": the parameter provides the pointee const
@@ -7275,6 +7276,54 @@ class TestSimplifyTemplate : public TestFixture {
72757276 ASSERT_EQUALS (" " , errout_str ());
72767277 }
72777278
7279+ void templateTypeDeductionNested ()
7280+ { // a call inside a function body that a deduction instantiated has no symbol
7281+ // database scope yet when it is seen - the deduction must be retried in the next
7282+ // round instead of being given up
7283+ {
7284+ const char code[] = " template<class T> T twice(T t) { return t * 2; }\n "
7285+ " template<class T> T thrice(T t) { return twice(t) + t; }\n "
7286+ " int g(int a) { return thrice(a); }" ;
7287+ const char exp[] = " int twice<int> ( int t ) ; "
7288+ " int thrice<int> ( int t ) ; "
7289+ " int g ( int a ) { return thrice<int> ( a ) ; } "
7290+ " int thrice<int> ( int t ) { return twice<int> ( t ) + t ; } "
7291+ " int twice<int> ( int t ) { return t * 2 ; }" ;
7292+ ASSERT_EQUALS (exp, tok (code));
7293+ ASSERT_EQUALS (exp, tok (code, dinit (CheckOptions, $.templateFullRebuild = true )));
7294+ ASSERT_EQUALS (" " , errout_str ());
7295+ }
7296+ { // three levels, each one needs another round
7297+ const char code[] = " template<class T> T a(T t) { return t; }\n "
7298+ " template<class T> T b(T t) { return a(t); }\n "
7299+ " template<class T> T c(T t) { return b(t); }\n "
7300+ " long g(long x) { return c(x); }" ;
7301+ const char exp[] = " long a<long> ( long t ) ; "
7302+ " long b<long> ( long t ) ; "
7303+ " long c<long> ( long t ) ; "
7304+ " long g ( long x ) { return c<long> ( x ) ; } "
7305+ " long c<long> ( long t ) { return b<long> ( t ) ; } "
7306+ " long b<long> ( long t ) { return a<long> ( t ) ; } "
7307+ " long a<long> ( long t ) { return t ; }" ;
7308+ ASSERT_EQUALS (exp, tok (code));
7309+ ASSERT_EQUALS (exp, tok (code, dinit (CheckOptions, $.templateFullRebuild = true )));
7310+ ASSERT_EQUALS (" " , errout_str ());
7311+ }
7312+ { // the nested call uses a different type than the outer one
7313+ const char code[] = " template<class T> void sink(T t) { (void)t; }\n "
7314+ " template<class T> void outer(T t) { sink(&t); }\n "
7315+ " void g(int x) { outer(x); }" ;
7316+ const char exp[] = " void sink<int*> ( int * t ) ; "
7317+ " void outer<int> ( int t ) ; "
7318+ " void g ( int x ) { outer<int> ( x ) ; } "
7319+ " void outer<int> ( int t ) { sink<int*> ( & t ) ; } "
7320+ " void sink<int*> ( int * t ) { ( void ) t ; }" ;
7321+ ASSERT_EQUALS (exp, tok (code));
7322+ ASSERT_EQUALS (exp, tok (code, dinit (CheckOptions, $.templateFullRebuild = true )));
7323+ ASSERT_EQUALS (" " , errout_str ());
7324+ }
7325+ }
7326+
72787327 void templateTypeDeductionEnum ()
72797328 {
72807329 { // an enum variable has the ValueType of the underlying integer type - the enum
0 commit comments