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