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]
Other format: [Raw text]

[C++ PATCH] Fix PR8442, 8591, 8806


Hi

The following patch fixes template vs class issues reported in PR
8442 (ICE for unqualified name), 8591 (ICE for qualified name) and 
8806 (non-standard template argument matching behavior).  I decide
to put these together in the same patch since the problems lies in
the function 'cp_parser_elaborated_type_specifier' itself or those
called by this function.

For PR8442 (a regression, I have fixed this on 3.2/3.3 branches):
The problem is due to 'xref_tag' doesn't check if the name lookup
incorrectly finds a template.  GCC then tries to layout this template
later even its template parameters are left unsubstituted.  In correct
usages are now detected by this patch.  I also have to undo the
changes (made by Nathan when fixing PR5213) in 
'convert_template_argument' to restore the correct specialization 
behavior.

For PR8591 (a regression from 2.95, also already fixed on 3.2/3.3):
This is due to 'cp_parser_elaborated_type_specifier'.  We convert
TEMPLATE_DECL to TYPE_DECL even though we are not processing template
friend.  A test inside 'cp_parser_maybe_treat_template_as_class' is
redundant there and is eliminated.

For PR8806 (not a regression):
This is a non-standard template argument matching where we allow
a class name as a valid template template argument.  The changes
touch the same part of 'convert_template_argument' so I decide to fix
this at the same time.  'is_base_of_enclosing_class' function 
becomes no longer useful and removed.  The changed behavior is 
documented in the NEWS file.

Bootstrapped and tested on i686-pc-linux-gnu with no regression.
OK for the main trunk?

--Kriang


2003-01-27  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	PR c++/8591
	* parser.c (cp_parser_elaborated_type_specifier): Convert
	TEMPLATE_DECL to TYPE_DECL only when processing template friends.
	(cp_parser_maybe_treat_template_as_class): Remove redundant tests.

	PR c++/8442, c++/8806
	* pt.c (convert_template_argument): Don't accept RECORD_TYPE as
	template template argument.
	* decl.c (xref_tag): Issue diagnostic when name lookup finds a
	template instead of a class.
	* class.c (is_base_of_enclosing_class): Remove.
	* cp-tree.h (is_base_of_enclosing_class): Likewise.
	* NEWS: Update template template argument change.

2003-01-27  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	PR c++/8442
	* g++.dg/template/type2.C: Likewise.
	* g++.dg/template/ttp3.C: Change error message.  Remove XFAIL's.
	* g++.old-deja/g++.law/visibility13.C: Change error message.

	PR c++/8591
	* g++.dg/parse/friend2.C: New test.

	PR c++/8806
	* g++.old-deja/g++.pt/ttp41.C: Expect error message.
	* g++.old-deja/g++.pt/ttp43.C: Use qualified name for template
	template arguments.
	* g++.old-deja/g++.pt/ttp44.C: Likewise.

diff -cprN gcc-main-save/gcc/cp/NEWS gcc-main-new/gcc/cp/NEWS
*** gcc-main-save/gcc/cp/NEWS	Sat Dec 28 21:50:04 2002
--- gcc-main-new/gcc/cp/NEWS	Mon Jan 27 00:58:27 2003
***************
*** 70,75 ****
--- 70,88 ----
  
      X x __attribute__((...)) (1);
  
+ * Inside the scope of a template class, the name of the class itself
+   is no longer a valid template template argument.  Instead, you now have
+   to qualify the name by its scope.  For example:
+ 
+     template <template <class> class TT> class X {};
+     template <class T> class Y {
+       X<Y> x; // Invalid.
+     };
+ 
+   The valid code for the above example is:
+ 
+       X< ::Y> x; // Valid.  Note that `<:' is a digraph and means `['.
+ 
  *** Changes in GCC 3.3:
  
  * The "new X = 3" extension has been removed; you must now use "new X(3)".
diff -cprN gcc-main-save/gcc/cp/class.c gcc-main-new/gcc/cp/class.c
*** gcc-main-save/gcc/cp/class.c	Fri Jan 24 23:01:40 2003
--- gcc-main-new/gcc/cp/class.c	Mon Jan 27 01:02:55 2003
*************** get_enclosing_class (tree type)
*** 6639,6659 ****
    return NULL_TREE;
  }
  
