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


On Sat, Feb 20, 2010 at 04:07:24PM -0500, Jason Merrill wrote:
> On 02/20/2010 03:47 PM, Dodji Seketeli wrote:
> >+      if (PRIMARY_TEMPLATE_P (gen_tmpl)
> >+	     &&  TREE_VEC_LENGTH (arglist) >  1
> 
> TMPL_ARGS_HAVE_MULTIPLE_LEVELS

Done.

> 
> >+	  tree partial_inst_args;
> >+	  TREE_VEC_LENGTH (arglist)--;
> >+	  ++processing_template_decl;
> >+	  partial_inst_args = tsubst (CLASSTYPE_TI_ARGS (TREE_TYPE (gen_tmpl)),
> 
> I think you could take INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS here...
> 
> >+				      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));
> 
> ...rather than INNERMOST_TEMPLATE_ARGS (partial_inst_args) here.
> Probably not a significant optimization, but we might as well.

Okay, done.

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

Thanks.

        Dodji

commit 9eaa8418240f4bb2a265e119beeec85980e103b6
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..492e445 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,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
@@ -6574,8 +6631,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 +6641,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]