Import gcc-4.4.1
[dragonfly.git] / contrib / gcc-4.4 / 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, 2008  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 3, 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 COPYING3.  If not see
20 <http://www.gnu.org/licenses/>.  */
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 "config.h"
29 #include "system.h"
30 #include "coretypes.h"
31 #include "tm.h"
32 #include "tree.h"
33 #include "cp-tree.h"
34 #include "input.h"
35 #include "obstack.h"
36 #include "toplev.h"
37 #include "diagnostic.h"
38 #include "flags.h"
39
40 static char *extract_string (char **);
41 static const char *get_base_filename (const char *);
42 static FILE *open_repo_file (const char *);
43 static char *afgets (FILE *);
44 static FILE *reopen_repo_file_for_write (void);
45
46 static GTY(()) tree pending_repo;
47 static char *repo_name;
48
49 static const char *old_args, *old_dir, *old_main;
50
51 static struct obstack temporary_obstack;
52 static bool temporary_obstack_initialized_p;
53
54 /* Parse a reasonable subset of shell quoting syntax.  */
55
56 static char *
57 extract_string (char **pp)
58 {
59   char *p = *pp;
60   int backquote = 0;
61   int inside = 0;
62
63   for (;;)
64     {
65       char c = *p;
66       if (c == '\0')
67         break;
68       ++p;
69       if (backquote)
70         {
71           obstack_1grow (&temporary_obstack, c);
72           backquote = 0;
73         }
74       else if (! inside && c == ' ')
75         break;
76       else if (! inside && c == '\\')
77         backquote = 1;
78       else if (c == '\'')
79         inside = !inside;
80       else
81         obstack_1grow (&temporary_obstack, c);
82     }
83
84   obstack_1grow (&temporary_obstack, '\0');
85   *pp = p;
86   return (char *) obstack_finish (&temporary_obstack);
87 }
88
89 static const char *
90 get_base_filename (const char *filename)
91 {
92   char *p = getenv ("COLLECT_GCC_OPTIONS");
93   char *output = NULL;
94   int compiling = 0;
95
96   while (p && *p)
97     {
98       char *q = extract_string (&p);
99
100       if (strcmp (q, "-o") == 0)
101         output = extract_string (&p);
102       else if (strcmp (q, "-c") == 0)
103         compiling = 1;
104     }
105
106   if (compiling && output)
107     return output;
108
109   if (p && ! compiling)
110     {
111       warning (0, "-frepo must be used with -c");
112       flag_use_repository = 0;
113       return NULL;
114     }
115
116   return lbasename (filename);
117 }
118
119 static FILE *
120 open_repo_file (const char *filename)
121 {
122   const char *p;
123   const char *s = get_base_filename (filename);
124
125   if (s == NULL)
126     return NULL;
127
128   p = lbasename (s);
129   p = strrchr (p, '.');
130   if (! p)
131     p = s + strlen (s);
132
133   repo_name = XNEWVEC (char, p - s + 5);
134   memcpy (repo_name, s, p - s);
135   memcpy (repo_name + (p - s), ".rpo", 5);
136
137   return fopen (repo_name, "r");
138 }
139
140 static char *
141 afgets (FILE *stream)
142 {
143   int c;
144   while ((c = getc (stream)) != EOF && c != '\n')
145     obstack_1grow (&temporary_obstack, c);
146   if (obstack_object_size (&temporary_obstack) == 0)
147     return NULL;
148   obstack_1grow (&temporary_obstack, '\0');
149   return (char *) obstack_finish (&temporary_obstack);
150 }
151
152 void
153 init_repo (void)
154 {
155   char *buf;
156   FILE *repo_file;
157
158   if (! flag_use_repository)
159     return;
160
161   /* When a PCH file is loaded, the entire identifier table is
162      replaced, with the result that IDENTIFIER_REPO_CHOSEN is cleared.
163      So, we have to reread the repository file.  */
164   lang_post_pch_load = init_repo;
165
166   if (!temporary_obstack_initialized_p)
167     gcc_obstack_init (&temporary_obstack);
168
169   repo_file = open_repo_file (main_input_filename);
170
171   if (repo_file == 0)
172     return;
173
174   while ((buf = afgets (repo_file)))
175     {
176       switch (buf[0])
177         {
178         case 'A':
179           old_args = ggc_strdup (buf + 2);
180           break;
181         case 'D':
182           old_dir = ggc_strdup (buf + 2);
183           break;
184         case 'M':
185           old_main = ggc_strdup (buf + 2);
186           break;
187         case 'O':
188           /* A symbol that we were able to define the last time this
189              file was compiled.  */
190           break;
191         case 'C':
192           /* A symbol that the prelinker has requested that we
193              define.  */
194           {
195             tree id = get_identifier (buf + 2);
196             IDENTIFIER_REPO_CHOSEN (id) = 1;
197           }
198           break;
199         default:
200           error ("mysterious repository information in %s", repo_name);
201         }
202       obstack_free (&temporary_obstack, buf);
203     }
204   fclose (repo_file);
205
206   if (old_args && !get_random_seed (true)
207       && (buf = strstr (old_args, "'-frandom-seed=")))
208     set_random_seed (extract_string (&buf) + strlen ("-frandom-seed="));
209 }
210
211 static FILE *
212 reopen_repo_file_for_write (void)
213 {
214   FILE *repo_file = fopen (repo_name, "w");
215
216   if (repo_file == 0)
217     {
218       error ("can't create repository information file %qs", repo_name);
219       flag_use_repository = 0;
220     }
221
222   return repo_file;
223 }
224
225 /* Emit any pending repos.  */
226
227 void
228 finish_repo (void)
229 {
230   tree t;
231   char *dir, *args;
232   FILE *repo_file;
233
234   if (!flag_use_repository)
235     return;
236
237   if (errorcount || sorrycount)
238     return;
239
240   repo_file = reopen_repo_file_for_write ();
241   if (repo_file == 0)
242     goto out;
243
244   fprintf (repo_file, "M %s\n", main_input_filename);
245   dir = getpwd ();
246   fprintf (repo_file, "D %s\n", dir);
247   args = getenv ("COLLECT_GCC_OPTIONS");
248   if (args)
249     {
250       fprintf (repo_file, "A %s", args);
251       /* If -frandom-seed is not among the ARGS, then add the value
252          that we chose.  That will ensure that the names of types from
253          anonymous namespaces will get the same mangling when this
254          file is recompiled.  */
255       if (!strstr (args, "'-frandom-seed="))
256         fprintf (repo_file, " '-frandom-seed=%s'", get_random_seed (false));
257       fprintf (repo_file, "\n");
258     }
259
260   for (t = pending_repo; t; t = TREE_CHAIN (t))
261     {
262       tree val = TREE_VALUE (t);
263       tree name = DECL_ASSEMBLER_NAME (val);
264       char type = IDENTIFIER_REPO_CHOSEN (name) ? 'C' : 'O';
265       fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (name));
266     }
267
268  out:
269   if (repo_file)
270     fclose (repo_file);
271 }
272
273 /* DECL is a FUNCTION_DECL or VAR_DECL with vague linkage whose
274    definition is available in this translation unit.  Returns 0 if
275    this definition should not be emitted in this translation unit
276    because it will be emitted elsewhere.  Returns 1 if the repository
277    file indicates that that DECL should be emitted in this translation
278    unit, or 2 if the repository file is not in use.  */
279
280 int
281 repo_emit_p (tree decl)
282 {
283   int ret = 0;
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       /* Const static data members initialized by constant expressions must
309          be processed where needed so that their definitions are
310          available.  Still record them into *.rpo files, so if they
311          weren't actually emitted and collect2 requests them, they can
312          be provided.  */
313       if (DECL_INTEGRAL_CONSTANT_VAR_P (decl)
314           && DECL_CLASS_SCOPE_P (decl))
315         ret = 2;
316     }
317   else if (!DECL_TEMPLATE_INSTANTIATION (decl))
318     return 2;
319
320   if (DECL_EXPLICIT_INSTANTIATION (decl))
321     return 2;
322
323   /* For constructors and destructors, the repository contains
324      information about the clones -- not the original function --
325      because only the clones are emitted in the object file.  */
326   if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
327       || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
328     {
329       int emit_p = 0;
330       tree clone;
331       /* There is no early exit from this loop because we want to
332          ensure that all of the clones are marked as available in this
333          object file.  */
334       FOR_EACH_CLONE (clone, decl)
335         /* The only possible results from the recursive call to
336            repo_emit_p are 0 or 1.  */
337         if (repo_emit_p (clone))
338           emit_p = 1;
339       return emit_p;
340     }
341
342   /* Keep track of all available entities.  */
343   if (!DECL_REPO_AVAILABLE_P (decl))
344     {
345       DECL_REPO_AVAILABLE_P (decl) = 1;
346       pending_repo = tree_cons (NULL_TREE, decl, pending_repo);
347     }
348
349   return IDENTIFIER_REPO_CHOSEN (DECL_ASSEMBLER_NAME (decl)) ? 1 : ret;
350 }
351
352 /* Returns true iff the prelinker has explicitly marked CLASS_TYPE for
353    export from this translation unit.  */
354
355 bool
356 repo_export_class_p (const_tree class_type)
357 {
358   if (!flag_use_repository)
359     return false;
360   if (!CLASSTYPE_VTABLES (class_type))
361     return false;
362   /* If the virtual table has been assigned to this translation unit,
363      export the class.  */
364   return (IDENTIFIER_REPO_CHOSEN
365           (DECL_ASSEMBLER_NAME (CLASSTYPE_VTABLES (class_type))));
366 }
367
368 #include "gt-cp-repo.h"