OSDN Git Service

* collect2.c (main, write_c_file_stat), gcc.c (translate_options,
[pf3gnuchains/gcc-fork.git] / gcc / cp / repo.c
1 /* Code to maintain a C++ template repository.
2    Copyright (C) 1995, 1996, 1997, 1998, 2000 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 PARAMS ((tree));
38 static char *extract_string PARAMS ((char **));
39 static char *get_base_filename PARAMS ((const char *));
40 static void open_repo_file PARAMS ((const char *));
41 static char *afgets PARAMS ((FILE *));
42 static void reopen_repo_file_for_write PARAMS ((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 static 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 (TYPE_P (t))
99     {
100       tree vtable;
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 (!COMPLETE_TYPE_P (t) || TYPE_BEING_DEFINED (t))
106         my_friendly_abort (981113);
107
108       vtable = get_vtbl_decl_for_binfo (TYPE_BINFO (t));
109
110       /* If we don't have a primary vtable, try looking for a secondary
111          vtable.  */
112       if (vtable == NULL_TREE && !flag_new_abi
113           && TYPE_USES_VIRTUAL_BASECLASSES (t))
114         {
115           tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
116           int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
117           for (i = 0; i < n_baselinks; ++i)
118             {
119               tree base_binfo = TREE_VEC_ELT (binfos, i);
120               if (TREE_VIA_VIRTUAL (base_binfo))
121                 {
122                   vtable = get_vtbl_decl_for_binfo (base_binfo);
123                   if (vtable)
124                     break;
125                 }
126             }
127         }
128
129       t = vtable;
130       if (t == NULL_TREE)
131         return t;
132     }
133   return DECL_ASSEMBLER_NAME (t);
134 }
135
136 /* Note that a template has been used.  If we can see the definition, offer
137    to emit it.  */
138
139 void
140 repo_template_used (t)
141      tree t;
142 {
143   tree id;
144
145   if (! flag_use_repository)
146     return;
147
148   id = repo_get_id (t);
149   if (id == NULL_TREE)
150     return;
151   
152   if (TYPE_P (t))
153     {
154       if (IDENTIFIER_REPO_CHOSEN (id))
155         mark_class_instantiated (t, 0);
156     }
157   else if (DECL_P (t))
158     {
159       if (IDENTIFIER_REPO_CHOSEN (id))
160         mark_decl_instantiated (t, 0);
161     }
162   else
163     my_friendly_abort (1);
164
165   if (! IDENTIFIER_REPO_USED (id))
166     {
167       IDENTIFIER_REPO_USED (id) = 1;
168       pending_repo = tree_cons (NULL_TREE, id, pending_repo);
169     }
170 }
171
172 #if 0
173 /* Note that the vtable for a class has been used, and offer to emit it.  */
174
175 static void
176 repo_vtable_used (t)
177      tree t;
178 {
179   if (! flag_use_repository)
180     return;
181
182   pending_repo = tree_cons (NULL_TREE, t, pending_repo);
183 }
184
185 /* Note that an inline with external linkage has been used, and offer to
186    emit it.  */
187
188 void
189 repo_inline_used (fn)
190      tree fn;
191 {
192   if (! flag_use_repository)
193     return;
194
195   /* Member functions of polymorphic classes go with their vtables.  */
196   if (DECL_FUNCTION_MEMBER_P (fn) 
197       && TYPE_POLYMORPHIC_P (DECL_CONTEXT (fn)))
198     {
199       repo_vtable_used (DECL_CONTEXT (fn));
200       return;
201     }
202
203   pending_repo = tree_cons (NULL_TREE, fn, pending_repo);
204 }
205
206 /* Note that a particular typeinfo node has been used, and offer to
207    emit it.  */
208
209 void
210 repo_tinfo_used (ti)
211      tree ti;
212 {
213 }
214 #endif
215
216 void
217 repo_template_instantiated (t, extern_p)
218      tree t;
219      int extern_p;
220 {
221   if (! extern_p)
222     {
223       tree id = repo_get_id (t);
224       if (id)
225         IDENTIFIER_REPO_CHOSEN (id) = 1;
226     }
227 }
228
229 /* Parse a reasonable subset of shell quoting syntax.  */
230
231 static char *
232 extract_string (pp)
233      char **pp;
234 {
235   char *p = *pp;
236   int backquote = 0;
237   int inside = 0;
238
239   for (;;)
240     {
241       char c = *p;
242       if (c == '\0')
243         break;
244       ++p;
245       if (backquote)
246         obstack_1grow (&temporary_obstack, c);
247       else if (! inside && c == ' ')
248         break;
249       else if (! inside && c == '\\')
250         backquote = 1;
251       else if (c == '\'')
252         inside = !inside;
253       else
254         obstack_1grow (&temporary_obstack, c);
255     }
256
257   obstack_1grow (&temporary_obstack, '\0');
258   *pp = p;
259   return obstack_finish (&temporary_obstack);
260 }
261
262 static char *
263 get_base_filename (filename)
264      const char *filename;
265 {
266   char *p = getenv ("COLLECT_GCC_OPTIONS");
267   char *output = NULL;
268   int compiling = 0;
269
270   while (p && *p)
271     {
272       char *q = extract_string (&p);
273
274       if (strcmp (q, "-o") == 0)
275         output = extract_string (&p);
276       else if (strcmp (q, "-c") == 0)
277         compiling = 1;
278       }
279
280   if (compiling && output)
281     return output;
282
283   if (p && ! compiling)
284     {
285       warning ("-frepo must be used with -c");
286       flag_use_repository = 0;
287       return NULL;
288     }
289
290   return file_name_nondirectory (filename);
291 }        
292
293 static void
294 open_repo_file (filename)
295      const char *filename;
296 {
297   register const char *p;
298   const char *s = get_base_filename (filename);
299
300   if (s == NULL)
301     return;
302
303   p = file_name_nondirectory (s);
304   p = strrchr (p, '.');
305   if (! p)
306     p = s + strlen (s);
307
308   obstack_grow (&permanent_obstack, s, p - s);
309   repo_name = obstack_copy0 (&permanent_obstack, ".rpo", 4);
310
311   repo_file = fopen (repo_name, "r");
312 }
313
314 static char *
315 afgets (stream)
316      FILE *stream;
317 {
318   int c;
319   while ((c = getc (stream)) != EOF && c != '\n')
320     obstack_1grow (&temporary_obstack, c);
321   if (obstack_object_size (&temporary_obstack) == 0)
322     return NULL;
323   obstack_1grow (&temporary_obstack, '\0');
324   return obstack_finish (&temporary_obstack);
325 }
326
327 void
328 init_repo (filename)
329      const char *filename;
330 {
331   char *buf;
332
333   if (! flag_use_repository)
334     return;
335
336   ggc_add_tree_root (&pending_repo, 1);
337   ggc_add_tree_root (&original_repo, 1);
338   gcc_obstack_init (&temporary_obstack);
339
340   open_repo_file (filename);
341
342   if (repo_file == 0)
343     return;
344
345   while ((buf = afgets (repo_file)))
346     {
347       switch (buf[0])
348         {
349         case 'A':
350           old_args = obstack_copy0 (&permanent_obstack, buf + 2,
351                                     strlen (buf + 2));
352           break;
353         case 'D':
354           old_dir = obstack_copy0 (&permanent_obstack, buf + 2,
355                                    strlen (buf + 2));
356           break;
357         case 'M':
358           old_main = obstack_copy0 (&permanent_obstack, buf + 2,
359                                     strlen (buf + 2));
360           break;
361         case 'C':
362         case 'O':
363           {
364             tree id = get_identifier (buf + 2);
365             tree orig;
366
367             if (buf[0] == 'C')
368               {
369                 IDENTIFIER_REPO_CHOSEN (id) = 1;
370                 orig = integer_one_node;
371               }
372             else
373               orig = NULL_TREE;
374
375             original_repo = tree_cons (orig, id, original_repo);
376           }
377           break;
378         default:
379           error ("mysterious repository information in %s", repo_name);
380         }
381       obstack_free (&temporary_obstack, buf);
382     }
383 }
384
385 static void
386 reopen_repo_file_for_write ()
387 {
388   if (repo_file)
389     fclose (repo_file);
390   repo_file = fopen (repo_name, "w");
391
392   if (repo_file == 0)
393     {
394       error ("can't create repository information file `%s'", repo_name);
395       flag_use_repository = 0;
396     }
397 }
398
399 /* Emit any pending repos.  */
400
401 void
402 finish_repo ()
403 {
404   tree t;
405   int repo_changed = 0;
406   char *dir, *args;
407
408   if (! flag_use_repository)
409     return;
410
411   /* Do we have to write out a new info file?  */
412
413   /* Are there any old templates that aren't used any longer or that are
414      newly chosen?  */
415   
416   for (t = original_repo; t; t = TREE_CHAIN (t))
417     {
418       if (! IDENTIFIER_REPO_USED (TREE_VALUE (t))
419           || (! TREE_PURPOSE (t) && IDENTIFIER_REPO_CHOSEN (TREE_VALUE (t))))
420         {
421           repo_changed = 1;
422           break;
423         }
424       IDENTIFIER_REPO_USED (TREE_VALUE (t)) = 0;
425     }
426
427   /* Are there any templates that are newly used?  */
428   
429   if (! repo_changed)
430     for (t = pending_repo; t; t = TREE_CHAIN (t))
431       {
432         if (IDENTIFIER_REPO_USED (TREE_VALUE (t)))
433           {
434             repo_changed = 1;
435             break;
436           }
437       }
438
439   dir = getpwd ();
440   args = getenv ("COLLECT_GCC_OPTIONS");
441
442   if (! repo_changed && pending_repo)
443     if (strcmp (old_main, main_input_filename) != 0
444         || strcmp (old_dir, dir) != 0
445         || (args == NULL) != (old_args == NULL)
446         || (args && strcmp (old_args, args) != 0))
447       repo_changed = 1;
448
449   if (! repo_changed || errorcount || sorrycount)
450     goto out;
451
452   reopen_repo_file_for_write ();
453
454   if (repo_file == 0)
455     goto out;
456
457   fprintf (repo_file, "M %s\n", main_input_filename);
458   fprintf (repo_file, "D %s\n", dir);
459   if (args)
460     fprintf (repo_file, "A %s\n", args);
461
462   for (t = pending_repo; t; t = TREE_CHAIN (t))
463     {
464       tree val = TREE_VALUE (t);
465       char type = IDENTIFIER_REPO_CHOSEN (val) ? 'C' : 'O';
466
467       fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (val));
468     }
469
470  out:
471   if (repo_file)
472     fclose (repo_file);
473 }