xref: /dflybsd-src/contrib/gcc-8.0/gcc/cp/repo.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
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