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