diff options
author | levine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1996-10-21 21:41:34 +0000 |
---|---|---|
committer | levine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1996-10-21 21:41:34 +0000 |
commit | a5fdebc5f6375078ec1763850a4ca23ec7fe6458 (patch) | |
tree | bcf0a25c3d45a209a6e3ac37b233a4812f29c732 /rpc++/gcc-2.2.fix | |
download | ATCD-a5fdebc5f6375078ec1763850a4ca23ec7fe6458.tar.gz |
Initial revision
Diffstat (limited to 'rpc++/gcc-2.2.fix')
-rw-r--r-- | rpc++/gcc-2.2.fix | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/rpc++/gcc-2.2.fix b/rpc++/gcc-2.2.fix new file mode 100644 index 00000000000..f684e5b128b --- /dev/null +++ b/rpc++/gcc-2.2.fix @@ -0,0 +1,252 @@ +To: bug-g++@prep.ai.mit.edu +Subject: gcc-2.2 loops with template-local typedefs (bug&patch) +BCC: mnl,ulf +--text follows this line-- +Hi, + +trying to translate the following fragment on a Sparc running SunOs 4.1.2 +with gcc-2.2 results in gcc infinitly looping. + +--------------------------------------------------------------------------- +// -*- c++ -*- + +class AnyRpcCallback +{ +protected: + +public: + inline virtual ~AnyRpcCallback () {} + inline virtual void Do (void* in, void* out) = 0; +}; + +template<class T> class RpcCallback : public AnyRpcCallback +{ + typedef void (T::*Method)(void*, void*); + typedef void (T::*MethodN)(void*, void**); + typedef void (T::*Method1)(void*, void*); + typedef void (T::*Method2)(void*, void*, void*); + +private: + T* object; + void (T::*method)(void*, void*); + +public: + inline RpcCallback (T* o, void* m) + { object = o; method = m; } + inline void Do (void* in, void* out) + { (object->*method)(in, out); } +}; + +class Test +{ +public: + void m (void*, void*); +}; + +main () +{ + Test o; + AnyRpcCallback* cb = new RpcCallback<Test> (&o, &Test::m); +} +--------------------------------------------------------------------------- + +PLEASE NOTE that you will get another loop due to a bug that I have +reported together with a patch earlier (it's appended to this mail). +So you won't be able to reproduce the bug reported in this mail unless +you have my previous patch applied. I am, however, definitely sure +(and the explanation below will confirm it) that the bug reported in +this mail is *NOT* caused by my patch! + +The problem is, that the "chain" field of the tree-nodes used by gcc +for its internal representation is used for various purposes, and in +the case of this template-local typedef, someone lost track of its usage. + +After parsing, the TYPE_DECL-node created for the typedef is appended +to the scope via "pushlevel". Types in the current scope are linked +using the "chain" field. At the same time, however, all components of +the template are linked together during parsing using the same "chain" +field. Parsing the second typedef, "pushlevel" makes the first typedef +a successor of the second typedef and the subsequent catenation of +components makes the second typedef a successor of the first typedef +thus creating a loop. + +The resulting list of all components is used in routine +"finish_struct". + +I think the most proper approach would be to use TREE_LIST nodes in +the list of components as indirect references to the typedef-nodes. +This is easy to achieve, it is, however, very hard to modify +finish_struct in a way that it handles these indirection properly. +Actually, I gave up when I tried to understand & modify the routine +that removes the duplicate declarations from the list of components. + +There are two easier approaches: (1) Don't include typedefs in the +list of components, (2) use copies of the typedef-node which have an +unused chain field. The first approach assumes that finish_struct +doesn't do anything with typedefs, so it wouldn't be important if they +are missing from the list of components. If this is the case, however, +it can't hurt to use copies of the typedef-nodes (copies of the +originals that are linked in the scope-list), so the second approach +is safer. It can only fail if finish_struct modifies the typedef-nodes +and this modification is significant for the typedef-nodes in the +scope-list (which are, of course, not modified. Only the copies are). + +So I think the patch is pretty safe. It fixes the problem and doesn't +seem to introduce new ones. I'm aware that typedefs that are local to +templates stretch language features to the limits, but it makes my +C++ interface to RPCs real nice (I'll post it one of these days). + +Michael + +*** .orig/cp-parse.y Mon Jun 15 17:08:58 1992 +--- cp-parse.y Mon Jun 15 19:13:15 1992 +*************** +*** 2211,2217 **** + if (TREE_CODE (t) == ENUMERAL_TYPE && TREE_NONLOCAL_FLAG (t)) + $$ = grok_enum_decls (t, $2); + else +! $$ = $2; + } + end_exception_decls (); + } +--- 2211,2233 ---- + if (TREE_CODE (t) == ENUMERAL_TYPE && TREE_NONLOCAL_FLAG (t)) + $$ = grok_enum_decls (t, $2); + else +! { +! /* if a component is a typedef, it is inserted +! in the list of nodes that make up the valid +! types in the scope. Thus its chain field is +! used and can't be used a second time for linking +! the components of the struct. So, we make a copy +! here. This apparently works. The proper thing +! to do, however, would be to use a TREE_LIST +! node to reference the typedef. I tried to rewrite +! finish_struct accordingly (i.e., ``dereference'' +! components TREE_LIST before use, but I gave up. +! mnl@dtro.e-technik.th-darmstadt.de */ +! if (TREE_CODE ($2) == TYPE_DECL) +! $$ = copy_node ($2); +! else +! $$ = $2; +! } + } + end_exception_decls (); + } + +=========================================================================== +The previous bug: +--------------------------------------------------------------------------- +Return-Path: <mnl> +Date: Wed, 10 Jun 92 19:31:13 +0200 +From: "Michael N. Lipp" <mnl> +To: bug-g++@prep.ai.mit.edu +Subject: gcc-2.2 bug&patch: typedef in template + +Hi, + +gcc-2.2 on a sparc running SunOS 4.1.2 enters an infinite loop when +compiling this: + +----------------------------------------------------------------------------- +// -*- c++ -*- + +class AnyRpcCallback +{ +protected: + +public: + inline virtual ~AnyRpcCallback () {} + inline virtual void Do (void* in, void* out) = 0; +}; + +template<class T> class RpcCallback : public AnyRpcCallback +{ + typedef void (T::*Method)(void*, void*); + +private: + T* object; + void (T::*method)(void*, void*); + +public: + inline RpcCallback (T* o, void* m) + { object = o; method = m; } + inline void Do (void* in, void* out) + { (object->*method)(in, out); } +}; + +class Test +{ +public: + void m (void*, void*); +}; + +main () +{ + Test o; + AnyRpcCallback* cb = new RpcCallback<Test> (&o, &Test::m); +} +----------------------------------------------------------------------------- + +This is quite an improvement over gcc-2.1 which dumped core with this +source. + +I tracked the cause down: grokdeclarator does a pushlevel(0), then +calls start_decl, which in turn calls grokdeclarator again which does +a poplevel_class. This poplevel_class pops the level pushed by +pushlevel(0) and so the poplevel performed by grokdeclarator to match +its pushlevel(0) pops quite a different level! This can easily be +observed by compiling cp-decl.c with -DDEBUG_CP_BINDING_LEVELS. + +Here is a patch that fixes the bug. I don't think it hits the real +cause of this problem, but it works. + +*** .orig/cp-decl.c Wed Jun 10 14:06:26 1992 +--- cp-decl.c Wed Jun 10 15:20:38 1992 +*************** +*** 6874,6882 **** +--- 6874,6889 ---- + tree loc_typedecl; + register int i = sizeof (struct lang_decl_flags) / sizeof (int); + register int *pi; ++ struct binding_level *local_binding_level; + + /* keep `grokdeclarator' from thinking we are in PARM context. */ + pushlevel (0); ++ /* poplevel_class may be called by grokdeclarator which is called in ++ start_decl which is called below. In this case, our pushed level ++ may vanish and poplevel mustn't be called. So remember what we ++ have pushed and pop only if that is matched by ++ current_binding_level later. mnl@dtro.e-technik.th-darmstadt.de */ ++ local_binding_level = current_binding_level; + loc_typedecl = start_decl (declarator, declspecs, initialized, NULL_TREE); + + pi = (int *) permalloc (sizeof (struct lang_decl_flags)); +*************** +*** 6883,6889 **** + while (i > 0) + pi[--i] = 0; + DECL_LANG_SPECIFIC (loc_typedecl) = (struct lang_decl *) pi; +! poplevel (0, 0, 0); + + #if 0 + if (TREE_CODE (TREE_TYPE (loc_typedecl)) == ENUMERAL_TYPE) +--- 6890,6897 ---- + while (i > 0) + pi[--i] = 0; + DECL_LANG_SPECIFIC (loc_typedecl) = (struct lang_decl *) pi; +! if (current_binding_level == local_binding_level) +! poplevel (0, 0, 0); + + #if 0 + if (TREE_CODE (TREE_TYPE (loc_typedecl)) == ENUMERAL_TYPE) + +Michael + +-----------------,------------------------------,------------------------------ +Michael N. Lipp ! Institut fuer Datentechnik ! Phone: 49-6151-163776 + ! Merckstr. 25 ,----------' Fax: 49-6151-164976 + ! D-6100 Darmstadt ! E-Mail: + ! (Germany) ! mnl@dtro.e-technik.th-darmstadt.de +-----------------'-------------------'----------------------------------------- + |