[C++ PATCH] Fix for bug 29, g++.oliva/partspec1.C
Kriang Lerdsuwanakij
lerdsuwa@scf.usc.edu
Fri Nov 24 18:24:00 GMT 2000
Hi
The following patch fixes bug #29 and the testcase
g++.oliva/partspec1.C which is currently marked as XFAIL.
During class template partial specialization, we only
decide whether template argument deduction succeed without
verifying if it produces a valid type in nondeduce context.
This cause the failure in as reported in PR 29.
Furthermore a case that isn't really a nondeduce context,
when a template class is specialized by an expression
that is not template parameter dependent, is not compared
at all in unify(). This can be seen in g++.oliva/partspec1.C
involving ADDR_EXPR.
The patch below introduce a new function verify_class_unification
to do all the checking.
Patch tested on i586-pc-linux-gnu. Ok to install this patch?
--Kriang
2000-11-24 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
* pt.c (verify_class_unification): New function.
(try_class_unification): Use it.
(get_class_bindings): Likewise.
(unify): Adjust comment.
diff -cprN gcc-old/cp/pt.c gcc/cp/pt.c
*** gcc-old/cp/pt.c Thu Nov 23 17:18:46 2000
--- gcc/cp/pt.c Thu Nov 23 21:22:42 2000
*************** static tree tsubst_call_declarator_parms
*** 157,162 ****
--- 157,163 ----
static tree get_template_base_recursive PARAMS ((tree, tree,
tree, tree, tree, int));
static tree get_template_base PARAMS ((tree, tree, tree, tree));
+ static int verify_class_unification PARAMS ((tree, tree, tree));
static tree try_class_unification PARAMS ((tree, tree, tree, tree));
static int coerce_template_template_parms PARAMS ((tree, tree, int,
tree, tree));
*************** try_one_overload (tparms, orig_targs, ta
*** 8030,8035 ****
--- 8031,8082 ----
return 1;
}
+ /* Verify that nondeduce template argument agrees with the type
+ obtained from argument deduction. Return nonzero if the
+ verification fails.
+
+ For example:
+
+ struct A { typedef int X; };
+ template <class T, class U> struct C {};
+ template <class T> struct C<T, typename T::X> {};
+
+ Then with the instantiation `C<A, int>', we can deduce that
+ `T' is `A' but unify () does not check whether `typename T::X'
+ is `int'. This function ensure that they agree.
+
+ TARGS, PARMS are the same as the arguments of unify.
+ ARGS contains template arguments from all levels. */
+
+ static int
+ verify_class_unification (targs, parms, args)
+ tree targs, parms, args;
+ {
+ int i;
+ int nparms = TREE_VEC_LENGTH (parms);
+ tree new_parms = tsubst (parms, add_outermost_template_args (args, targs),
+ /*complain=*/0, NULL_TREE);
+ if (new_parms == error_mark_node)
+ return 1;
+
+ args = INNERMOST_TEMPLATE_ARGS (args);
+
+ for (i = 0; i < nparms; i++)
+ {
+ tree parm = TREE_VEC_ELT (new_parms, i);
+ tree arg = TREE_VEC_ELT (args, i);
+
+ /* In case we are deducing from a function argument of a function
+ templates, some parameters may not be deduced yet. So we
+ make sure that only fully substituted elements of PARM are
+ compared below. */
+
+ if (!uses_template_parms (parm) && !template_args_equal (parm, arg))
+ return 1;
+ }
+ return 0;
+ }
+
/* PARM is a template class (perhaps with unbound template
parameters). ARG is a fully instantiated type. If ARG can be
bound to PARM, return ARG, otherwise return NULL_TREE. TPARMS and
*************** try_class_unification (tparms, targs, pa
*** 8042,8048 ****
tree parm;
tree arg;
{
- int i;
tree copy_of_targs;
if (!CLASSTYPE_TEMPLATE_INFO (arg)
--- 8089,8094 ----
*************** try_class_unification (tparms, targs, pa
*** 8080,8093 ****
with S<I, I, I>. If we kept the already deduced knowledge, we
would reject the possibility I=1. */
copy_of_targs = make_tree_vec (TREE_VEC_LENGTH (targs));
- i = unify (tparms, copy_of_targs, CLASSTYPE_TI_ARGS (parm),
- CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE);
/* If unification failed, we're done. */
! if (i != 0)
return NULL_TREE;
! else
! return arg;
}
/* Subroutine of get_template_base. RVAL, if non-NULL, is a base we
--- 8126,8142 ----
with S<I, I, I>. If we kept the already deduced knowledge, we
would reject the possibility I=1. */
copy_of_targs = make_tree_vec (TREE_VEC_LENGTH (targs));
/* If unification failed, we're done. */
! if (unify (tparms, copy_of_targs, CLASSTYPE_TI_ARGS (parm),
! CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE))
return NULL_TREE;
!
! if (verify_class_unification (copy_of_targs, CLASSTYPE_TI_ARGS (parm),
! CLASSTYPE_TI_ARGS (arg)))
! return NULL_TREE;
!
! return arg;
}
/* Subroutine of get_template_base. RVAL, if non-NULL, is a base we
*************** unify (tparms, targs, parm, arg, strict)
*** 8706,8712 ****
a template-parameter.
In these cases, we assume deduction succeeded, but don't
! actually infer any unifications. */
return 0;
else
sorry ("use of `%s' in template type unification",
--- 8755,8764 ----
a template-parameter.
In these cases, we assume deduction succeeded, but don't
! actually infer any unifications.
!
! The cases when the arguments are not template parameter
! dependent it handled by verify_class_unification. */
return 0;
else
sorry ("use of `%s' in template type unification",
*************** get_class_bindings (tparms, parms, args)
*** 8913,8926 ****
int i, ntparms = TREE_VEC_LENGTH (tparms);
tree vec = make_tree_vec (ntparms);
! args = INNERMOST_TEMPLATE_ARGS (args);
!
! if (unify (tparms, vec, parms, args, UNIFY_ALLOW_NONE))
return NULL_TREE;
for (i = 0; i < ntparms; ++i)
if (! TREE_VEC_ELT (vec, i))
return NULL_TREE;
return vec;
}
--- 8965,8980 ----
int i, ntparms = TREE_VEC_LENGTH (tparms);
tree vec = make_tree_vec (ntparms);
! if (unify (tparms, vec, parms, INNERMOST_TEMPLATE_ARGS (args),
! UNIFY_ALLOW_NONE))
return NULL_TREE;
for (i = 0; i < ntparms; ++i)
if (! TREE_VEC_ELT (vec, i))
return NULL_TREE;
+
+ if (verify_class_unification (vec, parms, args))
+ return NULL_TREE;
return vec;
}
diff -cprN gcc-old/testsuite/g++.old-deja/g++.oliva/partspec1.C gcc/testsuite/g++.old-deja/g++.oliva/partspec1.C
*** gcc-old/testsuite/g++.old-deja/g++.oliva/partspec1.C Thu Nov 23 17:18:55 2000
--- gcc/testsuite/g++.old-deja/g++.oliva/partspec1.C Thu Nov 23 17:18:38 2000
*************** template <typename A, int* P> struct X;
*** 10,20 ****
int a;
template <typename A>
! struct X<A,&a> {}; // gets bogus error - candidate - XFAIL *-*-*
int b;
template <typename A>
! struct X<A,&b> {}; // gets bogus error - candidate - XFAIL *-*-*
! X<int,&a> x; // gets bogus error - ambiguous - XFAIL *-*-*
--- 10,20 ----
int a;
template <typename A>
! struct X<A,&a> {};
int b;
template <typename A>
! struct X<A,&b> {};
! X<int,&a> x;
diff -cprN gcc-old/testsuite/g++.old-deja/g++.pt/partial4.C gcc/testsuite/g++.old-deja/g++.pt/partial4.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/partial4.C Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.pt/partial4.C Thu Nov 23 17:19:27 2000
***************
*** 0 ****
--- 1,24 ----
+ // Build don't link:
+ // Origin: Gabriel Dos Reis <Gabriel.Dos-Reis@cmla.ens-cachan.fr>
+
+ // Bug 29. We failed to verify that template argument deduction
+ // produces a valid result in nondeduce context.
+
+ template<class T> struct Y { typedef T X; };
+
+ template<class T, class U> struct Base {};
+
+ template<class T> struct Base<T, typename T::X> {};
+
+ template<class T> struct Base<typename T::X, T> {};
+
+ template<class T, class U> struct Derived : Base <T, U> {};
+
+ struct A {};
+
+ template<class T> struct Derived<A, T> : Base< Y<T>, Y<T> > {};
+
+ int main()
+ {
+ Derived<A, int> d;
+ }
More information about the Gcc-patches
mailing list