[RFC] PR c++/43206

Dodji Seketeli dodji@redhat.com
Thu Mar 4 20:59:00 GMT 2010


Hello,

In the example of the patch below we fail to compare template type parms 
when we are still parsing template parameters. In that case, the 
DECL_CONTEXT of the TYPE_NAME of the template type parms is not set yet, 
because it's set later when the containing TEMPLATE_DECL is created in 
push_template_decl_real.

A/ It would be convenient to say that if T1 and T2 are template type 
parms -- one of them being a typedef variant -- and if we could get the 
template parms T1 belongs to, but failed to get the template parms T2 
belongs to, (because we get NULL_TREE instead) then it would mean T1 and 
T2 are incompatible.

B/ But that assumption would break other codes like:
template<class T>
struct S
{
    typedef T TT;
    TT foo(); //#1
};

template<class T>
T S<t>::foo(); //#2

When we reach #2 start_decl -- by mean of maybe_push_decl -- must 
compare #1 and #2 and recognize that #2 is the same decl as #1, merge 
the two decls and only then create a TEMPLATE_DECL for #2. Thus the 
DECL_CONTEXT of the TYPE_NAME of T is empty for #2 during the type 
comparison of T (in #2) and TT that happens when comparing the decls #1 
and #2. The A/ assumption would thus make #2 be different from #1.

So I temporarily set the DECL_CONTEXT of the TYPE_NAME of each template 
type parm to the list of parms it belongs to in end_template_parm_list.
That removes problem B/.
The DECL_CONTEXT would then be later set to the proper TEMPLATE_DECL in
push_template_decl_real.

I guess this allows me to make assumption A/, unless there are cases 
other than B for which A/ is not correct. Can you see other cases like 
that?

FWIW, tested on x86_64-unknown-linux-gnu against trunk.

        Dodji

commit eeec5b3c414d67e4290e9370710400f4a5024902
Author: Dodji Seketeli <dodji@redhat.com>
Date:   Thu Mar 4 18:42:20 2010 +0100

    Fix candidate for PR c++/43206
    
    gcc/cp/ChangeLog:
    	PR c++/43206
    	* pt.c (end_template_parm_list): Temporarily set DECL_CONTEXT
    	of the type decl of template type parm to the list of
    	template parameters it belongs to.
    	* typeck.c (get_template_parms_of_dependent_type): Try to get template
    	parms's TREE_LIST from DECL_CONTEXT of template type parm when
    	the containing DECL_TEMPLATE is not created.
    	(incompatible_dependent_types_p): If we get empty parms from just one
    	of the template type parms we are comparing then the template parms are
    	incompatible.
    
    gcc/testsuite/ChangeLog:
    	PR c++/43206
    	* g++.dg/template/typedef30.C: New test case.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f5d3851..64e2b15 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3549,6 +3549,17 @@ end_template_parm_list (tree parms)
       next = TREE_CHAIN (parm);
       TREE_VEC_ELT (saved_parmlist, nparms) = parm;
       TREE_CHAIN (parm) = NULL_TREE;
+      if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL)
+	/* Temporarily set the DECL_CONTEXT of the parm decl to the
+	   list of template parms this type parm belongs to. This is useful
+	   to be able to do proper type comparison between typedefs of
+	   dependent types because in those cases we need to compare the
+	   parms of the template the typedefs belong to.
+	   See function incompatible_dependent_types_p.
+	   In any case, later when the TEMPLATE_DECL these template parms
+	   belong to is created push_template_decl_real fixes
+	   this up and assigns this DECL_CONTEXT to that TEMPLATE_DECL.  */
+	DECL_CONTEXT (TREE_VALUE (parm)) = current_template_parms;
     }
 
   --processing_template_parmlist;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index b9ef78f..0fc8089 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1110,11 +1110,19 @@ get_template_parms_of_dependent_type (tree t)
      template info from T itself.  */
   if ((tinfo = get_template_info (t)))
     ;
+  else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM
+	   && DECL_CONTEXT (TYPE_NAME (t))
+	   && TREE_CODE (DECL_CONTEXT (TYPE_NAME (t))) == TREE_LIST)
+    /* This means we have not yet created the DECL_TEMPLATE this
+       template type parm belongs to. In that case,
+       DECL_CONTEXT (TYPE_NAME (t)) contains the TREE_LIST of the
+       template parms -- see end_template_parm_list. Return it.  */
+    return DECL_CONTEXT (TYPE_NAME (t));
   /* If T1 is a typedef or whatever has a template info associated
      to its context, get the template parameters from that context.  */
   else if (typedef_variant_p (t)
-      && DECL_CONTEXT (TYPE_NAME (t))
-      && !NAMESPACE_SCOPE_P (TYPE_NAME (t)))
+	   && DECL_CONTEXT (TYPE_NAME (t))
+	   && !NAMESPACE_SCOPE_P (TYPE_NAME (t)))
     tinfo = get_template_info (DECL_CONTEXT (TYPE_NAME (t)));
   else if (TYPE_CONTEXT (t)
 	   && !NAMESPACE_SCOPE_P (t))
@@ -1170,6 +1178,17 @@ incompatible_dependent_types_p (tree t1, tree t2)
   tparms1 = get_template_parms_of_dependent_type (t1);
   tparms2 = get_template_parms_of_dependent_type (t2);
 
+  /* If T2 is a template type parm and if we could not get the template
+     parms it belongs to, that means we have not finished parsing the
+     full set of template parameters of the template declaration it
+     belongs to yet. If we could get the template parms T1 belongs to,
+     that mostly means T1 and T2 belongs to templates that are
+     different and incompatible.  */
+  if (TREE_CODE (t1) == TEMPLATE_TYPE_PARM
+      && (tparms1 == NULL_TREE || tparms2 == NULL_TREE)
+      && tparms1 != tparms2)
+    return true;
+
   if (tparms1 == NULL_TREE
       || tparms2 == NULL_TREE
       || tparms1 == tparms2)
diff --git a/gcc/testsuite/g++.dg/template/typedef30.C b/gcc/testsuite/g++.dg/template/typedef30.C
new file mode 100644
index 0000000..2f9362a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef30.C
@@ -0,0 +1,20 @@
+// Origin: PR c++/43206
+// { dg-do compile }
+
+template<class A> struct NumericTraits{ typedef A TInputImage;};
+template<class B> class CovariantVector{};
+template<class C> struct Image{ typedef C PixelType;};
+template<class H, class E, class D>
+class F {
+  typedef H G;
+  typedef
+  typename NumericTraits<typename G::PixelType>::RealType
+  InputRealType;
+};
+
+template<typename TInputImage,
+         typename TOutputImage=Image<CovariantVector<typename NumericTraits<typename TInputImage::PixelType>::TInputImage> > >
+class XXX{};
+
+XXX<Image<float> > x;
+



More information about the Gcc-patches mailing list