Bug 14032 - Specialization of inner template using outer template argument doesn't work
Summary: Specialization of inner template using outer template argument doesn't work
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.3.1
: P2 normal
Target Milestone: ---
Assignee: Jason Merrill
URL:
Keywords: rejects-valid, wrong-code
: 4882 10574 29767 29830 (view as bug list)
Depends on:
Blocks: c++-lookup, c++-name-lookup 29767
  Show dependency treegraph
 
Reported: 2004-02-05 20:54 UTC by Tobias Schwinger
Modified: 2007-09-15 15:35 UTC (History)
13 users (show)

See Also:
Host:
Target:
Build:
Known to work: 4.2.2 4.3.0
Known to fail: 3.3.1 3.2.3 2.95.3 3.4.0 4.0.0 4.1.2 4.2.0
Last reconfirmed: 2007-08-29 01:00:33


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tobias Schwinger 2004-02-05 20:54:32 UTC
Compiled with gcc 3.3.1 (cygwin), 3.2.3 (gentoo-linux), mingw32 3.2 the test 
code included in this report generates an endless recursion.
It compiles without errors or warnings so the underlying problem can be quite 
hard to track for the user.

$ cat <<EOF >test.cpp
#include <iostream>

template <bool compare>
struct outer
{
  template <bool compare_with,bool second>
  struct inner           // unspecialized compare != compare_with
  {
    static inline void test()
    {
      std::cout << "invert" << std::endl;
      // call version with inverted template value
      inner<! compare_with, ! second>::test();
    }
  };
  template <bool second> // specialization compare == compare_with
  struct inner<compare,second>
  {
    static inline void test()
    {
      std::cout << "second: " << second << std::endl;
    }
  };
};
int main(int argc,char* argv[],char** envp)
{
  // expected output:
  //  invert
  //  second: true
  outer<false>::inner<true,false>::test();

  // expected output:
  //  second: false
  outer<true>::inner<true,false>::test();

  return 0;
}

EOF
$ make test && ./test
Comment 1 Wolfgang Bangerth 2004-02-05 21:51:20 UTC
Confirmed. Reduced, this looks so: 
--------------------------- 
template <bool B1> struct outer { 
    template <bool B2, bool B3> 
    struct inner { 
        static int f() { return inner<!B2,!B3>::N; }; 
    }; 
 
    template <bool B3> 
    struct inner<B1,B3> { 
        static const int N = 1; 
    }; 
}; 
 
int i = outer<false>::inner<true,false>::f(); 
--------------------------- 
This should compile, since in f() we should look into the specialization, 
but we don't. And never did. 
 
W. 
Comment 2 Wolfgang Bangerth 2004-02-05 21:54:18 UTC
And just as a sidenote: this bug may be related to the fact 
that we reject this explicit (full) specialization in this code: 
------------------------- 
template <bool B1> struct outer { 
    template <bool B2> 
    struct inner { 
        static int f() { return inner<!B2>::N; }; 
    }; 
 
    template <> 
    struct inner<B1> { 
        static const int N = 1; 
    }; 
}; 
 
int i = outer<false>::inner<true>::f(); 
---------------------------- 
 
