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