]>
Commit | Line | Data |
---|---|---|
bb09dca5 | 1 | /* Code to maintain a C++ template repository. |
606b494c | 2 | Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001 Free Software Foundation, Inc. |
bb09dca5 | 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 | |
c58d4270 | 19 | the Free Software Foundation, 59 Temple Place - Suite 330, |
20 | Boston, MA 02111-1307, USA. */ | |
bb09dca5 | 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 | |
11682839 | 26 | explicit code. */ |
bb09dca5 | 27 | |
11682839 | 28 | #include "config.h" |
b3ef7553 | 29 | #include "system.h" |
bb09dca5 | 30 | #include "tree.h" |
31 | #include "cp-tree.h" | |
32 | #include "input.h" | |
3e1ffd94 | 33 | #include "obstack.h" |
2a4e40b0 | 34 | #include "toplev.h" |
1e4853c2 | 35 | #include "ggc.h" |
bb09dca5 | 36 | |
24054144 | 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)); | |
bb09dca5 | 43 | |
44 | static tree pending_repo; | |
3e1ffd94 | 45 | static tree original_repo; |
3f7d79e4 | 46 | static char *repo_name; |
bb09dca5 | 47 | static FILE *repo_file; |
48 | ||
6686e84d | 49 | static char *old_args, *old_dir, *old_main; |
50 | ||
bb09dca5 | 51 | extern int flag_use_repository; |
d7c47c0e | 52 | static struct obstack temporary_obstack; |
3f7d79e4 | 53 | extern struct obstack permanent_obstack; |
bb09dca5 | 54 | |
bb09dca5 | 55 | #define IDENTIFIER_REPO_USED(NODE) (TREE_LANG_FLAG_3 (NODE)) |
56 | #define IDENTIFIER_REPO_CHOSEN(NODE) (TREE_LANG_FLAG_4 (NODE)) | |
57 | ||
e857e9c7 | 58 | #if 0 |
bb09dca5 | 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 | {} | |
e857e9c7 | 92 | #endif |
bb09dca5 | 93 | |
e857e9c7 | 94 | static tree |
dc76caae | 95 | repo_get_id (t) |
96 | tree t; | |
97 | { | |
9308e976 | 98 | if (TYPE_P (t)) |
dc76caae | 99 | { |
8b1e0315 | 100 | tree vtable; |
101 | ||
d1c45f5d | 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. */ | |
4b72716d | 105 | if (!COMPLETE_TYPE_P (t) || TYPE_BEING_DEFINED (t)) |
d1c45f5d | 106 | my_friendly_abort (981113); |
107 | ||
8b1e0315 | 108 | vtable = get_vtbl_decl_for_binfo (TYPE_BINFO (t)); |
109 | ||
8b1e0315 | 110 | t = vtable; |
dc76caae | 111 | if (t == NULL_TREE) |
112 | return t; | |
113 | } | |
114 | return DECL_ASSEMBLER_NAME (t); | |
115 | } | |
116 | ||
bb09dca5 | 117 | /* Note that a template has been used. If we can see the definition, offer |
96624a9e | 118 | to emit it. */ |
bb09dca5 | 119 | |
120 | void | |
121 | repo_template_used (t) | |
122 | tree t; | |
123 | { | |
124 | tree id; | |
125 | ||
126 | if (! flag_use_repository) | |
127 | return; | |
128 | ||
dc76caae | 129 | id = repo_get_id (t); |
130 | if (id == NULL_TREE) | |
131 | return; | |
132 | ||
9308e976 | 133 | if (TYPE_P (t)) |
bb09dca5 | 134 | { |
bb09dca5 | 135 | if (IDENTIFIER_REPO_CHOSEN (id)) |
136 | mark_class_instantiated (t, 0); | |
137 | } | |
9308e976 | 138 | else if (DECL_P (t)) |
bb09dca5 | 139 | { |
bb09dca5 | 140 | if (IDENTIFIER_REPO_CHOSEN (id)) |
e857e9c7 | 141 | mark_decl_instantiated (t, 0); |
bb09dca5 | 142 | } |
143 | else | |
144 | my_friendly_abort (1); | |
145 | ||
146 | if (! IDENTIFIER_REPO_USED (id)) | |
147 | { | |
bb09dca5 | 148 | IDENTIFIER_REPO_USED (id) = 1; |
b0652a4f | 149 | pending_repo = tree_cons (NULL_TREE, id, pending_repo); |
bb09dca5 | 150 | } |
bb09dca5 | 151 | } |
152 | ||
e857e9c7 | 153 | #if 0 |
bb09dca5 | 154 | /* Note that the vtable for a class has been used, and offer to emit it. */ |
155 | ||
e857e9c7 | 156 | static void |
bb09dca5 | 157 | repo_vtable_used (t) |
158 | tree t; | |
159 | { | |
160 | if (! flag_use_repository) | |
161 | return; | |
162 | ||
b0652a4f | 163 | pending_repo = tree_cons (NULL_TREE, t, pending_repo); |
bb09dca5 | 164 | } |
165 | ||
166 | /* Note that an inline with external linkage has been used, and offer to | |
167 | emit it. */ | |
168 | ||
169 | void | |
170 | repo_inline_used (fn) | |
171 | tree fn; | |
172 | { | |
173 | if (! flag_use_repository) | |
174 | return; | |
175 | ||
176 | /* Member functions of polymorphic classes go with their vtables. */ | |
1d6228f0 | 177 | if (DECL_FUNCTION_MEMBER_P (fn) |
9ba4048d | 178 | && TYPE_POLYMORPHIC_P (DECL_CONTEXT (fn))) |
bb09dca5 | 179 | { |
9ba4048d | 180 | repo_vtable_used (DECL_CONTEXT (fn)); |
bb09dca5 | 181 | return; |
182 | } | |
183 | ||
b0652a4f | 184 | pending_repo = tree_cons (NULL_TREE, fn, pending_repo); |
bb09dca5 | 185 | } |
186 | ||
187 | /* Note that a particular typeinfo node has been used, and offer to | |
188 | emit it. */ | |
189 | ||
190 | void | |
191 | repo_tinfo_used (ti) | |
192 | tree ti; | |
193 | { | |
194 | } | |
e857e9c7 | 195 | #endif |
bb09dca5 | 196 | |
dc76caae | 197 | void |
198 | repo_template_instantiated (t, extern_p) | |
199 | tree t; | |
200 | int extern_p; | |
201 | { | |
202 | if (! extern_p) | |
203 | { | |
204 | tree id = repo_get_id (t); | |
205 | if (id) | |
206 | IDENTIFIER_REPO_CHOSEN (id) = 1; | |
207 | } | |
208 | } | |
209 | ||
6686e84d | 210 | /* Parse a reasonable subset of shell quoting syntax. */ |
211 | ||
212 | static char * | |
213 | extract_string (pp) | |
214 | char **pp; | |
215 | { | |
216 | char *p = *pp; | |
217 | int backquote = 0; | |
218 | int inside = 0; | |
219 | ||
220 | for (;;) | |
221 | { | |
222 | char c = *p; | |
223 | if (c == '\0') | |
224 | break; | |
225 | ++p; | |
226 | if (backquote) | |
227 | obstack_1grow (&temporary_obstack, c); | |
228 | else if (! inside && c == ' ') | |
229 | break; | |
230 | else if (! inside && c == '\\') | |
231 | backquote = 1; | |
232 | else if (c == '\'') | |
233 | inside = !inside; | |
234 | else | |
235 | obstack_1grow (&temporary_obstack, c); | |
236 | } | |
237 | ||
238 | obstack_1grow (&temporary_obstack, '\0'); | |
239 | *pp = p; | |
240 | return obstack_finish (&temporary_obstack); | |
241 | } | |
242 | ||
11682839 | 243 | static char * |
244 | get_base_filename (filename) | |
e1721763 | 245 | const char *filename; |
11682839 | 246 | { |
247 | char *p = getenv ("COLLECT_GCC_OPTIONS"); | |
6686e84d | 248 | char *output = NULL; |
11682839 | 249 | int compiling = 0; |
250 | ||
6686e84d | 251 | while (p && *p) |
252 | { | |
253 | char *q = extract_string (&p); | |
11682839 | 254 | |
6686e84d | 255 | if (strcmp (q, "-o") == 0) |
256 | output = extract_string (&p); | |
257 | else if (strcmp (q, "-c") == 0) | |
258 | compiling = 1; | |
11682839 | 259 | } |
260 | ||
261 | if (compiling && output) | |
262 | return output; | |
263 | ||
3e1ffd94 | 264 | if (p && ! compiling) |
265 | { | |
905d4035 | 266 | warning ("-frepo must be used with -c"); |
3e1ffd94 | 267 | flag_use_repository = 0; |
268 | return NULL; | |
269 | } | |
270 | ||
27b0422c | 271 | return file_name_nondirectory (filename); |
11682839 | 272 | } |
273 | ||
bb09dca5 | 274 | static void |
275 | open_repo_file (filename) | |
e1721763 | 276 | const char *filename; |
bb09dca5 | 277 | { |
e1721763 | 278 | register const char *p; |
279 | const char *s = get_base_filename (filename); | |
3e1ffd94 | 280 | |
3f7d79e4 | 281 | if (s == NULL) |
3e1ffd94 | 282 | return; |
283 | ||
27b0422c | 284 | p = file_name_nondirectory (s); |
78dbff7c | 285 | p = strrchr (p, '.'); |
3f7d79e4 | 286 | if (! p) |
287 | p = s + strlen (s); | |
bb09dca5 | 288 | |
3f7d79e4 | 289 | obstack_grow (&permanent_obstack, s, p - s); |
290 | repo_name = obstack_copy0 (&permanent_obstack, ".rpo", 4); | |
bb09dca5 | 291 | |
292 | repo_file = fopen (repo_name, "r"); | |
293 | } | |
294 | ||
3f7d79e4 | 295 | static char * |
296 | afgets (stream) | |
297 | FILE *stream; | |
298 | { | |
299 | int c; | |
300 | while ((c = getc (stream)) != EOF && c != '\n') | |
301 | obstack_1grow (&temporary_obstack, c); | |
302 | if (obstack_object_size (&temporary_obstack) == 0) | |
303 | return NULL; | |
304 | obstack_1grow (&temporary_obstack, '\0'); | |
305 | return obstack_finish (&temporary_obstack); | |
306 | } | |
307 | ||
bb09dca5 | 308 | void |
309 | init_repo (filename) | |
e1721763 | 310 | const char *filename; |
bb09dca5 | 311 | { |
3f7d79e4 | 312 | char *buf; |
bb09dca5 | 313 | |
314 | if (! flag_use_repository) | |
315 | return; | |
316 | ||
1e4853c2 | 317 | ggc_add_tree_root (&pending_repo, 1); |
318 | ggc_add_tree_root (&original_repo, 1); | |
d7c47c0e | 319 | gcc_obstack_init (&temporary_obstack); |
1e4853c2 | 320 | |
3e1ffd94 | 321 | open_repo_file (filename); |
bb09dca5 | 322 | |
323 | if (repo_file == 0) | |
324 | return; | |
325 | ||
034b484a | 326 | while ((buf = afgets (repo_file))) |
bb09dca5 | 327 | { |
bb09dca5 | 328 | switch (buf[0]) |
329 | { | |
330 | case 'A': | |
6686e84d | 331 | old_args = obstack_copy0 (&permanent_obstack, buf + 2, |
332 | strlen (buf + 2)); | |
333 | break; | |
3f7d79e4 | 334 | case 'D': |
6686e84d | 335 | old_dir = obstack_copy0 (&permanent_obstack, buf + 2, |
336 | strlen (buf + 2)); | |
337 | break; | |
bb09dca5 | 338 | case 'M': |
6686e84d | 339 | old_main = obstack_copy0 (&permanent_obstack, buf + 2, |
340 | strlen (buf + 2)); | |
bb09dca5 | 341 | break; |
342 | case 'C': | |
343 | case 'O': | |
344 | { | |
3f7d79e4 | 345 | tree id = get_identifier (buf + 2); |
346 | tree orig; | |
3e1ffd94 | 347 | |
bb09dca5 | 348 | if (buf[0] == 'C') |
dc76caae | 349 | { |
350 | IDENTIFIER_REPO_CHOSEN (id) = 1; | |
351 | orig = integer_one_node; | |
352 | } | |
353 | else | |
354 | orig = NULL_TREE; | |
355 | ||
b0652a4f | 356 | original_repo = tree_cons (orig, id, original_repo); |
bb09dca5 | 357 | } |
358 | break; | |
359 | default: | |
905d4035 | 360 | error ("mysterious repository information in %s", repo_name); |
bb09dca5 | 361 | } |
3f7d79e4 | 362 | obstack_free (&temporary_obstack, buf); |
bb09dca5 | 363 | } |
364 | } | |
365 | ||
366 | static void | |
367 | reopen_repo_file_for_write () | |
368 | { | |
369 | if (repo_file) | |
370 | fclose (repo_file); | |
371 | repo_file = fopen (repo_name, "w"); | |
372 | ||
373 | if (repo_file == 0) | |
374 | { | |
905d4035 | 375 | error ("can't create repository information file `%s'", repo_name); |
bb09dca5 | 376 | flag_use_repository = 0; |
377 | } | |
378 | } | |
379 | ||
380 | /* Emit any pending repos. */ | |
381 | ||
382 | void | |
383 | finish_repo () | |
384 | { | |
385 | tree t; | |
3e1ffd94 | 386 | int repo_changed = 0; |
6686e84d | 387 | char *dir, *args; |
bb09dca5 | 388 | |
389 | if (! flag_use_repository) | |
390 | return; | |
391 | ||
392 | /* Do we have to write out a new info file? */ | |
393 | ||
dc76caae | 394 | /* Are there any old templates that aren't used any longer or that are |
395 | newly chosen? */ | |
3e1ffd94 | 396 | |
397 | for (t = original_repo; t; t = TREE_CHAIN (t)) | |
398 | { | |
dc76caae | 399 | if (! IDENTIFIER_REPO_USED (TREE_VALUE (t)) |
400 | || (! TREE_PURPOSE (t) && IDENTIFIER_REPO_CHOSEN (TREE_VALUE (t)))) | |
3e1ffd94 | 401 | { |
402 | repo_changed = 1; | |
403 | break; | |
404 | } | |
405 | IDENTIFIER_REPO_USED (TREE_VALUE (t)) = 0; | |
406 | } | |
407 | ||
408 | /* Are there any templates that are newly used? */ | |
409 | ||
410 | if (! repo_changed) | |
411 | for (t = pending_repo; t; t = TREE_CHAIN (t)) | |
412 | { | |
413 | if (IDENTIFIER_REPO_USED (TREE_VALUE (t))) | |
414 | { | |
415 | repo_changed = 1; | |
416 | break; | |
417 | } | |
418 | } | |
419 | ||
6686e84d | 420 | dir = getpwd (); |
421 | args = getenv ("COLLECT_GCC_OPTIONS"); | |
422 | ||
423 | if (! repo_changed && pending_repo) | |
424 | if (strcmp (old_main, main_input_filename) != 0 | |
425 | || strcmp (old_dir, dir) != 0 | |
426 | || (args == NULL) != (old_args == NULL) | |
c90e0199 | 427 | || (args && strcmp (old_args, args) != 0)) |
6686e84d | 428 | repo_changed = 1; |
429 | ||
bb09dca5 | 430 | if (! repo_changed || errorcount || sorrycount) |
431 | goto out; | |
432 | ||
433 | reopen_repo_file_for_write (); | |
434 | ||
435 | if (repo_file == 0) | |
436 | goto out; | |
437 | ||
11682839 | 438 | fprintf (repo_file, "M %s\n", main_input_filename); |
6686e84d | 439 | fprintf (repo_file, "D %s\n", dir); |
440 | if (args) | |
441 | fprintf (repo_file, "A %s\n", args); | |
11682839 | 442 | |
bb09dca5 | 443 | for (t = pending_repo; t; t = TREE_CHAIN (t)) |
444 | { | |
445 | tree val = TREE_VALUE (t); | |
3e1ffd94 | 446 | char type = IDENTIFIER_REPO_CHOSEN (val) ? 'C' : 'O'; |
bb09dca5 | 447 | |
3f7d79e4 | 448 | fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (val)); |
bb09dca5 | 449 | } |
450 | ||
451 | out: | |
452 | if (repo_file) | |
453 | fclose (repo_file); | |
454 | } |