xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/cp/repo.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11 
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along 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 
49 static const char *extract_string (const char **);
50 static const char *get_base_filename (const char *);
51 static FILE *open_repo_file (const char *);
52 static char *afgets (FILE *);
53 static FILE *reopen_repo_file_for_write (void);
54 
55 static GTY(()) vec<tree, va_gc> *pending_repo;
56 static char *repo_name;
57 
58 static const char *old_args, *old_dir, *old_main;
59 
60 static struct obstack temporary_obstack;
61 static bool temporary_obstack_initialized_p;
62 
63 /* Parse a reasonable subset of shell quoting syntax.  */
64 
65 static const char *
66 extract_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 
98 static const char *
99 get_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 
136 static FILE *
137 open_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 
157 static char *
158 afgets (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 
169 void
170 init_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 
229 static FILE *
230 reopen_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 
245 void
246 finish_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 
299 int
300 repo_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 
377 bool
378 repo_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