This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[C++ PATCH] Fix a template template parm non-compliant behavior


Hi

The appended patch fixes one of a few issues of template template parameter
that is not standard compliant.  Inside a template class, the name of
the class itself is no longer treated as a legal template template argument.
Example of such case can be seen in the diff to the file 'NEWS'.

With the patch, the code is now flagged as error and a message suggesting
the solution is printed.  The function is_base_of_enclosing_class is no
longer used and is removed.  I propose that this new error message be
removed some time later in the future (perhaps in gcc 3.3 ?) because it is
ugly and not 100% reliable, i.e, it cannot distinguish between C<D> and
C<D<T> >, and no message is displayed for illegal syntax in function calls 
f<D>().

Bootstrapped and tested on i686-pc-linux-gnu without any regressions.
Ok to commit to the main trunk?

--Kriang


2001-07-12  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	* cp-tree.h (is_base_of_enclosing_class): Remove.
	* class.c (is_base_of_enclosing_class): Likewise.
	* pt.c (convert_template_argument): Issue error when implicitly
	created TYPE_DECL is used as template template argument.
	* NEWS: Document changed behavior.

2001-07-12  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	* g++.old-deja/g++.pt/ttp41.C: New test.
	* g++.old-deja/g++.pt/ttp43.C: Adjust test.
	* g++.old-deja/g++.pt/ttp44.C: Adjust test.


diff -cprN gcc-main-save/gcc/cp/NEWS gcc-main-new/gcc/cp/NEWS
*** gcc-main-save/gcc/cp/NEWS	Thu Jun 14 01:37:18 2001
--- gcc-main-new/gcc/cp/NEWS	Wed Jul 11 21:53:18 2001
***************
*** 1,5 ****
--- 1,17 ----
  *** Changes in GCC 3.1:
  
+ * Fix to template template parameter handling to conform with the C++
+   standard:
+ 
+      + Inside a template class, the name of the class itself is no longer
+        valid template template argument.  A qualified name must be used
+        instead.  Example:
+ 
+ 	template <template <class> class TT> class C {};
+ 	template <class T> class D {
+ 		C<D> c;		// Invalid, should be C<::D>
+ 	};
+ 
  *** Changes in GCC 3.0:
  
  * Support for guiding declarations has been removed.
diff -cprN gcc-main-save/gcc/cp/class.c gcc-main-new/gcc/cp/class.c
*** gcc-main-save/gcc/cp/class.c	Mon Jun 18 18:17:53 2001
--- gcc-main-new/gcc/cp/class.c	Wed Jul 11 21:27:25 2001
*************** get_enclosing_class (type)
*** 6662,6683 ****
    return NULL_TREE;
  }
  
- /* Return 1 if TYPE or one of its enclosing classes is derived from BASE.  */
- 
- int
- is_base_of_enclosing_class (base, type)
-      tree base, type;
- {
-   while (type)
-     {
-       if (get_binfo (base, type, 0))
- 	return 1;
- 
-       type = get_enclosing_class (type);
-     }
-   return 0;
- }
- 
  /* Note that NAME was looked up while the current class was being
     defined and that the result of that lookup was DECL.  */
  
--- 6662,6667 ----
diff -cprN gcc-main-save/gcc/cp/cp-tree.h gcc-main-new/gcc/cp/cp-tree.h
*** gcc-main-save/gcc/cp/cp-tree.h	Thu Jul  5 19:43:02 2001
--- gcc-main-new/gcc/cp/cp-tree.h	Wed Jul 11 21:27:18 2001
*************** extern void build_self_reference		PARAMS
*** 3722,3728 ****
  extern int same_signature_p			PARAMS ((tree, tree));
  extern void warn_hidden				PARAMS ((tree));
  extern tree get_enclosing_class			PARAMS ((tree));
- int is_base_of_enclosing_class			PARAMS ((tree, tree));
  extern void unreverse_member_declarations       PARAMS ((tree));
  extern void invalidate_class_lookup_cache       PARAMS ((void));
  extern void maybe_note_name_used_in_class       PARAMS ((tree, tree));
