This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [Patch] PR c++/42824


Hello,

So I tried the idea you talked about on IRC, which is basically to
tsubst the arguments of the type of the most general template with all
but the innermost arguments of the current template specialization we 
are looking up. The result of that tsubsting constitutes the arguments 
of the partial instantiation of the member of class template, if
applicable.

Comparing the arguments of the specialization we are looking up with the 
result of the tsubsting does the trick and lets me do away with the new 
comparison code.

Tested on x86_64-unknown-linux-gnu against trunk.

Thanks.

        Dodji

commit 4bf13553672be5c496042b762766167642a5fd11
Author: Dodji Seketeli <dodji@redhat.com>
Date:   Thu Feb 4 20:20:49 2010 +0100

    Fix PR c++/42824
    
    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.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b903f77..6b5a65d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6325,7 +6325,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);
@@ -6441,21 +6442,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)
@@ -6474,7 +6471,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),
@@ -6540,11 +6537,69 @@ 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)
+	  && TREE_VEC_LENGTH (arglist) > 1
+	  /* 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 (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),
+				 INNERMOST_TEMPLATE_ARGS (partial_inst_args));
+	}
+
+      if (!use_partial_inst_tmpl)
 	/* This case is easy; there are no member templates involved.  */
 	found = gen_tmpl;
       else
@@ -6574,8 +6629,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
@@ -6585,7 +6639,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;
diff --git a/gcc/testsuite/g++.dg/template/memclass4.C b/gcc/testsuite/g++.dg/template/memclass4.C
new file mode 100644
index 0000000..65a42a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/memclass4.C
@@ -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> ();
+    }
+};
+


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]