g/x> /home/bangerth/bin/gcc-3.4-pre/bin/c++ x.cc -c 
x.cc:7: error: invalid explicit specialization before '>' token 
x.cc:7: error: explicit specialization in non-namespace scope `struct 
outer<B1>' 
x.cc:7: error: enclosing class templates are not explicitly specialized 
g/x>  
g/x> icc -c x.cc 
g/x>  
Comment 3 Giovanni Bajo 2004-02-06 18:47:19 UTC
Testcase in comment #2 by Wolfgang is ill-formed because of [temp.expl.spec]/2: 
explicit specializations must always be defined at namespace scope. Instead, 
partial specialization can be defined at class scope.
Comment 4 Wolfgang Bangerth 2004-02-06 19:05:06 UTC
I was basically looking at the first line of errors only, so 
totally missed the rest. Sorry. The example in #1 should be 
valid, though. 
 
W. 
Comment 5 Kriang Lerdsuwanakij 2004-07-30 17:30:52 UTC
Related to PR4882, PR13088.
Comment 6 Kriang Lerdsuwanakij 2004-11-28 10:47:47 UTC
Work postponed to GCC 4.1.  This bug is tricky to fix.
Comment 7 Kriang Lerdsuwanakij 2005-10-22 13:57:43 UTC
Won't work on it for a long while.
Comment 8 Wolfgang Bangerth 2006-11-09 05:25:20 UTC
*** Bug 29767 has been marked as a duplicate of this bug. ***
Comment 9 Wolfgang Bangerth 2006-11-09 05:33:08 UTC
PR29767 made me try whether we can achieve the same wrong effect for
template type parameters, and indeed we can:
--------------------
template <typename T> struct outer { 
    template <typename T2, typename U> 
    struct inner { 
        static int f() { return inner<T,int>::N; }; 
    }; 
 
    template <typename U> 
    struct inner<T,U> { 
        static const int N = 1; 
    }; 
}; 
 
int i = outer<int>::inner<double,int>::f(); 
------------------
This compiles with icc, but doesn't with gcc:
g/x> /home/bangerth/bin/gcc-4.2-pre/bin/c++ -c x.cc
x.cc: In static member function &#8216;static int outer<T>::inner<T2, U>::f() [with T2 = double, U = int, T = int]&#8217;:
x.cc:13:   instantiated from here
x.cc:4: error: &#8216;N&#8217; is not a member of &#8216;outer<int>::inner<int, int>&#8217;

As PR29767 shows, this can actually lead to wrong code.

W.
Comment 10 Andrew Pinski 2006-11-14 16:30:52 UTC
*** Bug 29830 has been marked as a duplicate of this bug. ***
Comment 11 Zoltan Jasz 2006-11-14 17:40:01 UTC
(In reply to comment #6)
> Work postponed to GCC 4.1.  This bug is tricky to fix.

What is the status of this bug? Will be resolved in the next release?
For us is critical because a whole framework is built up on this.:,,,(
Unfortunately we don't have any workaround!

/jz
Comment 12 Richard Biener 2006-11-14 17:46:33 UTC
Raising severity, some more people in CC.  This at least seems to be an often reported problem.
Comment 13 Andrew Pinski 2006-11-14 17:54:30 UTC
(In reply to comment #12)
> Raising severity, some more people in CC.  This at least seems to be an often
> reported problem.

It is not a regression as far as I can tell.
Comment 14 bangerth@math.tamu.edu 2006-11-14 18:37:25 UTC
Subject: Re:  Specialization of inner template using outer template argument doesn't work


> It is not a regression as far as I can tell.

True. However it does produce wrong code.
W.
Comment 15 Tyson Whitehead 2007-02-16 15:10:38 UTC
This is a duplicate of 4882, however, I don't have the power to mark it as that (not that that would necessarily be a good thing as this contains more recent begging and is flagged with a higher priority).
Comment 16 Wolfgang Bangerth 2007-02-16 18:39:33 UTC
*** Bug 4882 has been marked as a duplicate of this bug. ***
Comment 17 Wolfgang Bangerth 2007-02-16 18:47:55 UTC
If anyone ever fixes this, the various duplicates of this bug
have a number of interesting variants that may be worth adding
to the testsuite as well.

W.
Comment 18 Jason Merrill 2007-09-04 12:27:40 UTC
Subject: Bug 14032

Author: jason
Date: Tue Sep  4 12:27:21 2007
New Revision: 128076

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=128076
Log:
        PR c++/14032
        * pt.c (most_specialized_class): Substitute outer template
        arguments into the arguments of a member template partial
        specialization.
        (strip_innermost_template_args): New fn.

Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/pt.c

Comment 19 Jason Merrill 2007-09-04 12:28:27 UTC
Subject: Bug 14032

Author: jason
Date: Tue Sep  4 12:27:38 2007
New Revision: 128077

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=128077
Log:
        PR c++/14032
        * pt.c (most_specialized_class): Substitute outer template
        arguments into the arguments of a member template partial
        specialization.
        (strip_innermost_template_args): New fn.

Added:
    trunk/gcc/testsuite/g++.dg/template/mem-partial1.C
    trunk/gcc/testsuite/g++.dg/template/mem-partial2.C

Comment 20 Jason Merrill 2007-09-04 15:43:12 UTC
Subject: Bug 14032

Author: jason
Date: Tue Sep  4 15:43:00 2007
New Revision: 128090

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=128090
Log:
        PR c++/14032
        * pt.c (most_specialized_class): Substitute outer template
        arguments into the arguments of a member template partial
        specialization.
        (strip_innermost_template_args): New fn.

Added:
    branches/gcc-4_2-branch/gcc/testsuite/g++.dg/template/mem-partial1.C
      - copied unchanged from r128077, trunk/gcc/testsuite/g++.dg/template/mem-partial1.C
    branches/gcc-4_2-branch/gcc/testsuite/g++.dg/template/mem-partial2.C
      - copied unchanged from r128077, trunk/gcc/testsuite/g++.dg/template/mem-partial2.C
Modified:
    branches/gcc-4_2-branch/gcc/cp/ChangeLog
    branches/gcc-4_2-branch/gcc/cp/pt.c

Comment 21 Jason Merrill 2007-09-13 16:06:05 UTC
Fixed for 4.2.2 and 4.3.0.
Comment 22 Volker Reichelt 2007-09-15 15:35:44 UTC
*** Bug 10574 has been marked as a duplicate of this bug. ***