OSDN Git Service

Fix PR c++/42824
authordodji <dodji@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 21 Feb 2010 18:06:39 +0000 (18:06 +0000)
committerdodji <dodji@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 21 Feb 2010 18:06:39 +0000 (18:06 +0000)
gcc/cp/ChangeLog:
PR c++/42824
* pt.c (lookup_template_class): Better support of specialization
of member of class template implicit instantiation.

gcc/testsuite/ChangeLog:
PR c++/42824
* g++.dg/template/memclass4.C: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@156939 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/memclass4.C [new file with mode: 0644]

index d71e2b4..2ce5e02 100644 (file)
@@ -1,3 +1,9 @@
+2010-02-21  Dodji Seketeli  <dodji@redhat.com>
+
+       PR c++/42824
+       * pt.c (lookup_template_class): Better support of specialization
+       of member of class template implicit instantiation.
+
 2010-02-20  Manuel López-Ibáñez  <manu@gcc.gnu.org>
 
        PR c++/35669
index 9e159a2..8b19e2c 100644 (file)
@@ -6379,7 +6379,8 @@ lookup_template_class (tree d1,
       tree found = NULL_TREE;
       int arg_depth;
       int parm_depth;
-      int is_partial_instantiation;
+      int is_dependent_type;
+      int use_partial_inst_tmpl = false;
 
       gen_tmpl = most_general_template (templ);
       parmlist = DECL_TEMPLATE_PARMS (gen_tmpl);
@@ -6495,21 +6496,17 @@ lookup_template_class (tree d1,
       if (entry)
        POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, entry->spec);
 
-      /* This type is a "partial instantiation" if any of the template
-        arguments still involve template parameters.  Note that we set
-        IS_PARTIAL_INSTANTIATION for partial specializations as
-        well.  */
-      is_partial_instantiation = uses_template_parms (arglist);
+      is_dependent_type = uses_template_parms (arglist);
 
       /* If the deduced arguments are invalid, then the binding
         failed.  */
-      if (!is_partial_instantiation
+      if (!is_dependent_type
          && check_instantiated_args (gen_tmpl,
                                      INNERMOST_TEMPLATE_ARGS (arglist),
                                      complain))
        POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
 
-      if (!is_partial_instantiation
+      if (!is_dependent_type
          && !PRIMARY_TEMPLATE_P (gen_tmpl)
          && !LAMBDA_TYPE_P (TREE_TYPE (gen_tmpl))
          && TREE_CODE (CP_DECL_CONTEXT (gen_tmpl)) == NAMESPACE_DECL)
@@ -6528,7 +6525,7 @@ lookup_template_class (tree d1,
       /* Create the type.  */
       if (TREE_CODE (template_type) == ENUMERAL_TYPE)
        {
-         if (!is_partial_instantiation)
+         if (!is_dependent_type)
            {
              set_current_access_from_decl (TYPE_NAME (template_type));
              t = start_enum (TYPE_IDENTIFIER (template_type),
@@ -6594,11 +6591,71 @@ lookup_template_class (tree d1,
          DECL_VISIBILITY (type_decl) = CLASSTYPE_VISIBILITY (template_type);
        }
 
-      /* Set up the template information.  We have to figure out which
-        template is the immediate parent if this is a full
-        instantiation.  */
-      if (parm_depth == 1 || is_partial_instantiation
-         || !PRIMARY_TEMPLATE_P (gen_tmpl))
+      /* Let's consider the explicit specialization of a member
+         of a class template specialization that is implicitely instantiated,
+        e.g.:
+            template<class T>
+            struct S
+            {
+              template<class U> struct M {}; //#0
+            };
+
+            template<>
+            template<>
+            struct S<int>::M<char> //#1
+            {
+              int i;
+            };
+       [temp.expl.spec]/4 says this is valid.
+
+       In this case, when we write:
+       S<int>::M<char> m;
+
+       M is instantiated from the CLASSTYPE_TI_TEMPLATE of #1, not from
+       the one of #0.
+
+       When we encounter #1, we want to store the partial instantiation
+       of M (template<class T> S<int>::M<T>) in it's CLASSTYPE_TI_TEMPLATE.
+
+       For all cases other than this "explicit specialization of member of a
+       class template", we just want to store the most general template into
+       the CLASSTYPE_TI_TEMPLATE of M.
+
+       This case of "explicit specialization of member of a class template"
+       only happens when:
+       1/ the enclosing class is an instantiation of, and therefore not
+       the same as, the context of the most general template, and
+       2/ we aren't looking at the partial instantiation itself, i.e.
+       the innermost arguments are not the same as the innermost parms of
+       the most general template.
+
+       So it's only when 1/ and 2/ happens that we want to use the partial
+       instantiation of the member template in lieu of its most general
+       template.  */
+
+      if (PRIMARY_TEMPLATE_P (gen_tmpl)
+         && TMPL_ARGS_HAVE_MULTIPLE_LEVELS (arglist)
+         /* the enclosing class must be an instantiation...  */
+         && CLASS_TYPE_P (context)
+         && !same_type_p (context, DECL_CONTEXT (gen_tmpl)))
+       {
+         tree partial_inst_args;
+         TREE_VEC_LENGTH (arglist)--;
+         ++processing_template_decl;
+         partial_inst_args =
+           tsubst (INNERMOST_TEMPLATE_ARGS
+                       (CLASSTYPE_TI_ARGS (TREE_TYPE (gen_tmpl))),
+                   arglist, complain, NULL_TREE);
+         --processing_template_decl;
+         TREE_VEC_LENGTH (arglist)++;
+         use_partial_inst_tmpl =
+           /*...and we must not be looking at the partial instantiation
+            itself. */
+           !comp_template_args (INNERMOST_TEMPLATE_ARGS (arglist),
+                                partial_inst_args);
+       }
+
+      if (!use_partial_inst_tmpl)
        /* This case is easy; there are no member templates involved.  */
        found = gen_tmpl;
       else
@@ -6628,8 +6685,7 @@ lookup_template_class (tree d1,
        = tree_cons (arglist, t,
                     DECL_TEMPLATE_INSTANTIATIONS (templ));
 
-      if (TREE_CODE (t) == ENUMERAL_TYPE
-         && !is_partial_instantiation)
+      if (TREE_CODE (t) == ENUMERAL_TYPE && !is_dependent_type)
        /* Now that the type has been registered on the instantiations
           list, we set up the enumerators.  Because the enumeration
           constants may involve the enumeration type itself, we make
@@ -6639,7 +6695,7 @@ lookup_template_class (tree d1,
           the instantiation and exit above.  */
        tsubst_enum (template_type, t, arglist);
 
-      if (is_partial_instantiation)
+      if (is_dependent_type)
        /* If the type makes use of template parameters, the
           code that generates debugging information will crash.  */
        DECL_IGNORED_P (TYPE_STUB_DECL (t)) = 1;
index 682a7e8..cc94d47 100644 (file)
@@ -1,3 +1,8 @@
+2010-02-21  Dodji Seketeli  <dodji@redhat.com>
+
+       PR c++/42824
+       * g++.dg/template/memclass4.C: New test.
+
 2010-02-21  Tobias Burnus  <burnus@net-b.de>
 
        PR fortran/35259
diff --git a/gcc/testsuite/g++.dg/template/memclass4.C b/gcc/testsuite/g++.dg/template/memclass4.C
new file mode 100644 (file)
index 0000000..65a42a4
--- /dev/null
@@ -0,0 +1,70 @@
+// Origin: PR c++/42824
+// { dg-do compile }
+
+template<int T>
+class int_ {
+};
+
+template<int T, int T2>
+class Unit {
+public:
+    Unit(const Unit<T, T2>& other) {}
+};
+
+template<int T>
+class Quan {
+public:
+    Quan(void) {}
+
+    template<int T2>
+    Quan(double value, Unit<T, T2> unit) {}
+};
+typedef Quan<0> Scalar;
+
+template<int T>
+class hlp {
+public:
+   typedef Quan<T> type;
+};
+
+class Mtrl {
+public:
+    template<int T>
+    struct AssoType {
+        typedef typename hlp<T>::type type;
+    };
+};
+
+template<class T>
+class Eval {
+public:
+    Eval(const T& object){}
+
+    template<int V>
+    void eval() {
+        eval<V> (int_<0>());
+    }
+private:
+    template<typename U> struct Wrap {};
+
+    template<int V, int V2>
+    void value(Wrap<Quan<V2> >) {}
+
+    template<int V>
+    void value(Wrap<Scalar>) {}
+
+    template<int V>
+    void eval(int_<0>) {
+        typedef typename T::template AssoType<V>::type Type;
+        value<V>(Wrap<Type>());
+    }
+};
+
+class Foo {
+public:
+    static void eval(const Mtrl& mtrl) {
+        Eval<Mtrl> h(mtrl);
+        h.eval<0> ();
+    }
+};
+