PR c++/43558

Dodji Seketeli dodji@redhat.com
Mon Mar 29 15:20:00 GMT 2010


Hello,

Consider this example:

template<class T, class U> struct S; //tmpl#1
template<class T>
class S<T*, int> //tmpl#2
{
    typedef T TT;
    TT f(T); //f#1
}; //#2

template<class T>
T
S<T*, int>::f(T t) //f#2
{
    return t;
}

During the comparison of the return types of f#1 and f#2, when we 
consider TT, we want to get the template parms of tmpl#2 and compare 
them with the template parms of //f#2.
The problem is we get the template parms of the most general template 
tmpl#1 instead.
This is because get_template_info called on the context of TT yields the
template info of the most general template tmpl#1 so we get the template 
parms of that tmpl#1 instead of getting the template parms of tmpl#2.

Thus the patch below introduces a new function 
get_most_specialized_template_info that yields the the template info of 
tmpl#2 when called on TT.

I couldn't find a direct way of getting the template parms (T) of
the partial specialization template<class T> S<T*, int> because its
CLASSTYPE_TEMPLATE_INFO points to the template info of tmpl#1.
So I ressorted to getting the CLASSTYPE_TEMPLATE_INFO of the self
reference of S<T*, int> because it represents the template info of this 
partial specialization so its DECL_TEMPLATE_PARMS (TI_TEMPLATE())
really is the template parms set T I want. Is there a better way of 
doing this?

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

        Dodji

commit 750822c2b384f2192c3ed6b9bcce00af137ed7a8
Author: Dodji Seketeli <dodji@redhat.com>
Date:   Mon Mar 29 15:10:42 2010 +0200

    Fix PR c++/43558
    
    gcc/cp/ChangeLog:
    	PR c++/43558
    	* cp-tree.h (get_self_reference,
    	get_most_specialized_template_info): Declare new fns.
    	* class.c (get_self_reference): Define new fn.
    	* pt.c (get_most_specialized_template_info): Define new fn. Use
    	get_self_reference.
    	* typeck.c (get_template_parms_of_dependent_type): Get template parms
    	of typedefs from the most specialized template info of their
    	context. Use get_most_specialized_template_info.
    
    gcc/testsuite/ChangeLog:
    	PR c++/43558
    	* g++.dg/template/typedef31.C: New test.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 1bab07d..2af3f1e 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6533,6 +6533,24 @@ build_self_reference (void)
   current_access_specifier = saved_cas;
 }
 
+/* Get the reference to CLASS_TYPE that has been built by
+   build_self_reference.  */
+
+tree
+get_self_reference (tree class_type)
+{
+  tree t;
+
+  if (!class_type || !CLASS_TYPE_P (class_type))
+    return NULL_TREE;
+
+  for (t = TYPE_FIELDS (class_type); t; t = TREE_CHAIN (t))
+    if (DECL_SELF_REFERENCE_P (t))
+      return t;
+
+  return NULL_TREE;
+}
+
 /* Returns 1 if TYPE contains only padding bytes.  */
 
 int
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 2eaee84..38df5fe 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4588,6 +4588,7 @@ extern void pop_lang_context			(void);
 extern tree instantiate_type			(tree, tree, tsubst_flags_t);
 extern void print_class_statistics		(void);
 extern void build_self_reference		(void);
+extern tree get_self_reference			(tree);
 extern int same_signature_p			(const_tree, const_tree);
 extern void maybe_add_class_template_decl_list	(tree, tree, int);
 extern void unreverse_member_declarations	(tree);
@@ -4926,6 +4927,7 @@ extern tree make_pack_expansion                 (tree);
 extern bool check_for_bare_parameter_packs      (tree);
 extern tree build_template_info			(tree, tree);
 extern tree get_template_info			(const_tree);
+extern tree get_most_specialized_template_info	(tree);
 extern VEC(qualified_typedef_usage_t,gc)* get_types_needing_access_check (tree);
 extern int template_class_depth			(tree);
 extern int is_specialization_of			(tree, tree);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3bd45f7..15fad01 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -321,6 +321,34 @@ get_template_info (const_tree t)
   return tinfo;
 }
 
+/* Return the template info corresponding to T.
+   If T is an instantiation of a partial class template specialization,
+   this function returns the template info corresponding to the partial
+   specialization instead of the one corresponding to the most general
+   template.
+
+   E.g:
+
+       template<class T, class U> struct S; //#1
+       template<class T> struct S<T*, int> {}; //#2
+
+   When called on S<char*, int>, this function returns the template info
+   corresponding to //#2.  */
+
+tree
+get_most_specialized_template_info (tree t)
+{
+  if (t && TAGGED_TYPE_P (t)
+      && CLASSTYPE_TEMPLATE_SPECIALIZATION (t)
+      && !explicit_class_specialization_p (t))
+    {
+      tree self = get_self_reference (t);
+      if (self)
+	return get_template_info (self);
+    }
+  return get_template_info (t);
+}
+
 /* Returns the template nesting level of the indicated class TYPE.
 
    For example, in:
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index a4c64ea..e9c7e5c 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1110,11 +1110,10 @@ get_template_parms_of_dependent_type (tree t)
      template info from T itself.  */
   if ((tinfo = get_template_info (t)))
     ;
-  /* If T1 is a typedef or whatever has a template info associated
-     to its context, get the template parameters from that context.  */
+  /* If T1 is a typedef, get the template parameters from its context.  */
   else if (typedef_variant_p (t)
 	   && !NAMESPACE_SCOPE_P (TYPE_NAME (t)))
-    tinfo = get_template_info (DECL_CONTEXT (TYPE_NAME (t)));
+    tinfo = get_most_specialized_template_info (DECL_CONTEXT (TYPE_NAME (t)));
   else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM
 	   && DECL_CONTEXT (TYPE_NAME (t)) == NULL_TREE)
     /* We have not yet created the DECL_TEMPLATE this
diff --git a/gcc/testsuite/g++.dg/template/typedef31.C b/gcc/testsuite/g++.dg/template/typedef31.C
new file mode 100644
index 0000000..7d66e3f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef31.C
@@ -0,0 +1,21 @@
+// Origin: PR c++/43558
+// { dg-do compile }
+
+class Compressible;
+template <class T, class EngineTag> class Engine;
+template <class T>
+class Engine<T, Compressible>
+{
+  public:
+    typedef T Element_t;
+      //Element_t read(int);
+      T read(int);
+};
+
+template <class T>
+T Engine<T, Compressible>::read(int)
+{
+}
+
+Engine<int, Compressible> x;
+



More information about the Gcc-patches mailing list