--- 3722,3727 ----
diff -cprN gcc-main-save/gcc/cp/pt.c gcc-main-new/gcc/cp/pt.c
*** gcc-main-save/gcc/cp/pt.c	Thu Jul  5 19:43:27 2001
--- gcc-main-new/gcc/cp/pt.c	Wed Jul 11 21:30:40 2001
*************** convert_template_argument (parm, arg, ar
*** 3284,3309 ****
    requires_type = (TREE_CODE (parm) == TYPE_DECL
  		   || requires_tmpl_type);
  
!   /* Check if it is a class template.  If REQUIRES_TMPL_TYPE is true,
!      we also accept implicitly created TYPE_DECL as a valid argument.
!      This is necessary to handle the case where we pass a template name
!      to a template template parameter in a scope where we've derived from
!      in instantiation of that template, so the template name refers to that
!      instantiation.  We really ought to handle this better.  */
    is_tmpl_type 
!     = ((TREE_CODE (arg) == TEMPLATE_DECL
! 	&& TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)
!        || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
!        || (TREE_CODE (arg) == RECORD_TYPE
! 	   && CLASSTYPE_TEMPLATE_INFO (arg)
! 	   && TREE_CODE (TYPE_NAME (arg)) == TYPE_DECL
! 	   && DECL_ARTIFICIAL (TYPE_NAME (arg))
! 	   && requires_tmpl_type
! 	   && is_base_of_enclosing_class (arg, current_class_type)));
    if (is_tmpl_type && TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
      arg = TYPE_STUB_DECL (arg);
-   else if (is_tmpl_type && TREE_CODE (arg) == RECORD_TYPE)
-     arg = CLASSTYPE_TI_TEMPLATE (arg);
  
    is_type = TYPE_P (arg) || is_tmpl_type;
  
--- 3284,3329 ----
    requires_type = (TREE_CODE (parm) == TYPE_DECL
  		   || requires_tmpl_type);
  
!   /* Check if it is a class template.  */
    is_tmpl_type 
!     = (TREE_CODE (arg) == TEMPLATE_DECL
!        && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)
!       || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM;
! 
!   /* If REQUIRES_TMPL_TYPE is true, we used to also accept implicitly
!      created TYPE_DECL as a valid argument.  It is not standard compliant.
!      A nice diagnostic is issued here to aid porting old code where
!      a template name was passed to a template template parameter in 
!      a scope where we've derived from in instantiation of that template,
!      so the template name refers to that instantiation.  It will be removed
!      in future gcc version.  */
!   if (complain && TREE_CODE (arg) == RECORD_TYPE
!       && CLASSTYPE_TEMPLATE_INFO (arg)
!       && TREE_CODE (TYPE_NAME (arg)) == TYPE_DECL
!       && DECL_ARTIFICIAL (TYPE_NAME (arg))
!       && requires_tmpl_type
!       && arg == current_class_type)
!     {
!       tree name = DECL_NAME (CLASSTYPE_TI_TEMPLATE (arg));
!       tree context = DECL_CONTEXT (CLASSTYPE_TI_TEMPLATE (arg));
!       if (context && TYPE_P (context))
! 	context = TYPE_NAME (context);
! 
!       cp_error ("unqualified name `%D' is not a valid template template"
! 		" argument inside class `%T'", name, current_class_type);
!       if (context)
! 	/* Dump CONTEXT as IDENTIFIER_NODE to avoid class key in case it is
! 	   an aggregate.  */
! 	cp_error ("  use qualified name `%D::%D' instead",
! 		  DECL_NAME (context), name);
!       else
! 	cp_error ("  use qualified name `::%D' instead", name);
!       return error_mark_node;
!     }
! 
!   /* Extract TEMPLATE_DECL from TEMPLATE_TEMPLATE_PARM node.  */
    if (is_tmpl_type && TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
      arg = TYPE_STUB_DECL (arg);
  
    is_type = TYPE_P (arg) || is_tmpl_type;
  
diff -cprN gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/ttp41.C gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/ttp41.C
*** gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/ttp41.C	Thu Dec 17 05:01:57 1998
--- gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/ttp41.C	Wed Jul 11 21:13:31 2001
*************** template<class T> class D
*** 12,23 ****
  
  template<class T> int D<T>::f()
  {
! 	C<D,D> c;
! 	return c.g();
  }
  
  int main()
  {
  	D<char> d;
! 	d.f();
  }
--- 12,23 ----
  
  template<class T> int D<T>::f()
  {
! 	C<D,D> c;		// ERROR - illegal
! 	return c.g();		// ERROR - ref above
  }
  
  int main()
  {
  	D<char> d;
! 	d.f();			// ERROR - ref above
  }
diff -cprN gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/ttp43.C gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/ttp43.C
*** gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/ttp43.C	Thu Dec 17 05:01:59 1998
--- gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/ttp43.C	Thu Jul  5 23:57:29 2001
*************** struct Lit {
*** 20,30 ****
  
  template < class T >
  struct Id {
!   Add < T, Id, Lit > operator+(const T& t) const {
!     return Add < T, Id, Lit >(*this, Lit<T>(t));
    }
  
!   Mul < T, Id, Lit > operator*(const T& t) const {
!     return Mul < T, Id, Lit >(*this, Lit<T>(t));
    }
  };
--- 20,30 ----
  
  template < class T >
  struct Id {
!   Add < T, ::Id, Lit > operator+(const T& t) const {
!     return Add < T, ::Id, Lit >(*this, Lit<T>(t));
    }
  
!   Mul < T, ::Id, Lit > operator*(const T& t) const {
!     return Mul < T, ::Id, Lit >(*this, Lit<T>(t));
    }
  };
diff -cprN gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/ttp44.C gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/ttp44.C
*** gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/ttp44.C	Thu Dec 17 05:02:00 1998
--- gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/ttp44.C	Thu Jul  5 23:57:35 2001
*************** public:
*** 9,16 ****
  template < class T >
  struct Id {
    template < template < class > class E >
!   Add < T, Id, E > operator+(const E<T>& e) const {
!     return Add < T, Id, E >(*this, e);
    }
  };
  
--- 9,16 ----
  template < class T >
  struct Id {
    template < template < class > class E >
!   Add < T, ::Id, E > operator+(const E<T>& e) const {
!     return Add < T, ::Id, E >(*this, e);
    }
  };
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]