OSDN Git Service

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