This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for infinite recursion with implicit typename
- To: egcs-patches at cygnus dot com
- Subject: C++ PATCH for infinite recursion with implicit typename
- From: Mark Mitchell <mark at markmitchell dot com>
- Date: Thu, 15 Oct 1998 11:32:26 -0700
- Cc: Jason Merrill <jason at cygnus dot com>
- Reply-to: mark at markmitchell dot com
The infamous :-) implicit typename extension struck again, causing an
infinite recursion on this code:
template <class T>
struct B {
typedef T X;
};
template <class T>
struct S : public B<T>
{
struct I {
void f(X x);
};
};
When looking for `X' we called make_typename_type for S<T>::X, which
called lookup_field, which called make_typename_type...
If lookup_field can't find the type, there's no need to go through
make_typename_type since we already know we can't find the type
itself.
--
Mark Mitchell mark@markmitchell.com
Mark Mitchell Consulting http://www.markmitchell.com
1998-10-15 Mark Mitchell <mark@markmitchell.com>
* cp-tree.def (TYPENAME_TYPE): Add to documentation.
* cp-tree.h (TYPENAME_TYPE_FULLNAME): Document.
(build_typename_type): New function.
* decl.c (build_typename_type): Broken out from ...
(make_typename_type): Use it.
* search.c (lookup_field): Likewise.
Index: typename14.C
===================================================================
RCS file: typename14.C
diff -N typename14.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- typename14.C Thu Oct 15 11:01:48 1998
***************
*** 0 ****
--- 1,15 ----
+ // Build don't link:
+ // Special g++ Options:
+
+ template <class T>
+ struct B {
+ typedef T X;
+ };
+
+ template <class T>
+ struct S : public B<T>
+ {
+ struct I {
+ void f(X x);
+ };
+ };
Index: cp-tree.def
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.def,v
retrieving revision 1.20
diff -c -p -r1.20 cp-tree.def
*** cp-tree.def 1998/10/06 14:19:46 1.20
--- cp-tree.def 1998/10/15 17:47:34
*************** DEFTREECODE (TEMPLATE_TYPE_PARM, "templa
*** 143,149 ****
The TYPE_FIELDS value will be a TEMPLATE_PARM_INDEX. */
DEFTREECODE (TEMPLATE_TEMPLATE_PARM, "template_template_parm", 't', 0)
! /* A type designated by 'typename T::t'. */
DEFTREECODE (TYPENAME_TYPE, "typename_type", 't', 0)
/* A thunk is a stub function.
--- 143,152 ----
The TYPE_FIELDS value will be a TEMPLATE_PARM_INDEX. */
DEFTREECODE (TEMPLATE_TEMPLATE_PARM, "template_template_parm", 't', 0)
! /* A type designated by `typename T::t'. TYPE_CONTEXT is `T',
! TYPE_NAME is a TYPE_DECL for `t'. If TREE_TYPE is present, this
! type was generated by the implicit typename extension, and the
! TREE_TYPE is a _TYPE from a baseclass of `T'. */
DEFTREECODE (TYPENAME_TYPE, "typename_type", 't', 0)
/* A thunk is a stub function.
Index: cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.152
diff -c -p -r1.152 cp-tree.h
*** cp-tree.h 1998/10/13 14:34:21 1.152
--- cp-tree.h 1998/10/15 17:47:46
*************** struct lang_decl
*** 1337,1342 ****
--- 1337,1346 ----
&& !CLASSTYPE_USE_TEMPLATE (NODE) \
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE)))
+ /* The name used by the user to name the typename type. Typically,
+ this is an IDENTIFIER_NODE, and the same as the DECL_NAME on the
+ corresponding TYPE_DECL. However, this may also be a
+ TEMPLATE_ID_EXPR if we had something like `typename X::Y<T>'. */
#define TYPENAME_TYPE_FULLNAME(NODE) CLASSTYPE_SIZE (NODE)
/* Nonzero in INTEGER_CST means that this int is negative by dint of
*************** extern tree binding_for_name
*** 2543,2548 ****
--- 2547,2553 ----
extern tree namespace_binding PROTO((tree, tree));
extern void set_namespace_binding PROTO((tree, tree, tree));
extern tree lookup_namespace_name PROTO((tree, tree));
+ extern tree build_typename_type PROTO((tree, tree, tree, tree));
extern tree make_typename_type PROTO((tree, tree));
extern tree lookup_name_nonclass PROTO((tree));
extern tree lookup_function_nonclass PROTO((tree, tree));
Index: decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.230
diff -c -p -r1.230 decl.c
*** decl.c 1998/10/14 21:16:37 1.230
--- decl.c 1998/10/15 17:48:29
*************** lookup_namespace_name (namespace, name)
*** 4776,4786 ****
return error_mark_node;
}
tree
make_typename_type (context, name)
tree context, name;
{
! tree t, d;
tree fullname;
if (TREE_CODE_CLASS (TREE_CODE (name)) == 't')
--- 4776,4826 ----
return error_mark_node;
}
+ /* Build a TYPENAME_TYPE. If the type is `typename T::t', CONTEXT is
+ the type of `T', NAME is the IDENTIFIER_NODE for `t'. If BASE_TYPE
+ is non-NULL, this type is being created by the implicit typename
+ extension, and BASE_TYPE is a type named `t' in some base class of
+ `T' which depends on template parameters.
+
+ Returns the new TYPENAME_TYPE. */
+
tree
+ build_typename_type (context, name, fullname, base_type)
+ tree context;
+ tree name;
+ tree fullname;
+ tree base_type;
+ {
+ tree t;
+ tree d;
+
+ if (processing_template_decl)
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+
+ /* Build the TYPENAME_TYPE. */
+ t = make_lang_type (TYPENAME_TYPE);
+ TYPE_CONTEXT (t) = FROB_CONTEXT (context);
+ TYPENAME_TYPE_FULLNAME (t) = fullname;
+ TREE_TYPE (t) = base_type;
+ CLASSTYPE_GOT_SEMICOLON (t) = 1;
+
+ /* Build the corresponding TYPE_DECL. */
+ d = build_decl (TYPE_DECL, name, t);
+ TYPE_NAME (TREE_TYPE (d)) = d;
+ TYPE_STUB_DECL (TREE_TYPE (d)) = d;
+ DECL_CONTEXT (d) = FROB_CONTEXT (context);
+
+ if (processing_template_decl)
+ pop_obstacks ();
+
+ return t;
+ }
+
+ tree
make_typename_type (context, name)
tree context, name;
{
! tree t;
tree fullname;
if (TREE_CODE_CLASS (TREE_CODE (name)) == 't')
*************** make_typename_type (context, name)
*** 4846,4867 ****
return TREE_TYPE (t);
}
}
!
! if (processing_template_decl)
! push_obstacks (&permanent_obstack, &permanent_obstack);
! t = make_lang_type (TYPENAME_TYPE);
! TYPENAME_TYPE_FULLNAME (t) = fullname;
! d = build_decl (TYPE_DECL, name, t);
! if (processing_template_decl)
! pop_obstacks ();
!
! TYPE_CONTEXT (t) = FROB_CONTEXT (context);
! TYPE_NAME (TREE_TYPE (d)) = d;
! TYPE_STUB_DECL (TREE_TYPE (d)) = d;
! DECL_CONTEXT (d) = FROB_CONTEXT (context);
! CLASSTYPE_GOT_SEMICOLON (t) = 1;
!
! return t;
}
/* Select the right _DECL from multiple choices. */
--- 4886,4893 ----
return TREE_TYPE (t);
}
}
!
! return build_typename_type (context, name, fullname, NULL_TREE);
}
/* Select the right _DECL from multiple choices. */
Index: search.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/search.c,v
retrieving revision 1.59
diff -c -p -r1.59 search.c
*** search.c 1998/10/13 14:34:24 1.59
--- search.c 1998/10/15 18:24:44
*************** lookup_field (xbasetype, name, protect,
*** 1178,1184 ****
rval = error_mark_node;
}
! /* Do implicit typename stuff. */
if (rval && TREE_CODE (rval) == TYPE_DECL
&& processing_template_decl
&& ! currently_open_class (BINFO_TYPE (rval_binfo))
--- 1178,1191 ----
rval = error_mark_node;
}
! /* Do implicit typename stuff. This code also handles out-of-class
! definitions of nested classes whose enclosing class is a
! template. For example:
!
! template <class T> struct S { struct I { void f(); }; };
! template <class T> void S<T>::I::f() {}
!
! will come through here to handle `S<T>::I'. */
if (rval && TREE_CODE (rval) == TYPE_DECL
&& processing_template_decl
&& ! currently_open_class (BINFO_TYPE (rval_binfo))
*************** lookup_field (xbasetype, name, protect,
*** 1191,1199 ****
== current_class_type))
break;
! entry = make_typename_type (BINFO_TYPE (binfo), name);
! TREE_TYPE (entry) = TREE_TYPE (rval);
! rval = TYPE_MAIN_DECL (entry);
}
return rval;
--- 1198,1206 ----
== current_class_type))
break;
! entry = build_typename_type (BINFO_TYPE (binfo), name, name,
! TREE_TYPE (rval));
! return TYPE_STUB_DECL (entry);
}
return rval;