]>
Commit | Line | Data |
---|---|---|
faae18ab | 1 | /* Code to maintain a C++ template repository. |
43c6a96a SB |
2 | Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003 |
3 | Free Software Foundation, Inc. | |
faae18ab MS |
4 | Contributed by Jason Merrill (jason@cygnus.com) |
5 | ||
f5adbb8d | 6 | This file is part of GCC. |
faae18ab | 7 | |
f5adbb8d | 8 | GCC is free software; you can redistribute it and/or modify |
faae18ab MS |
9 | it under the terms of the GNU General Public License as published by |
10 | the Free Software Foundation; either version 2, or (at your option) | |
11 | any later version. | |
12 | ||
f5adbb8d | 13 | GCC is distributed in the hope that it will be useful, |
faae18ab MS |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
f5adbb8d | 19 | along with GCC; see the file COPYING. If not, write to |
e9fa0c7c RK |
20 | the Free Software Foundation, 59 Temple Place - Suite 330, |
21 | Boston, MA 02111-1307, USA. */ | |
faae18ab MS |
22 | |
23 | /* My strategy here is as follows: | |
24 | ||
25 | Everything should be emitted in a translation unit where it is used. | |
26 | The results of the automatic process should be easily reproducible with | |
b19b4a78 | 27 | explicit code. */ |
faae18ab | 28 | |
b19b4a78 | 29 | #include "config.h" |
8d052bc7 | 30 | #include "system.h" |
4977bab6 ZW |
31 | #include "coretypes.h" |
32 | #include "tm.h" | |
faae18ab MS |
33 | #include "tree.h" |
34 | #include "cp-tree.h" | |
35 | #include "input.h" | |
79ff2c6c | 36 | #include "obstack.h" |
54f92bfb | 37 | #include "toplev.h" |
2a2b2d43 | 38 | #include "diagnostic.h" |
faae18ab | 39 | |
848eed92 GDR |
40 | static char *extract_string (char **); |
41 | static const char *get_base_filename (const char *); | |
42 | static void open_repo_file (const char *); | |
43 | static char *afgets (FILE *); | |
44 | static void reopen_repo_file_for_write (void); | |
faae18ab | 45 | |
e2500fed | 46 | static GTY(()) tree pending_repo; |
e8abc66f | 47 | static char *repo_name; |
faae18ab MS |
48 | static FILE *repo_file; |
49 | ||
e65e6212 | 50 | static const char *old_args, *old_dir, *old_main; |
6633d636 | 51 | |
1f8f4a0b | 52 | static struct obstack temporary_obstack; |
4684cd27 | 53 | static bool temporary_obstack_initialized_p; |
44a8d0b3 | 54 | |
6633d636 MS |
55 | /* Parse a reasonable subset of shell quoting syntax. */ |
56 | ||
57 | static char * | |
848eed92 | 58 | extract_string (char **pp) |
6633d636 MS |
59 | { |
60 | char *p = *pp; | |
61 | int backquote = 0; | |
62 | int inside = 0; | |
63 | ||
64 | for (;;) | |
65 | { | |
66 | char c = *p; | |
67 | if (c == '\0') | |
68 | break; | |
69 | ++p; | |
70 | if (backquote) | |
71 | obstack_1grow (&temporary_obstack, c); | |
72 | else if (! inside && c == ' ') | |
73 | break; | |
74 | else if (! inside && c == '\\') | |
75 | backquote = 1; | |
76 | else if (c == '\'') | |
77 | inside = !inside; | |
78 | else | |
79 | obstack_1grow (&temporary_obstack, c); | |
80 | } | |
81 | ||
82 | obstack_1grow (&temporary_obstack, '\0'); | |
83 | *pp = p; | |
84 | return obstack_finish (&temporary_obstack); | |
85 | } | |
86 | ||
8ce33230 | 87 | static const char * |
848eed92 | 88 | get_base_filename (const char *filename) |
b19b4a78 MS |
89 | { |
90 | char *p = getenv ("COLLECT_GCC_OPTIONS"); | |
6633d636 | 91 | char *output = NULL; |
b19b4a78 MS |
92 | int compiling = 0; |
93 | ||
6633d636 MS |
94 | while (p && *p) |
95 | { | |
96 | char *q = extract_string (&p); | |
b19b4a78 | 97 | |
6633d636 MS |
98 | if (strcmp (q, "-o") == 0) |
99 | output = extract_string (&p); | |
100 | else if (strcmp (q, "-c") == 0) | |
101 | compiling = 1; | |
b19b4a78 MS |
102 | } |
103 | ||
104 | if (compiling && output) | |
105 | return output; | |
106 | ||
79ff2c6c MS |
107 | if (p && ! compiling) |
108 | { | |
8251199e | 109 | warning ("-frepo must be used with -c"); |
79ff2c6c MS |
110 | flag_use_repository = 0; |
111 | return NULL; | |
112 | } | |
113 | ||
b3e68a79 | 114 | return lbasename (filename); |
b19b4a78 MS |
115 | } |
116 | ||
faae18ab | 117 | static void |
848eed92 | 118 | open_repo_file (const char *filename) |
faae18ab | 119 | { |
926ce8bd | 120 | const char *p; |
d8e178a0 | 121 | const char *s = get_base_filename (filename); |
79ff2c6c | 122 | |
e8abc66f | 123 | if (s == NULL) |
79ff2c6c MS |
124 | return; |
125 | ||
b3e68a79 | 126 | p = lbasename (s); |
9473c522 | 127 | p = strrchr (p, '.'); |
e8abc66f MS |
128 | if (! p) |
129 | p = s + strlen (s); | |
faae18ab | 130 | |
6d9f628e GK |
131 | repo_name = xmalloc (p - s + 5); |
132 | memcpy (repo_name, s, p - s); | |
133 | memcpy (repo_name + (p - s), ".rpo", 5); | |
faae18ab MS |
134 | |
135 | repo_file = fopen (repo_name, "r"); | |
136 | } | |
137 | ||
e8abc66f | 138 | static char * |
848eed92 | 139 | afgets (FILE *stream) |
e8abc66f MS |
140 | { |
141 | int c; | |
142 | while ((c = getc (stream)) != EOF && c != '\n') | |
143 | obstack_1grow (&temporary_obstack, c); | |
144 | if (obstack_object_size (&temporary_obstack) == 0) | |
145 | return NULL; | |
146 | obstack_1grow (&temporary_obstack, '\0'); | |
147 | return obstack_finish (&temporary_obstack); | |
148 | } | |
149 | ||
faae18ab | 150 | void |
4684cd27 | 151 | init_repo (void) |
faae18ab | 152 | { |
e8abc66f | 153 | char *buf; |
faae18ab MS |
154 | |
155 | if (! flag_use_repository) | |
156 | return; | |
157 | ||
4684cd27 MM |
158 | /* When a PCH file is loaded, the entire identifier table is |
159 | replaced, with the result that IDENTIFIER_REPO_CHOSEN is cleared. | |
160 | So, we have to reread the repository file. */ | |
161 | lang_post_pch_load = init_repo; | |
162 | ||
163 | if (!temporary_obstack_initialized_p) | |
164 | gcc_obstack_init (&temporary_obstack); | |
9cd64686 | 165 | |
4684cd27 | 166 | open_repo_file (main_input_filename); |
faae18ab MS |
167 | |
168 | if (repo_file == 0) | |
169 | return; | |
170 | ||
a703fb38 | 171 | while ((buf = afgets (repo_file))) |
faae18ab | 172 | { |
faae18ab MS |
173 | switch (buf[0]) |
174 | { | |
175 | case 'A': | |
6d9f628e | 176 | old_args = ggc_strdup (buf + 2); |
6633d636 | 177 | break; |
e8abc66f | 178 | case 'D': |
6d9f628e | 179 | old_dir = ggc_strdup (buf + 2); |
6633d636 | 180 | break; |
faae18ab | 181 | case 'M': |
6d9f628e | 182 | old_main = ggc_strdup (buf + 2); |
faae18ab | 183 | break; |
faae18ab | 184 | case 'O': |
4684cd27 MM |
185 | /* A symbol that we were able to define the last time this |
186 | file was compiled. */ | |
187 | break; | |
188 | case 'C': | |
189 | /* A symbol that the prelinker has requested that we | |
190 | define. */ | |
faae18ab | 191 | { |
e8abc66f | 192 | tree id = get_identifier (buf + 2); |
4684cd27 | 193 | IDENTIFIER_REPO_CHOSEN (id) = 1; |
faae18ab MS |
194 | } |
195 | break; | |
196 | default: | |
8251199e | 197 | error ("mysterious repository information in %s", repo_name); |
faae18ab | 198 | } |
e8abc66f | 199 | obstack_free (&temporary_obstack, buf); |
faae18ab | 200 | } |
4684cd27 | 201 | fclose (repo_file); |
faae18ab MS |
202 | } |
203 | ||
204 | static void | |
848eed92 | 205 | reopen_repo_file_for_write (void) |
faae18ab | 206 | { |
faae18ab MS |
207 | repo_file = fopen (repo_name, "w"); |
208 | ||
209 | if (repo_file == 0) | |
210 | { | |
8251199e | 211 | error ("can't create repository information file `%s'", repo_name); |
faae18ab MS |
212 | flag_use_repository = 0; |
213 | } | |
214 | } | |
215 | ||
216 | /* Emit any pending repos. */ | |
217 | ||
218 | void | |
848eed92 | 219 | finish_repo (void) |
faae18ab MS |
220 | { |
221 | tree t; | |
6633d636 | 222 | char *dir, *args; |
faae18ab | 223 | |
848eed92 | 224 | if (!flag_use_repository) |
faae18ab MS |
225 | return; |
226 | ||
4684cd27 | 227 | if (errorcount || sorrycount) |
faae18ab MS |
228 | goto out; |
229 | ||
230 | reopen_repo_file_for_write (); | |
faae18ab MS |
231 | if (repo_file == 0) |
232 | goto out; | |
233 | ||
b19b4a78 | 234 | fprintf (repo_file, "M %s\n", main_input_filename); |
4684cd27 | 235 | dir = getpwd (); |
6633d636 | 236 | fprintf (repo_file, "D %s\n", dir); |
4684cd27 | 237 | args = getenv ("COLLECT_GCC_OPTIONS"); |
6633d636 MS |
238 | if (args) |
239 | fprintf (repo_file, "A %s\n", args); | |
b19b4a78 | 240 | |
faae18ab MS |
241 | for (t = pending_repo; t; t = TREE_CHAIN (t)) |
242 | { | |
243 | tree val = TREE_VALUE (t); | |
4684cd27 MM |
244 | tree name = DECL_ASSEMBLER_NAME (val); |
245 | char type = IDENTIFIER_REPO_CHOSEN (name) ? 'C' : 'O'; | |
246 | fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (name)); | |
faae18ab MS |
247 | } |
248 | ||
249 | out: | |
250 | if (repo_file) | |
251 | fclose (repo_file); | |
252 | } | |
e2500fed | 253 | |
4684cd27 MM |
254 | /* DECL is a FUNCTION_DECL or VAR_DECL with vague linkage whose |
255 | definition is available in this translation unit. Returns 0 if | |
256 | this definition should not be emitted in this translation unit | |
257 | because it will be emitted elsewhere. Returns 1 if the repository | |
258 | file indicates that that DECL should be emitted in this translation | |
259 | unit, or 2 if the repository file is not in use. */ | |
260 | ||
261 | int | |
262 | repo_emit_p (tree decl) | |
263 | { | |
264 | my_friendly_assert (TREE_PUBLIC (decl), 20040725); | |
265 | my_friendly_assert (TREE_CODE (decl) == FUNCTION_DECL | |
266 | || TREE_CODE (decl) == VAR_DECL, | |
267 | 20040725); | |
268 | my_friendly_assert (!DECL_REALLY_EXTERN (decl), 20040725); | |
269 | ||
270 | /* When not using the repository, emit everything. */ | |
271 | if (!flag_use_repository) | |
272 | return 2; | |
273 | ||
274 | /* Only template instantiations are managed by the repository. This | |
275 | is an artificial restriction; the code in the prelinker and here | |
276 | will work fine if all entities with vague linkage are managed by | |
277 | the repository. */ | |
278 | if (TREE_CODE (decl) == VAR_DECL) | |
279 | { | |
280 | tree type = NULL_TREE; | |
281 | if (DECL_VTABLE_OR_VTT_P (decl)) | |
282 | type = DECL_CONTEXT (decl); | |
283 | else if (DECL_TINFO_P (decl)) | |
284 | type = TREE_TYPE (DECL_NAME (decl)); | |
285 | if (!DECL_TEMPLATE_INSTANTIATION (decl) | |
286 | && !CLASSTYPE_TEMPLATE_INSTANTIATION (type)) | |
287 | return 2; | |
288 | } | |
289 | else if (!DECL_TEMPLATE_INSTANTIATION (decl)) | |
290 | return 2; | |
291 | ||
292 | /* For constructors and destructors, the repository contains | |
293 | information about the clones -- not the original function -- | |
294 | because only the clones are emitted in the object file. */ | |
295 | if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl) | |
296 | || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl)) | |
297 | { | |
298 | int emit_p = 0; | |
299 | tree clone; | |
300 | /* There is no early exit from this loop because we want to | |
301 | ensure that all of the clones are marked as available in this | |
302 | object file. */ | |
303 | FOR_EACH_CLONE (clone, decl) | |
304 | /* The only possible results from the recursive call to | |
305 | repo_emit_p are 0 or 1. */ | |
306 | if (repo_emit_p (clone)) | |
307 | emit_p = 1; | |
308 | return emit_p; | |
309 | } | |
310 | ||
311 | /* Keep track of all available entities. */ | |
312 | if (!DECL_REPO_AVAILABLE_P (decl)) | |
313 | { | |
314 | DECL_REPO_AVAILABLE_P (decl) = 1; | |
315 | pending_repo = tree_cons (NULL_TREE, decl, pending_repo); | |
316 | } | |
317 | ||
318 | return IDENTIFIER_REPO_CHOSEN (DECL_ASSEMBLER_NAME (decl)); | |
319 | } | |
320 | ||
321 | /* Returns true iff the prelinker has explicitly marked CLASS_TYPE for | |
322 | export from this translation unit. */ | |
323 | ||
324 | bool | |
325 | repo_export_class_p (tree class_type) | |
326 | { | |
327 | if (!flag_use_repository) | |
328 | return false; | |
329 | if (!CLASSTYPE_VTABLES (class_type)) | |
330 | return false; | |
331 | /* If the virtual table has been assigned to this translation unit, | |
332 | export the class. */ | |
333 | return (IDENTIFIER_REPO_CHOSEN | |
334 | (DECL_ASSEMBLER_NAME (CLASSTYPE_VTABLES (class_type)))); | |
335 | } | |
336 | ||
e2500fed | 337 | #include "gt-cp-repo.h" |