1/* Code to maintain a C++ template repository.
2   Copyright (C) 1995-2015 Free Software Foundation, Inc.
3   Contributed by Jason Merrill (jason@cygnus.com)
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3.  If not see
19<http://www.gnu.org/licenses/>.  */
20
21/* My strategy here is as follows:
22
23   Everything should be emitted in a translation unit where it is used.
24   The results of the automatic process should be easily reproducible with
25   explicit code.  */
26
27#include "config.h"
28#include "system.h"
29#include "coretypes.h"
30#include "tm.h"
31#include "hash-set.h"
32#include "machmode.h"
33#include "vec.h"
34#include "double-int.h"
35#include "input.h"
36#include "alias.h"
37#include "symtab.h"
38#include "wide-int.h"
39#include "inchash.h"
40#include "tree.h"
41#include "stringpool.h"
42#include "cp-tree.h"
43#include "input.h"
44#include "obstack.h"
45#include "toplev.h"
46#include "diagnostic-core.h"
47#include "flags.h"
48
49static const char *extract_string (const char **);
50static const char *get_base_filename (const char *);
51static FILE *open_repo_file (const char *);
52static char *afgets (FILE *);
53static FILE *reopen_repo_file_for_write (void);
54
55static GTY(()) vec<tree, va_gc> *pending_repo;
56static char *repo_name;
57
58static const char *old_args, *old_dir, *old_main;
59
60static struct obstack temporary_obstack;
61static bool temporary_obstack_initialized_p;
62
63/* Parse a reasonable subset of shell quoting syntax.  */
64
65static const char *
66extract_string (const char **pp)
67{
68  const char *p = *pp;
69  int backquote = 0;
70  int inside = 0;
71
72  for (;;)
73    {
74      char c = *p;
75      if (c == '\0')
76	break;
77      ++p;
78      if (backquote)
79	{
80	  obstack_1grow (&temporary_obstack, c);
81	  backquote = 0;
82	}
83      else if (! inside && c == ' ')
84	break;
85      else if (! inside && c == '\\')
86	backquote = 1;
87      else if (c == '\'')
88	inside = !inside;
89      else
90	obstack_1grow (&temporary_obstack, c);
91    }
92
93  obstack_1grow (&temporary_obstack, '\0');
94  *pp = p;
95  return (char *) obstack_finish (&temporary_obstack);
96}
97
98static const char *
99get_base_filename (const char *filename)
100{
101  const char *p = getenv ("COLLECT_GCC_OPTIONS");
102  const char *output = NULL;
103  int compiling = 0;
104
105  while (p && *p)
106    {
107      const char *q = extract_string (&p);
108
109      if (strcmp (q, "-o") == 0)
110	{
111	  if (flag_compare_debug)
112	    /* Just in case aux_base_name was based on a name with two
113	       or more '.'s, add an arbitrary extension that will be
114	       stripped by the caller.  */
115	    output = concat (aux_base_name, ".o", NULL);
116	  else
117	    output = extract_string (&p);
118	}
119      else if (strcmp (q, "-c") == 0)
120	compiling = 1;
121    }
122
123  if (compiling && output)
124    return output;
125
126  if (p && ! compiling)
127    {
128      warning (0, "-frepo must be used with -c");
129      flag_use_repository = 0;
130      return NULL;
131    }
132
133  return lbasename (filename);
134}
135
136static FILE *
137open_repo_file (const char *filename)
138{
139  const char *p;
140  const char *s = get_base_filename (filename);
141
142  if (s == NULL)
143    return NULL;
144
145  p = lbasename (s);
146  p = strrchr (p, '.');
147  if (! p)
148    p = s + strlen (s);
149
150  repo_name = XNEWVEC (char, p - s + 5);
151  memcpy (repo_name, s, p - s);
152  memcpy (repo_name + (p - s), ".rpo", 5);
153
154  return fopen (repo_name, "r");
155}
156
157static char *
158afgets (FILE *stream)
159{
160  int c;
161  while ((c = getc (stream)) != EOF && c != '\n')
162    obstack_1grow (&temporary_obstack, c);
163  if (obstack_object_size (&temporary_obstack) == 0)
164    return NULL;
165  obstack_1grow (&temporary_obstack, '\0');
166  return (char *) obstack_finish (&temporary_obstack);
167}
168
169void
170init_repo (void)
171{
172  char *buf;
173  const char *p;
174  FILE *repo_file;
175
176  if (! flag_use_repository)
177    return;
178
179  /* When a PCH file is loaded, the entire identifier table is
180     replaced, with the result that IDENTIFIER_REPO_CHOSEN is cleared.
181     So, we have to reread the repository file.  */
182  lang_post_pch_load = init_repo;
183
184  if (!temporary_obstack_initialized_p)
185    gcc_obstack_init (&temporary_obstack);
186
187  repo_file = open_repo_file (main_input_filename);
188
189  if (repo_file == 0)
190    return;
191
192  while ((buf = afgets (repo_file)))
193    {
194      switch (buf[0])
195	{
196	case 'A':
197	  old_args = ggc_strdup (buf + 2);
198	  break;
199	case 'D':
200	  old_dir = ggc_strdup (buf + 2);
201	  break;
202	case 'M':
203	  old_main = ggc_strdup (buf + 2);
204	  break;
205	case 'O':
206	  /* A symbol that we were able to define the last time this
207	     file was compiled.  */
208	  break;
209	case 'C':
210	  /* A symbol that the prelinker has requested that we
211	     define.  */
212	  {
213	    tree id = get_identifier (buf + 2);
214	    IDENTIFIER_REPO_CHOSEN (id) = 1;
215	  }
216	  break;
217	default:
218	  error ("mysterious repository information in %s", repo_name);
219	}
220      obstack_free (&temporary_obstack, buf);
221    }
222  fclose (repo_file);
223
224  if (old_args && !get_random_seed (true)
225      && (p = strstr (old_args, "'-frandom-seed=")))
226    set_random_seed (extract_string (&p) + strlen ("-frandom-seed="));
227}
228
229static FILE *
230reopen_repo_file_for_write (void)
231{
232  FILE *repo_file = fopen (repo_name, "w");
233
234  if (repo_file == 0)
235    {
236      error ("can%'t create repository information file %qs", repo_name);
237      flag_use_repository = 0;
238    }
239
240  return repo_file;
241}
242
243/* Emit any pending repos.  */
244
245void
246finish_repo (void)
247{
248  tree val;
249  char *dir, *args;
250  FILE *repo_file;
251  unsigned ix;
252
253  if (!flag_use_repository || flag_compare_debug)
254    return;
255
256  if (seen_error ())
257    return;
258
259  repo_file = reopen_repo_file_for_write ();
260  if (repo_file == 0)
261    goto out;
262
263  fprintf (repo_file, "M %s\n", main_input_filename);
264  dir = getpwd ();
265  fprintf (repo_file, "D %s\n", dir);
266  args = getenv ("COLLECT_GCC_OPTIONS");
267  if (args)
268    {
269      fprintf (repo_file, "A %s", args);
270      /* If -frandom-seed is not among the ARGS, then add the value
271	 that we chose.  That will ensure that the names of types from
272	 anonymous namespaces will get the same mangling when this
273	 file is recompiled.  */
274      if (!strstr (args, "'-frandom-seed="))
275	fprintf (repo_file, " '-frandom-seed=" HOST_WIDE_INT_PRINT_HEX_PURE "'",
276		 get_random_seed (false));
277      fprintf (repo_file, "\n");
278    }
279
280  FOR_EACH_VEC_SAFE_ELT_REVERSE (pending_repo, ix, val)
281    {
282      tree name = DECL_ASSEMBLER_NAME (val);
283      char type = IDENTIFIER_REPO_CHOSEN (name) ? 'C' : 'O';
284      fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (name));
285    }
286
287 out:
288  if (repo_file)
289    fclose (repo_file);
290}
291
292/* DECL is a FUNCTION_DECL or VAR_DECL with vague linkage whose
293   definition is available in this translation unit.  Returns 0 if
294   this definition should not be emitted in this translation unit
295   because it will be emitted elsewhere.  Returns 1 if the repository
296   file indicates that that DECL should be emitted in this translation
297   unit, or 2 if the repository file is not in use.  */
298
299int
300repo_emit_p (tree decl)
301{
302  int ret = 0;
303  gcc_assert (TREE_PUBLIC (decl));
304  gcc_assert (VAR_OR_FUNCTION_DECL_P (decl));
305  gcc_assert (!DECL_REALLY_EXTERN (decl)
306	      /* A clone might not have its linkage flags updated yet
307		 because we call import_export_decl before
308		 maybe_clone_body.  */
309	      || DECL_ABSTRACT_ORIGIN (decl));
310
311  /* When not using the repository, emit everything.  */
312  if (!flag_use_repository)
313    return 2;
314
315  /* Only template instantiations are managed by the repository.  This
316     is an artificial restriction; the code in the prelinker and here
317     will work fine if all entities with vague linkage are managed by
318     the repository.  */
319  if (VAR_P (decl))
320    {
321      tree type = NULL_TREE;
322      if (DECL_VTABLE_OR_VTT_P (decl))
323	type = DECL_CONTEXT (decl);
324      else if (DECL_TINFO_P (decl))
325	type = TREE_TYPE (DECL_NAME (decl));
326      if (!DECL_TEMPLATE_INSTANTIATION (decl)
327	  && (!TYPE_LANG_SPECIFIC (type)
328	      || !CLASSTYPE_TEMPLATE_INSTANTIATION (type)))
329	return 2;
330      /* Const static data members initialized by constant expressions must
331	 be processed where needed so that their definitions are
332	 available.  Still record them into *.rpo files, so if they
333	 weren't actually emitted and collect2 requests them, they can
334	 be provided.  */
335      if (decl_maybe_constant_var_p (decl)
336	  && DECL_CLASS_SCOPE_P (decl))
337	ret = 2;
338    }
339  else if (!DECL_TEMPLATE_INSTANTIATION (decl))
340    return 2;
341
342  if (DECL_EXPLICIT_INSTANTIATION (decl))
343    return 2;
344
345  /* For constructors and destructors, the repository contains
346     information about the clones -- not the original function --
347     because only the clones are emitted in the object file.  */
348  if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
349      || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
350    {
351      int emit_p = 0;
352      tree clone;
353      /* There is no early exit from this loop because we want to
354	 ensure that all of the clones are marked as available in this
355	 object file.  */
356      FOR_EACH_CLONE (clone, decl)
357	/* The only possible results from the recursive call to
358	   repo_emit_p are 0 or 1.  */
359	if (repo_emit_p (clone))
360	  emit_p = 1;
361      return emit_p;
362    }
363
364  /* Keep track of all available entities.  */
365  if (!DECL_REPO_AVAILABLE_P (decl))
366    {
367      DECL_REPO_AVAILABLE_P (decl) = 1;
368      vec_safe_push (pending_repo, decl);
369    }
370
371  return IDENTIFIER_REPO_CHOSEN (DECL_ASSEMBLER_NAME (decl)) ? 1 : ret;
372}
373
374/* Returns true iff the prelinker has explicitly marked CLASS_TYPE for
375   export from this translation unit.  */
376
377bool
378repo_export_class_p (const_tree class_type)
379{
380  if (!flag_use_repository)
381    return false;
382  if (!CLASSTYPE_VTABLES (class_type))
383    return false;
384  /* If the virtual table has been assigned to this translation unit,
385     export the class.  */
386  return (IDENTIFIER_REPO_CHOSEN
387	  (DECL_ASSEMBLER_NAME (CLASSTYPE_VTABLES (class_type))));
388}
389
390#include "gt-cp-repo.h"
391