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