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