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