[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