- /* Return 1 if TYPE or one of its enclosing classes is derived from BASE.  */
- 
- int
- is_base_of_enclosing_class (tree base, tree type)
- {
-   while (type)
-     {
-       if (lookup_base (type, base, ba_any, NULL))
- 	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.  */
  
--- 6639,6644 ----
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	Sun Jan 26 22:44:42 2003
--- gcc-main-new/gcc/cp/cp-tree.h	Mon Jan 27 01:02:54 2003
*************** extern int same_signature_p			(tree, tre
*** 3663,3669 ****
  extern void warn_hidden				(tree);
  extern void maybe_add_class_template_decl_list	(tree, tree, int);
  extern tree get_enclosing_class			(tree);
- int is_base_of_enclosing_class			(tree, tree);
  extern void unreverse_member_declarations       (tree);
  extern void invalidate_class_lookup_cache       (void);
  extern void maybe_note_name_used_in_class       (tree, tree);
--- 3663,3668 ----
diff -cprN gcc-main-save/gcc/cp/decl.c gcc-main-new/gcc/cp/decl.c
*** gcc-main-save/gcc/cp/decl.c	Sat Jan 25 00:01:32 2003
--- gcc-main-new/gcc/cp/decl.c	Mon Jan 27 00:19:07 2003
*************** xref_tag (enum tag_types tag_code, tree 
*** 12701,12707 ****
  		   t, tag_name (tag_code));
  	}
        else
! 	ref = lookup_tag (code, name, b, 0);
  
        if (! ref)
  	{
--- 12701,12718 ----
  		   t, tag_name (tag_code));
  	}
        else
! 	{
! 	  ref = lookup_tag (code, name, b, 0);
! 	  if (ref && TREE_CODE (ref) == RECORD_TYPE
! 	      && CLASSTYPE_TEMPLATE_INFO (ref)
! 	      && !PROCESSING_REAL_TEMPLATE_DECL_P ())
! 	    {
! 	      error ("template argument required for `%s %T'",
! 		     tag_name (tag_code),
! 		     DECL_NAME (CLASSTYPE_TI_TEMPLATE (ref)));
! 	      return error_mark_node;
! 	    }
! 	}
  
        if (! ref)
  	{
*************** xref_tag (enum tag_types tag_code, tree 
*** 12720,12725 ****
--- 12731,12743 ----
  	  if (ref && TREE_CODE (ref) == TYPE_DECL
  	      && TREE_CODE (TREE_TYPE (ref)) == code)
  	    ref = TREE_TYPE (ref);
+ 	  else if (ref && DECL_CLASS_TEMPLATE_P (ref)
+ 		   && !PROCESSING_REAL_TEMPLATE_DECL_P ())
+ 	    {
+ 	      error ("template argument required for `%s %T'",
+ 		     tag_name (tag_code), DECL_NAME (ref));
+ 	      return error_mark_node;
+ 	    }
  	  else
  	    ref = NULL_TREE;
  	}
diff -cprN gcc-main-save/gcc/cp/parser.c gcc-main-new/gcc/cp/parser.c
*** gcc-main-save/gcc/cp/parser.c	Fri Jan 24 23:52:46 2003
--- gcc-main-new/gcc/cp/parser.c	Mon Jan 27 16:57:37 2003
*************** cp_parser_elaborated_type_specifier (cp_
*** 8668,8674 ****
  					/*is_namespace=*/false,
  					/*check_dependency=*/true);
  	  decl = (cp_parser_maybe_treat_template_as_class 
! 		  (decl, /*tag_name_p=*/is_friend));
  
  	  if (TREE_CODE (decl) != TYPE_DECL)
  	    {
--- 8668,8675 ----
  					/*is_namespace=*/false,
  					/*check_dependency=*/true);
  	  decl = (cp_parser_maybe_treat_template_as_class 
! 		  (decl, /*tag_name_p=*/is_friend
! 			 && parser->num_template_parameter_lists));
  
  	  if (TREE_CODE (decl) != TYPE_DECL)
  	    {
*************** cp_parser_resolve_typename_type (cp_pars
*** 13220,13237 ****
  static tree
  cp_parser_maybe_treat_template_as_class (tree decl, bool tag_name_p)
  {
!   /* If the DECL is a TEMPLATE_DECL for a class type, and we are in
!      the scope of the class, then treat the TEMPLATE_DECL as a
!      class-name.  For example, in:
! 
!        template <class T> struct S {
!          S s;
!        };
! 
!      is OK.  
! 
!      If the TEMPLATE_DECL is being declared as part of a class-head,
!      the same translation occurs:
  
         struct A { 
           template <typename T> struct B;
--- 13221,13228 ----
  static tree
  cp_parser_maybe_treat_template_as_class (tree decl, bool tag_name_p)
  {
!   /* If the TEMPLATE_DECL is being declared as part of a class-head,
!      the translation from TEMPLATE_DECL to TYPE_DECL occurs:
  
         struct A { 
           template <typename T> struct B;
*************** cp_parser_maybe_treat_template_as_class 
*** 13247,13258 ****
           template <typename T> friend struct N::X;
         };
  
!      */
!   if (DECL_CLASS_TEMPLATE_P (decl)
!       && (tag_name_p
! 	  || (current_class_type
! 	      && same_type_p (TREE_TYPE (DECL_TEMPLATE_RESULT (decl)),
! 			      current_class_type))))
      return DECL_TEMPLATE_RESULT (decl);
  
    return decl;
--- 13238,13255 ----
           template <typename T> friend struct N::X;
         };
  
!      However, if the DECL refers to a class type, and we are in
!      the scope of the class, then the name lookup automatically
!      finds the TYPE_DECL created by build_self_reference rather
!      than a TEMPLATE_DECL.  For example, in:
! 
!        template <class T> struct S {
!          S s;
!        };
! 
!      there is no need to handle such case.  */
! 
!   if (DECL_CLASS_TEMPLATE_P (decl) && tag_name_p)
      return DECL_TEMPLATE_RESULT (decl);
  
    return decl;
diff -cprN gcc-main-save/gcc/cp/pt.c gcc-main-new/gcc/cp/pt.c
*** gcc-main-save/gcc/cp/pt.c	Fri Jan 24 23:01:41 2003
--- gcc-main-new/gcc/cp/pt.c	Mon Jan 27 00:42:30 2003
*************** convert_template_argument (parm, arg, ar
*** 3447,3479 ****
    requires_type = (TREE_CODE (parm) == TYPE_DECL
  		   || requires_tmpl_type);
  
!   if (TREE_CODE (arg) != RECORD_TYPE)
!     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) == UNBOUND_CLASS_TEMPLATE);
!   else if (CLASSTYPE_TEMPLATE_INFO (arg) && !CLASSTYPE_USE_TEMPLATE (arg)
! 	   && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (arg)))
!     {
!       if (is_base_of_enclosing_class (arg, current_class_type))
! 	/* This is a template name used within the scope of the
! 	   template. It could be the template, or it could be the
! 	   instantiation. Choose whichever makes sense.  */
! 	is_tmpl_type = requires_tmpl_type;
!       else
! 	is_tmpl_type = 1;
!     }
!   else
!     /* It is a non-template class, or a specialization of a template
!        class, or a non-template member of a template class.  */
!     is_tmpl_type = 0;
    
    if (is_tmpl_type
        && (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
  	  || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE))
      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;
  
--- 3447,3461 ----
    requires_type = (TREE_CODE (parm) == TYPE_DECL
  		   || requires_tmpl_type);
  
!   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) == UNBOUND_CLASS_TEMPLATE);
    
    if (is_tmpl_type
        && (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
  	  || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE))
      arg = TYPE_STUB_DECL (arg);
  
    is_type = TYPE_P (arg) || is_tmpl_type;
  
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/parse/friend2.C gcc-main-new/gcc/testsuite/g++.dg/parse/friend2.C
*** gcc-main-save/gcc/testsuite/g++.dg/parse/friend2.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/parse/friend2.C	Mon Jan 27 16:08:35 2003
***************
*** 0 ****
--- 1,16 ----
+ // { dg-do compile }
+ // Origin: <struppi@acm.org>
+ 
+ // PR c++/8591
+ // Template or class detection in friend declaration
+ 
+ namespace NS {
+   template <class T1, class T2, class T3 = int, class T4 = int>
+   struct C {};
+ }
+ 
+ template <class T> class X {
+   friend class NS::C;	// { dg-error "expected|friend" }
+ };
+ 
+ X<int> c;
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/ttp3.C gcc-main-new/gcc/testsuite/g++.dg/template/ttp3.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/ttp3.C	Wed Jan  2 19:44:44 2002
--- gcc-main-new/gcc/testsuite/g++.dg/template/ttp3.C	Mon Jan 27 00:44:13 2003
*************** class OUTER {
*** 14,26 ****
    template <class T>
    class List { };
    
!   vector<class List> data; // { dg-error "type/value mismatch|expected a type|ISO C" "" }
  };
  
  template <class T>
