]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/cp/repo.c
gcc/ChangeLog:
[thirdparty/gcc.git] / gcc / cp / repo.c
1 /* Code to maintain a C++ template repository.
2 Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005,
3 2006, 2007 Free Software Foundation, Inc.
4 Contributed by Jason Merrill (jason@cygnus.com)
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify
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
13 GCC is distributed in the hope that it will be useful,
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
19 along with GCC; see the file COPYING. If not, write to
20 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
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
27 explicit code. */
28
29 #include "config.h"
30 #include "system.h"
31 #include "coretypes.h"
32 #include "tm.h"
33 #include "tree.h"
34 #include "cp-tree.h"
35 #include "input.h"
36 #include "obstack.h"
37 #include "toplev.h"
38 #include "diagnostic.h"
39 #include "flags.h"
40
41 static char *extract_string (char **);
42 static const char *get_base_filename (const char *);
43 static FILE *open_repo_file (const char *);
44 static char *afgets (FILE *);
45 static FILE *reopen_repo_file_for_write (void);
46
47 static GTY(()) tree pending_repo;
48 static char *repo_name;
49
50 static const char *old_args, *old_dir, *old_main;
51
52 static struct obstack temporary_obstack;
53 static bool temporary_obstack_initialized_p;
54
55 /* Parse a reasonable subset of shell quoting syntax. */
56
57 static char *
58 extract_string (char **pp)
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 {
72 obstack_1grow (&temporary_obstack, c);
73 backquote = 0;
74 }
75 else if (! inside && c == ' ')
76 break;
77 else if (! inside && c == '\\')
78 backquote = 1;
79 else if (c == '\'')
80 inside = !inside;
81 else
82 obstack_1grow (&temporary_obstack, c);
83 }
84
85 obstack_1grow (&temporary_obstack, '\0');
86 *pp = p;
87 return (char *) obstack_finish (&temporary_obstack);
88 }
89
90 static const char *
91 get_base_filename (const char *filename)
92 {
93 char *p = getenv ("COLLECT_GCC_OPTIONS");
94 char *output = NULL;
95 int compiling = 0;
96
97 while (p && *p)
98 {
99 char *q = extract_string (&p);
100
101 if (strcmp (q, "-o") == 0)
102 output = extract_string (&p);
103 else if (strcmp (q, "-c") == 0)
104 compiling = 1;
105 }
106
107 if (compiling && output)
108 return output;
109
110 if (p && ! compiling)
111 {
112 warning (0, "-frepo must be used with -c");
113 flag_use_repository = 0;
114 return NULL;
115 }
116
117 return lbasename (filename);
118 }
119
120 static FILE *
121 open_repo_file (const char *filename)
122 {
123 const char *p;
124 const char *s = get_base_filename (filename);
125
126 if (s == NULL)
127 return NULL;
128
129 p = lbasename (s);
130 p = strrchr (p, '.');
131 if (! p)
132 p = s + strlen (s);
133
134 repo_name = XNEWVEC (char, p - s + 5);
135 memcpy (repo_name, s, p - s);
136 memcpy (repo_name + (p - s), ".rpo", 5);
137
138 return fopen (repo_name, "r");
139 }
140
141 static char *
142 afgets (FILE *stream)
143 {
144 int c;
145 while ((c = getc (stream)) != EOF && c != '\n')
146 obstack_1grow (&temporary_obstack, c);
147 if (obstack_object_size (&temporary_obstack) == 0)
148 return NULL;
149 obstack_1grow (&temporary_obstack, '\0');
150 return (char *) obstack_finish (&temporary_obstack);
151 }
152
153 void
154 init_repo (void)
155 {
156 char *buf;
157 FILE *repo_file;
158
159 if (! flag_use_repository)
160 return;
161
162 /* When a PCH file is loaded, the entire identifier table is
163 replaced, with the result that IDENTIFIER_REPO_CHOSEN is cleared.
164 So, we have to reread the repository file. */
165 lang_post_pch_load = init_repo;
166
167 if (!temporary_obstack_initialized_p)
168 gcc_obstack_init (&temporary_obstack);
169
170 repo_file = open_repo_file (main_input_filename);
171
172 if (repo_file == 0)
173 return;
174
175 while ((buf = afgets (repo_file)))
176 {
177 switch (buf[0])
178 {
179 case 'A':
180 old_args = ggc_strdup (buf + 2);
181 break;
182 case 'D':
183 old_dir = ggc_strdup (buf + 2);
184 break;
185 case 'M':
186 old_main = ggc_strdup (buf + 2);
187 break;
188 case 'O':
189 /* A symbol that we were able to define the last time this
190 file was compiled. */
191 break;
192 case 'C':
193 /* A symbol that the prelinker has requested that we
194 define. */
195 {
196 tree id = get_identifier (buf + 2);
197 IDENTIFIER_REPO_CHOSEN (id) = 1;
198 }
199 break;
200 default:
201 error ("mysterious repository information in %s", repo_name);
202 }
203 obstack_free (&temporary_obstack, buf);
204 }
205 fclose (repo_file);
206
207 if (old_args && !get_random_seed (true)
208 && (buf = strstr (old_args, "'-frandom-seed=")))
209 set_random_seed (extract_string (&buf) + strlen ("-frandom-seed="));
210 }
211
212 static FILE *
213 reopen_repo_file_for_write (void)
214 {
215 FILE *repo_file = fopen (repo_name, "w");
216
217 if (repo_file == 0)
218 {
219 error ("can't create repository information file %qs", repo_name);
220 flag_use_repository = 0;
221 }
222
223 return repo_file;
224 }
225
226 /* Emit any pending repos. */
227
228 void
229 finish_repo (void)
230 {
231 tree t;
232 char *dir, *args;
233 FILE *repo_file;
234
235 if (!flag_use_repository)
236 return;
237
238 if (errorcount || sorrycount)
239 return;
240
241 repo_file = reopen_repo_file_for_write ();
242 if (repo_file == 0)
243 goto out;
244
245 fprintf (repo_file, "M %s\n", main_input_filename);
246 dir = getpwd ();
247 fprintf (repo_file, "D %s\n", dir);
248 args = getenv ("COLLECT_GCC_OPTIONS");
249 if (args)
250 {
251 fprintf (repo_file, "A %s", args);
252 /* If -frandom-seed is not among the ARGS, then add the value
253 that we chose. That will ensure that the names of types from
254 anonymous namespaces will get the same mangling when this
255 file is recompiled. */
256 if (!strstr (args, "'-frandom-seed="))
257 fprintf (repo_file, " '-frandom-seed=%s'", get_random_seed (false));
258 fprintf (repo_file, "\n");
259 }
260
261 for (t = pending_repo; t; t = TREE_CHAIN (t))
262 {
263 tree val = TREE_VALUE (t);
264 tree name = DECL_ASSEMBLER_NAME (val);
265 char type = IDENTIFIER_REPO_CHOSEN (name) ? 'C' : 'O';
266 fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (name));
267 }
268
269 out:
270 if (repo_file)
271 fclose (repo_file);
272 }
273
274 /* DECL is a FUNCTION_DECL or VAR_DECL with vague linkage whose
275 definition is available in this translation unit. Returns 0 if
276 this definition should not be emitted in this translation unit
277 because it will be emitted elsewhere. Returns 1 if the repository
278 file indicates that that DECL should be emitted in this translation
279 unit, or 2 if the repository file is not in use. */
280
281 int
282 repo_emit_p (tree decl)
283 {
284 gcc_assert (TREE_PUBLIC (decl));
285 gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
286 || TREE_CODE (decl) == VAR_DECL);
287 gcc_assert (!DECL_REALLY_EXTERN (decl));
288
289 /* When not using the repository, emit everything. */
290 if (!flag_use_repository)
291 return 2;
292
293 /* Only template instantiations are managed by the repository. This
294 is an artificial restriction; the code in the prelinker and here
295 will work fine if all entities with vague linkage are managed by
296 the repository. */
297 if (TREE_CODE (decl) == VAR_DECL)
298 {
299 tree type = NULL_TREE;
300 if (DECL_VTABLE_OR_VTT_P (decl))
301 type = DECL_CONTEXT (decl);
302 else if (DECL_TINFO_P (decl))
303 type = TREE_TYPE (DECL_NAME (decl));
304 if (!DECL_TEMPLATE_INSTANTIATION (decl)
305 && (!TYPE_LANG_SPECIFIC (type)
306 || !CLASSTYPE_TEMPLATE_INSTANTIATION (type)))
307 return 2;
308 /* Static data members initialized by constant expressions must
309 be processed where needed so that their definitions are
310 available. */
311 if (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
312 && DECL_CLASS_SCOPE_P (decl))
313 return 2;
314 }
315 else if (!DECL_TEMPLATE_INSTANTIATION (decl))
316 return 2;
317
318 /* For constructors and destructors, the repository contains
319 information about the clones -- not the original function --
320 because only the clones are emitted in the object file. */
321 if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
322 || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
323 {
324 int emit_p = 0;
325 tree clone;
326 /* There is no early exit from this loop because we want to
327 ensure that all of the clones are marked as available in this
328 object file. */
329 FOR_EACH_CLONE (clone, decl)
330 /* The only possible results from the recursive call to
331 repo_emit_p are 0 or 1. */
332 if (repo_emit_p (clone))
333 emit_p = 1;
334 return emit_p;
335 }
336
337 /* Keep track of all available entities. */
338 if (!DECL_REPO_AVAILABLE_P (decl))
339 {
340 DECL_REPO_AVAILABLE_P (decl) = 1;
341 pending_repo = tree_cons (NULL_TREE, decl, pending_repo);
342 }
343
344 return IDENTIFIER_REPO_CHOSEN (DECL_ASSEMBLER_NAME (decl));
345 }
346
347 /* Returns true iff the prelinker has explicitly marked CLASS_TYPE for
348 export from this translation unit. */
349
350 bool
351 repo_export_class_p (tree class_type)
352 {
353 if (!flag_use_repository)
354 return false;
355 if (!CLASSTYPE_VTABLES (class_type))
356 return false;
357 /* If the virtual table has been assigned to this translation unit,
358 export the class. */
359 return (IDENTIFIER_REPO_CHOSEN
360 (DECL_ASSEMBLER_NAME (CLASSTYPE_VTABLES (class_type))));
361 }
362
363 #include "gt-cp-repo.h"