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