! class List { };			// { dg-bogus "previous declaration" "" { xfail *-*-* } }
  
  // This next line should just do a lookup of 'class List', and then
  // get a type/value mismatch. Instead we try and push 'class List'
  // into the global namespace and get a redeclaration error.
! vector<class List > data;	// { dg-bogus "`struct List' redeclared|type/value mismatch" "" { xfail *-*-* } }
--- 14,26 ----
    template <class T>
    class List { };
    
!   vector<class List> data; // { dg-error "invalid|required|ISO C" "" }
  };
  
  template <class T>
! class List { };
  
  // This next line should just do a lookup of 'class List', and then
  // get a type/value mismatch. Instead we try and push 'class List'
  // into the global namespace and get a redeclaration error.
! vector<class List > data;	// { dg-error "invalid|required|expected" "" }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/type2.C gcc-main-new/gcc/testsuite/g++.dg/template/type2.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/type2.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/type2.C	Mon Jan 27 15:41:52 2003
***************
*** 0 ****
--- 1,16 ----
+ // { dg-do compile }
+ // Origin: Juan Carlos Arevalo-Baeza <jcab@JCABs-Rumblings.com>
+ 
+ // PR c++/8442
+ // Type template parameter incorrectly treated as template template
+ // parameter.
+ 
+ template <typename T> struct A {};
+ 
+ template <typename T> struct B
+ {
+   template <typename U> struct C {};
+   template <typename U> A<C<U> > foo(U);
+ };
+ 
+ B<void> b;
diff -cprN gcc-main-save/gcc/testsuite/g++.old-deja/g++.law/visibility13.C gcc-main-new/gcc/testsuite/g++.old-deja/g++.law/visibility13.C
*** gcc-main-save/gcc/testsuite/g++.old-deja/g++.law/visibility13.C	Fri Jan 17 19:14:21 2003
--- gcc-main-new/gcc/testsuite/g++.old-deja/g++.law/visibility13.C	Mon Jan 27 00:39:55 2003
*************** void Array<Type>::init(const Type *array
*** 65,71 ****
  //     ---------------   Array_RC.h  &&  Array_RC.cc   ----------------
  
  template <class Type>
! class Array_RC : public Array<Type> {// ERROR - previous declaration.*
  public:
      Array_RC(const Type *ar, int sz);
      Type& operator[](int ix);
--- 65,71 ----
  //     ---------------   Array_RC.h  &&  Array_RC.cc   ----------------
  
  template <class Type>
! class Array_RC : public Array<Type> {
  public:
      Array_RC(const Type *ar, int sz);
      Type& operator[](int ix);
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	Mon Jan 27 15:33:35 2003
*************** template<class T> class D
*** 12,19 ****
  
  template<class T> int D<T>::f()
  {
! 	C<D,D> c;
! 	return c.g();
  }
  
  int main()
--- 12,19 ----
  
  template<class T> int D<T>::f()
  {
! 	C<D,D> c;	// ERROR - type mismatch
! 	return c.g();	// ERROR - c not declared
  }
  
  int main()
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	Mon Jan 27 00:59:51 2003
*************** 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	Mon Jan 27 01:00:09 2003
*************** 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]