This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH] Fix PR8442, 8591, 8806
- From: Kriang Lerdsuwanakij <lerdsuwa at users dot sourceforge dot net>
- To: <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 27 Jan 2003 17:19:46 +0700 (ICT)
- Subject: [C++ PATCH] Fix PR8442, 8591, 8806
- Reply-to: <lerdsuwa at users dot sourceforge dot net>
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);
}
};