OSDN Git Service

Get ready for garbage collection.
[pf3gnuchains/gcc-fork.git] / gcc / cp / repo.c
1 /* Code to maintain a C++ template repository.
2    Copyright (C) 1995, 96-97, 1998 Free Software Foundation, Inc.
3    Contributed by Jason Merrill (jason@cygnus.com)
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 /* My strategy here is as follows:
23
24    Everything should be emitted in a translation unit where it is used.
25    The results of the automatic process should be easily reproducible with
26    explicit code.  */
27
28 #include "config.h"
29 #include "system.h"
30 #include "tree.h"
31 #include "cp-tree.h"
32 #include "input.h"
33 #include "obstack.h"
34 #include "toplev.h"
35 #include "ggc.h"
36
37 static tree repo_get_id PROTO((tree));
38 static char *extract_string PROTO((char **));
39 static char *get_base_filename PROTO((const char *));
40 static void open_repo_file PROTO((const char *));
41 static char *afgets PROTO((FILE *));
42 static void reopen_repo_file_for_write PROTO((void));
43
44 static tree pending_repo;
45 static tree original_repo;
46 static char *repo_name;
47 static FILE *repo_file;
48
49 static char *old_args, *old_dir, *old_main;
50
51 extern int flag_use_repository;
52 extern struct obstack temporary_obstack;
53 extern struct obstack permanent_obstack;
54
55 #define IDENTIFIER_REPO_USED(NODE)   (TREE_LANG_FLAG_3 (NODE))
56 #define IDENTIFIER_REPO_CHOSEN(NODE) (TREE_LANG_FLAG_4 (NODE))
57
58 #if 0
59 /* Record the flags used to compile this translation unit.  */
60
61 void
62 repo_compile_flags (argc, argv)
63      int argc;
64      char **argv;
65 {
66 }
67
68 /* If this template has not been seen before, add a note to the repository
69    saying where the declaration was.  This may be used to find the
70    definition at link time.  */
71
72 void
73 repo_template_declared (t)
74      tree t;
75 {}
76
77 /* Note where the definition of a template lives so that instantiations can
78    be generated later.  */
79
80 void
81 repo_template_defined (t)
82      tree t;
83 {}
84
85 /* Note where the definition of a class lives to that template
86    instantiations can use it.  */
87
88 void
89 repo_class_defined (t)
90      tree t;
91 {}
92 #endif
93
94 static tree
95 repo_get_id (t)
96      tree t;
97 {
98   if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
99     {
100       /* If we're not done setting up the class, we may not have set up
101          the vtable, so going ahead would give the wrong answer.
102          See g++.pt/instantiate4.C.  */
103       if (TYPE_SIZE (t) == NULL_TREE || TYPE_BEING_DEFINED (t))
104         my_friendly_abort (981113);
105
106       t = TYPE_BINFO_VTABLE (t);
107       if (t == NULL_TREE)
108         return t;
109     }
110   return DECL_ASSEMBLER_NAME (t);
111 }
112
113 /* Note that a template has been used.  If we can see the definition, offer
114    to emit it.  */
115
116 void
117 repo_template_used (t)
118      tree t;
119 {
120   tree id;
121
122   if (! flag_use_repository)
123     return;
124
125   id = repo_get_id (t);
126   if (id == NULL_TREE)
127     return;
128   
129   if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
130     {
131       if (IDENTIFIER_REPO_CHOSEN (id))
132         mark_class_instantiated (t, 0);
133     }
134   else if (TREE_CODE_CLASS (TREE_CODE (t)) == 'd')
135     {
136       if (IDENTIFIER_REPO_CHOSEN (id))
137         mark_decl_instantiated (t, 0);
138     }
139   else
140     my_friendly_abort (1);
141
142   if (! IDENTIFIER_REPO_USED (id))
143     {
144       IDENTIFIER_REPO_USED (id) = 1;
145       pending_repo = perm_tree_cons (NULL_TREE, id, pending_repo);
146     }
147 }
148
149 #if 0
150 /* Note that the vtable for a class has been used, and offer to emit it.  */
151
152 static void
153 repo_vtable_used (t)
154      tree t;
155 {
156   if (! flag_use_repository)
157     return;
158
159   pending_repo = perm_tree_cons (NULL_TREE, t, pending_repo);
160 }
161
162 /* Note that an inline with external linkage has been used, and offer to
163    emit it.  */
164
165 void
166 repo_inline_used (fn)
167      tree fn;
168 {
169   if (! flag_use_repository)
170     return;
171
172   /* Member functions of polymorphic classes go with their vtables.  */
173   if (DECL_FUNCTION_MEMBER_P (fn) && TYPE_VIRTUAL_P (DECL_CLASS_CONTEXT (fn)))
174     {
175       repo_vtable_used (DECL_CLASS_CONTEXT (fn));
176       return;
177     }
178
179   pending_repo = perm_tree_cons (NULL_TREE, fn, pending_repo);
180 }
181
182 /* Note that a particular typeinfo node has been used, and offer to
183    emit it.  */
184
185 void
186 repo_tinfo_used (ti)
187      tree ti;
188 {
189 }
190 #endif
191
192 void
193 repo_template_instantiated (t, extern_p)
194      tree t;
195      int extern_p;
196 {
197   if (! extern_p)
198     {
199       tree id = repo_get_id (t);
200       if (id)
201         IDENTIFIER_REPO_CHOSEN (id) = 1;
202     }
203 }
204
205 /* Parse a reasonable subset of shell quoting syntax.  */
206
207 static char *
208 extract_string (pp)
209      char **pp;
210 {
211   char *p = *pp;
212   int backquote = 0;
213   int inside = 0;
214
215   for (;;)
216     {
217       char c = *p;
218       if (c == '\0')
219         break;
220       ++p;
221       if (backquote)
222         obstack_1grow (&temporary_obstack, c);
223       else if (! inside && c == ' ')
224         break;
225       else if (! inside && c == '\\')
226         backquote = 1;
227       else if (c == '\'')
228         inside = !inside;
229       else
230         obstack_1grow (&temporary_obstack, c);
231     }
232
233   obstack_1grow (&temporary_obstack, '\0');
234   *pp = p;
235   return obstack_finish (&temporary_obstack);
236 }
237
238 static char *
239 get_base_filename (filename)
240      const char *filename;
241 {
242   char *p = getenv ("COLLECT_GCC_OPTIONS");
243   char *output = NULL;
244   int compiling = 0;
245
246   while (p && *p)
247     {
248       char *q = extract_string (&p);
249
250       if (strcmp (q, "-o") == 0)
251         output = extract_string (&p);
252       else if (strcmp (q, "-c") == 0)
253         compiling = 1;
254       }
255
256   if (compiling && output)
257     return output;
258
259   if (p && ! compiling)
260     {
261       warning ("-frepo must be used with -c");
262       flag_use_repository = 0;
263       return NULL;
264     }
265
266   return file_name_nondirectory (filename);
267 }        
268
269 static void
270 open_repo_file (filename)
271      const char *filename;
272 {
273   register const char *p;
274   const char *s = get_base_filename (filename);
275
276   if (s == NULL)
277     return;
278
279   p = file_name_nondirectory (s);
280   p = rindex (p, '.');
281   if (! p)
282     p = s + strlen (s);
283
284   obstack_grow (&permanent_obstack, s, p - s);
285   repo_name = obstack_copy0 (&permanent_obstack, ".rpo", 4);
286
287   repo_file = fopen (repo_name, "r");
288 }
289
290 static char *
291 afgets (stream)
292      FILE *stream;
293 {
294   int c;
295   while ((c = getc (stream)) != EOF && c != '\n')
296     obstack_1grow (&temporary_obstack, c);
297   if (obstack_object_size (&temporary_obstack) == 0)
298     return NULL;
299   obstack_1grow (&temporary_obstack, '\0');
300   return obstack_finish (&temporary_obstack);
301 }
302
303 void
304 init_repo (filename)
305      const char *filename;
306 {
307   char *buf;
308
309   if (! flag_use_repository)
310     return;
311
312   ggc_add_tree_root (&pending_repo, 1);
313   ggc_add_tree_root (&original_repo, 1);
314
315   open_repo_file (filename);
316
317   if (repo_file == 0)
318     return;
319
320   while ((buf = afgets (repo_file)))
321     {
322       switch (buf[0])
323         {
324         case 'A':
325           old_args = obstack_copy0 (&permanent_obstack, buf + 2,
326                                     strlen (buf + 2));
327           break;
328         case 'D':
329           old_dir = obstack_copy0 (&permanent_obstack, buf + 2,
330                                    strlen (buf + 2));
331           break;
332         case 'M':
333           old_main = obstack_copy0 (&permanent_obstack, buf + 2,
334                                     strlen (buf + 2));
335           break;
336         case 'C':
337         case 'O':
338           {
339             tree id = get_identifier (buf + 2);
340             tree orig;
341
342             if (buf[0] == 'C')
343               {
344                 IDENTIFIER_REPO_CHOSEN (id) = 1;
345                 orig = integer_one_node;
346               }
347             else
348               orig = NULL_TREE;
349
350             original_repo = perm_tree_cons (orig, id, original_repo);
351           }
352           break;
353         default:
354           error ("mysterious repository information in %s", repo_name);
355         }
356       obstack_free (&temporary_obstack, buf);
357     }
358 }
359
360 static void
361 reopen_repo_file_for_write ()
362 {
363   if (repo_file)
364     fclose (repo_file);
365   repo_file = fopen (repo_name, "w");
366
367   if (repo_file == 0)
368     {
369       error ("can't create repository information file `%s'", repo_name);
370       flag_use_repository = 0;
371     }
372 }
373
374 /* Emit any pending repos.  */
375
376 void
377 finish_repo ()
378 {
379   tree t;
380   int repo_changed = 0;
381   char *dir, *args;
382
383   if (! flag_use_repository)
384     return;
385
386   /* Do we have to write out a new info file?  */
387
388   /* Are there any old templates that aren't used any longer or that are
389      newly chosen?  */
390   
391   for (t = original_repo; t; t = TREE_CHAIN (t))
392     {
393       if (! IDENTIFIER_REPO_USED (TREE_VALUE (t))
394           || (! TREE_PURPOSE (t) && IDENTIFIER_REPO_CHOSEN (TREE_VALUE (t))))
395         {
396           repo_changed = 1;
397           break;
398         }
399       IDENTIFIER_REPO_USED (TREE_VALUE (t)) = 0;
400     }
401
402   /* Are there any templates that are newly used?  */
403   
404   if (! repo_changed)
405     for (t = pending_repo; t; t = TREE_CHAIN (t))
406       {
407         if (IDENTIFIER_REPO_USED (TREE_VALUE (t)))
408           {
409             repo_changed = 1;
410             break;
411           }
412       }
413
414   dir = getpwd ();
415   args = getenv ("COLLECT_GCC_OPTIONS");
416
417   if (! repo_changed && pending_repo)
418     if (strcmp (old_main, main_input_filename) != 0
419         || strcmp (old_dir, dir) != 0
420         || (args == NULL) != (old_args == NULL)
421         || (args && strcmp (old_args, args) != 0))
422       repo_changed = 1;
423
424   if (! repo_changed || errorcount || sorrycount)
425     goto out;
426
427   reopen_repo_file_for_write ();
428
429   if (repo_file == 0)
430     goto out;
431
432   fprintf (repo_file, "M %s\n", main_input_filename);
433   fprintf (repo_file, "D %s\n", dir);
434   if (args)
435     fprintf (repo_file, "A %s\n", args);
436
437   for (t = pending_repo; t; t = TREE_CHAIN (t))
438     {
439       tree val = TREE_VALUE (t);
440       char type = IDENTIFIER_REPO_CHOSEN (val) ? 'C' : 'O';
441
442       fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (val));
443     }
444
445  out:
446   if (repo_file)
447     fclose (repo_file);
448 }