[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