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