home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / mnl-rpc++-2.3.1 / part01 / gcc-2.3.3.fix < prev    next >
Encoding:
Text File  |  1993-04-24  |  7.5 KB  |  230 lines

  1. There are two bugs in gcc-2.3.3 that I have reported together with
  2. fixes for gcc-2.2.2 previously.  The first bug is commented now (but
  3. not fixed), the second isn't fixed either (I can understand that.  It
  4. is hard to do it properly).  I'm repeating the bug report below
  5. together with new context diffs.  Please note that I have not
  6. re-debugged, I have simply found that the same patches make things
  7. work.  So maybe the comments are out of date.
  8.  
  9. Bug1:
  10.  
  11. Compiling this
  12. --------------------------------------------------
  13. // -*- c++ -*-
  14.  
  15. class AnyRpcCallback
  16. {
  17. protected:
  18.  
  19. public:
  20.   inline virtual ~AnyRpcCallback () {}
  21.   inline virtual void Do (void* in, void* out) = 0;
  22. };
  23.  
  24. template<class T> class RpcCallback : public AnyRpcCallback
  25. {
  26.   typedef void (T::*Method)(void*, void*);
  27.  
  28. private:
  29.   T* object;
  30.   void (T::*method)(void*, void*);
  31.  
  32. public:
  33.   inline RpcCallback (T* o, void* m)
  34.     { object = o; method = m; }
  35.   inline void Do (void* in, void* out)
  36.     { (object->*method)(in, out); }
  37. };
  38.  
  39. class Test
  40. {
  41. public:
  42.   void m (void*, void*);
  43. };
  44.  
  45. void Test::m (void*, void*)
  46. {
  47. }
  48.  
  49. main ()
  50. {
  51.   Test o;
  52.   AnyRpcCallback* cb = new RpcCallback<Test> (&o, &Test::m);
  53. }
  54. --------------------------------------------------
  55. results in cc1plus looping infinitely.
  56.  
  57. I tracked the cause down: grokdeclarator does a pushlevel(0), then
  58. calls start_decl, which in turn calls grokdeclarator again which does
  59. a poplevel_class. This poplevel_class pops the level pushed by
  60. pushlevel(0) and so the poplevel performed by grokdeclarator to match
  61. its pushlevel(0) pops quite a different level! This can easily be
  62. observed by compiling cp-decl.c with -DDEBUG_CP_BINDING_LEVELS.
  63.  
  64. In gcc-2.3.3 the problem seems to be known as it is commented.
  65.  
  66. Here is a patch that fixes the bug. I don't think it hits the real
  67. cause of this problem, but it works.
  68.  
  69. *** cp-decl.c.orig    Sat Jan  2 15:04:20 1993
  70. --- cp-decl.c    Sat Jan  2 15:06:18 1993
  71. ***************
  72. *** 7245,7253 ****
  73. --- 7245,7260 ----
  74.         tree loc_typedecl;
  75.         register int i = sizeof (struct lang_decl_flags) / sizeof (int);
  76.         register int *pi;
  77. +        struct binding_level *local_binding_level;
  78.   
  79.         /* keep `grokdeclarator' from thinking we are in PARM context.  */
  80.         pushlevel (0);
  81. +        /* poplevel_class may be called by grokdeclarator which is called in
  82. +           start_decl which is called below. In this case, our pushed level
  83. +           may vanish and poplevel mustn't be called. So remember what we
  84. +           have pushed and pop only if that is matched by 
  85. +           current_binding_level later. mnl@dtro.e-technik.th-darmstadt.de */
  86. +        local_binding_level = current_binding_level;
  87.         loc_typedecl = start_decl (declarator, declspecs, initialized, NULL_TREE);
  88.   
  89.         pi = (int *) permalloc (sizeof (struct lang_decl_flags));
  90. ***************
  91. *** 7256,7262 ****
  92.         DECL_LANG_SPECIFIC (loc_typedecl) = (struct lang_decl *) pi;
  93.         /* This poplevel conflicts with the popclass over in
  94.            grokdeclarator.  See ``This popclass conflicts'' */
  95. !       poplevel (0, 0, 0);
  96.   
  97.   #if 0
  98.         if (TREE_CODE (TREE_TYPE (loc_typedecl)) == ENUMERAL_TYPE)
  99. --- 7263,7270 ----
  100.         DECL_LANG_SPECIFIC (loc_typedecl) = (struct lang_decl *) pi;
  101.         /* This poplevel conflicts with the popclass over in
  102.            grokdeclarator.  See ``This popclass conflicts'' */
  103. !        if (current_binding_level == local_binding_level)
  104. !         poplevel (0, 0, 0);
  105.   
  106.   #if 0
  107.         if (TREE_CODE (TREE_TYPE (loc_typedecl)) == ENUMERAL_TYPE)
  108.  
  109. Bug2:
  110.  
  111. Compiling this
  112. --------------------------------------------------
  113. // -*- c++ -*-
  114.  
  115. class AnyRpcCallback
  116. {
  117. protected:
  118.  
  119. public:
  120.   inline virtual ~AnyRpcCallback () {}
  121.   inline virtual void Do (void* in, void* out) = 0;
  122. };
  123.  
  124. template<class T> class RpcCallback : public AnyRpcCallback
  125. {
  126.   typedef void (T::*Method)(void*, void*);
  127.   typedef void (T::*MethodN)(void*, void**);
  128.   typedef void (T::*Method1)(void*, void*);
  129.   typedef void (T::*Method2)(void*, void*, void*);
  130.  
  131. private:
  132.   T* object;
  133.   void (T::*method)(void*, void*);
  134.  
  135. public:
  136.   inline RpcCallback (T* o, void* m)
  137.     { object = o; method = m; }
  138.   inline void Do (void* in, void* out)
  139.     { (object->*method)(in, out); }
  140. };
  141.  
  142. class Test
  143. {
  144. public:
  145.   void m (void*, void*);
  146. };
  147.  
  148. main ()
  149. {
  150.   Test o;
  151.   AnyRpcCallback* cb = new RpcCallback<Test> (&o, &Test::m);
  152. }
  153. --------------------------------------------------
  154. results in cc1plus looping infinitely.
  155.  
  156. The problem is that the "chain" field of the tree-nodes used by gcc
  157. for its internal representation is used for various purposes, and in
  158. the case of this template-local typedef, someone lost track of its usage.
  159.  
  160. After parsing, the TYPE_DECL-node created for the typedef is appended
  161. to the scope via "pushlevel". Types in the current scope are linked
  162. using the "chain" field. At the same time, however, all components of
  163. the template are linked together during parsing using the same "chain"
  164. field. Parsing the second typedef, "pushlevel" makes the first typedef
  165. a successor of the second typedef and the subsequent catenation of
  166. components makes the second typedef a successor of the first typedef
  167. thus creating a loop.
  168.  
  169. The resulting list of all components is used in routine
  170. "finish_struct".
  171.  
  172. I think the most proper approach would be to use TREE_LIST nodes in
  173. the list of components as indirect references to the typedef-nodes.
  174. This is easy to achieve, it is, however, very hard to modify
  175. finish_struct in a way that it handles these indirection properly.
  176. Actually, I gave up when I tried to understand & modify the routine
  177. that removes the duplicate declarations from the list of components.
  178.  
  179. There are two easier approaches: (1) Don't include typedefs in the
  180. list of components, (2) use copies of the typedef-node which have an
  181. unused chain field. The first approach assumes that finish_struct
  182. doesn't do anything with typedefs, so it wouldn't be important if they
  183. are missing from the list of components. If this is the case, however,
  184. it can't hurt to use copies of the typedef-nodes (copies of the
  185. originals that are linked in the scope-list), so the second approach
  186. is safer. It can only fail if finish_struct modifies the typedef-nodes
  187. and this modification is significant for the typedef-nodes in the
  188. scope-list (which are, of course, not modified. Only the copies are).
  189.  
  190. So I think the patch is pretty safe. It fixes the problem and doesn't
  191. seem to introduce new ones. I'm aware that typedefs that are local to
  192. templates stretch language features to the limits, but it makes my
  193. C++ interface to RPCs real nice.
  194.  
  195. *** cp-parse.y.orig    Sat Jan  2 15:17:13 1993
  196. --- cp-parse.y    Sat Jan  2 15:18:13 1993
  197. ***************
  198. *** 2335,2341 ****
  199.                 if (TREE_CODE (t) == ENUMERAL_TYPE && TREE_NONLOCAL_FLAG (t))
  200.               $$ = grok_enum_decls (t, $2);
  201.                 else
  202. !             $$ = $2;
  203.               }
  204.             end_exception_decls ();
  205.           }
  206. --- 2335,2357 ----
  207.                 if (TREE_CODE (t) == ENUMERAL_TYPE && TREE_NONLOCAL_FLAG (t))
  208.               $$ = grok_enum_decls (t, $2);
  209.                 else
  210. !             {
  211. !                /* if a component is a typedef, it is inserted
  212. !                   in the list of nodes that make up the valid
  213. !                   types in the scope. Thus its chain field is
  214. !                   used and can't be used a second time for linking
  215. !                   the components of the struct. So, we make a copy
  216. !                   here. This apparently works. The proper thing
  217. !                   to do, however, would be to use a TREE_LIST
  218. !                   node to reference the typedef. I tried to rewrite
  219. !                   finish_struct accordingly (i.e., ``dereference''
  220. !                   components TREE_LIST before use, but I gave up.
  221. !                   mnl@dtro.e-technik.th-darmstadt.de */
  222. !                if (TREE_CODE ($2) == TYPE_DECL)
  223. !                  $$ = copy_node ($2);
  224. !                else
  225. !                 $$ = $2;
  226. !             }
  227.               }
  228.             end_exception_decls ();
  229.           }
  230.