1/* Code to maintain a C++ template repository.
2   Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005
3   Free Software Foundation, Inc.
4   Contributed by Jason Merrill (jason@cygnus.com)
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2, or (at your option)
11any later version.
12
13GCC is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GCC; see the file COPYING.  If not, write to
20the Free Software Foundation, 51 Franklin Street, Fifth Floor,
21Boston, 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
41static char *extract_string (char **);
42static const char *get_base_filename (const char *);
43static FILE *open_repo_file (const char *);
44static char *afgets (FILE *);
45static FILE *reopen_repo_file_for_write (void);
46
47static GTY(()) tree pending_repo;
48static char *repo_name;
49
50static const char *old_args, *old_dir, *old_main;
51
52static struct obstack temporary_obstack;
53static bool temporary_obstack_initialized_p;
54
55/* Parse a reasonable subset of shell quoting syntax.  */
56
57static char *
58extract_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
90static const char *
91get_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
120static FILE *
121open_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
141static char *
142afgets (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
153void
154init_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
208static FILE *
209reopen_repo_file_for_write (void)
210{
211  FILE *repo_file = fopen (repo_name, "w");
212
213  if (repo_file == 0)
214    {
215      error ("can't create repository information file %qs", repo_name);
216      flag_use_repository = 0;
217    }
218
219  return repo_file;
220}
221
222/* Emit any pending repos.  */
223
224void
225finish_repo (void)
226{
227  tree t;
228  char *dir, *args;
229  FILE *repo_file;
230
231  if (!flag_use_repository)
232    return;
233
234  if (errorcount || sorrycount)
235    return;
236
237  repo_file = reopen_repo_file_for_write ();
238  if (repo_file == 0)
239    goto out;
240
241  fprintf (repo_file, "M %s\n", main_input_filename);
242  dir = getpwd ();
243  fprintf (repo_file, "D %s\n", dir);
244  args = getenv ("COLLECT_GCC_OPTIONS");
245  if (args)
246    {
247      fprintf (repo_file, "A %s", args);
248      /* If -frandom-seed is not among the ARGS, then add the value
249	 that we chose.  That will ensure that the names of types from
250	 anonymous namespaces will get the same mangling when this
251	 file is recompiled.  */
252      if (!strstr (args, "'-frandom-seed="))
253	fprintf (repo_file, " '-frandom-seed=%s'", flag_random_seed);
254      fprintf (repo_file, "\n");
255    }
256
257  for (t = pending_repo; t; t = TREE_CHAIN (t))
258    {
259      tree val = TREE_VALUE (t);
260      tree name = DECL_ASSEMBLER_NAME (val);
261      char type = IDENTIFIER_REPO_CHOSEN (name) ? 'C' : 'O';
262      fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (name));
263    }
264
265 out:
266  if (repo_file)
267    fclose (repo_file);
268}
269
270/* DECL is a FUNCTION_DECL or VAR_DECL with vague linkage whose
271   definition is available in this translation unit.  Returns 0 if
272   this definition should not be emitted in this translation unit
273   because it will be emitted elsewhere.  Returns 1 if the repository
274   file indicates that that DECL should be emitted in this translation
275   unit, or 2 if the repository file is not in use.  */
276
277int
278repo_emit_p (tree decl)
279{
280  gcc_assert (TREE_PUBLIC (decl));
281  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
282	      || TREE_CODE (decl) == VAR_DECL);
283  gcc_assert (!DECL_REALLY_EXTERN (decl));
284
285  /* When not using the repository, emit everything.  */
286  if (!flag_use_repository)
287    return 2;
288
289  /* Only template instantiations are managed by the repository.  This
290     is an artificial restriction; the code in the prelinker and here
291     will work fine if all entities with vague linkage are managed by
292     the repository.  */
293  if (TREE_CODE (decl) == VAR_DECL)
294    {
295      tree type = NULL_TREE;
296      if (DECL_VTABLE_OR_VTT_P (decl))
297	type = DECL_CONTEXT (decl);
298      else if (DECL_TINFO_P (decl))
299	type = TREE_TYPE (DECL_NAME (decl));
300      if (!DECL_TEMPLATE_INSTANTIATION (decl)
301	  && (!TYPE_LANG_SPECIFIC (type)
302	      || !CLASSTYPE_TEMPLATE_INSTANTIATION (type)))
303	return 2;
304      /* Static data members initialized by constant expressions must
305	 be processed where needed so that their definitions are
306	 available.  */
307      if (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
308	  && DECL_CLASS_SCOPE_P (decl))
309	return 2;
310    }
311  else if (!DECL_TEMPLATE_INSTANTIATION (decl))
312    return 2;
313
314  /* For constructors and destructors, the repository contains
315     information about the clones -- not the original function --
316     because only the clones are emitted in the object file.  */
317  if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
318      || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
319    {
320      int emit_p = 0;
321      tree clone;
322      /* There is no early exit from this loop because we want to
323	 ensure that all of the clones are marked as available in this
324	 object file.  */
325      FOR_EACH_CLONE (clone, decl)
326	/* The only possible results from the recursive call to
327	   repo_emit_p are 0 or 1.  */
328	if (repo_emit_p (clone))
329	  emit_p = 1;
330      return emit_p;
331    }
332
333  /* Keep track of all available entities.  */
334  if (!DECL_REPO_AVAILABLE_P (decl))
335    {
336      DECL_REPO_AVAILABLE_P (decl) = 1;
337      pending_repo = tree_cons (NULL_TREE, decl, pending_repo);
338    }
339
340  return IDENTIFIER_REPO_CHOSEN (DECL_ASSEMBLER_NAME (decl));
341}
342
343/* Returns true iff the prelinker has explicitly marked CLASS_TYPE for
344   export from this translation unit.  */
345
346bool
347repo_export_class_p (tree class_type)
348{
349  if (!flag_use_repository)
350    return false;
351  if (!CLASSTYPE_VTABLES (class_type))
352    return false;
353  /* If the virtual table has been assigned to this translation unit,
354     export the class.  */
355  return (IDENTIFIER_REPO_CHOSEN
356	  (DECL_ASSEMBLER_NAME (CLASSTYPE_VTABLES (class_type))));
357}
358
359#include "gt-cp-repo.h"
360