118334Speter/* Code to maintain a C++ template repository.
2169689Skan   Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005
3132718Skan   Free Software Foundation, Inc.
418334Speter   Contributed by Jason Merrill (jason@cygnus.com)
518334Speter
6132718SkanThis file is part of GCC.
718334Speter
8132718SkanGCC is free software; you can redistribute it and/or modify
918334Speterit under the terms of the GNU General Public License as published by
1018334Speterthe Free Software Foundation; either version 2, or (at your option)
1118334Speterany later version.
1218334Speter
13132718SkanGCC is distributed in the hope that it will be useful,
1418334Speterbut WITHOUT ANY WARRANTY; without even the implied warranty of
1518334SpeterMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1618334SpeterGNU General Public License for more details.
1718334Speter
1818334SpeterYou should have received a copy of the GNU General Public License
19132718Skanalong with GCC; see the file COPYING.  If not, write to
20169689Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor,
21169689SkanBoston, MA 02110-1301, USA.  */
2218334Speter
2318334Speter/* My strategy here is as follows:
2418334Speter
2518334Speter   Everything should be emitted in a translation unit where it is used.
2618334Speter   The results of the automatic process should be easily reproducible with
2718334Speter   explicit code.  */
2818334Speter
2918334Speter#include "config.h"
3050397Sobrien#include "system.h"
31132718Skan#include "coretypes.h"
32132718Skan#include "tm.h"
3318334Speter#include "tree.h"
3418334Speter#include "cp-tree.h"
3518334Speter#include "input.h"
3618334Speter#include "obstack.h"
3750397Sobrien#include "toplev.h"
3890075Sobrien#include "diagnostic.h"
39169689Skan#include "flags.h"
4018334Speter
41132718Skanstatic char *extract_string (char **);
42132718Skanstatic const char *get_base_filename (const char *);
43169689Skanstatic FILE *open_repo_file (const char *);
44132718Skanstatic char *afgets (FILE *);
45169689Skanstatic FILE *reopen_repo_file_for_write (void);
4618334Speter
47117395Skanstatic GTY(()) tree pending_repo;
4818334Speterstatic char *repo_name;
4918334Speter
50117395Skanstatic const char *old_args, *old_dir, *old_main;
5150397Sobrien
5290075Sobrienstatic struct obstack temporary_obstack;
53169689Skanstatic bool temporary_obstack_initialized_p;
5418334Speter
5550397Sobrien/* Parse a reasonable subset of shell quoting syntax.  */
5650397Sobrien
5718334Speterstatic char *
58132718Skanextract_string (char **pp)
5918334Speter{
6050397Sobrien  char *p = *pp;
6150397Sobrien  int backquote = 0;
6250397Sobrien  int inside = 0;
6350397Sobrien
6450397Sobrien  for (;;)
6550397Sobrien    {
6650397Sobrien      char c = *p;
6750397Sobrien      if (c == '\0')
6850397Sobrien	break;
6950397Sobrien      ++p;
7050397Sobrien      if (backquote)
71169689Skan	{
72169689Skan	  obstack_1grow (&temporary_obstack, c);
73169689Skan	  backquote = 0;
74169689Skan	}
7550397Sobrien      else if (! inside && c == ' ')
7650397Sobrien	break;
7750397Sobrien      else if (! inside && c == '\\')
7850397Sobrien	backquote = 1;
7950397Sobrien      else if (c == '\'')
8050397Sobrien	inside = !inside;
8150397Sobrien      else
8250397Sobrien	obstack_1grow (&temporary_obstack, c);
8350397Sobrien    }
8450397Sobrien
8550397Sobrien  obstack_1grow (&temporary_obstack, '\0');
8650397Sobrien  *pp = p;
87169689Skan  return (char *) obstack_finish (&temporary_obstack);
8818334Speter}
8918334Speter
90132718Skanstatic const char *
91132718Skanget_base_filename (const char *filename)
9218334Speter{
9318334Speter  char *p = getenv ("COLLECT_GCC_OPTIONS");
9450397Sobrien  char *output = NULL;
9518334Speter  int compiling = 0;
9618334Speter
9750397Sobrien  while (p && *p)
9850397Sobrien    {
9950397Sobrien      char *q = extract_string (&p);
10018334Speter
10150397Sobrien      if (strcmp (q, "-o") == 0)
10250397Sobrien	output = extract_string (&p);
10350397Sobrien      else if (strcmp (q, "-c") == 0)
10450397Sobrien	compiling = 1;
105169689Skan    }
10618334Speter
10718334Speter  if (compiling && output)
10818334Speter    return output;
10918334Speter
11018334Speter  if (p && ! compiling)
11118334Speter    {
112169689Skan      warning (0, "-frepo must be used with -c");
11318334Speter      flag_use_repository = 0;
11418334Speter      return NULL;
11518334Speter    }
11618334Speter
11790075Sobrien  return lbasename (filename);
118169689Skan}
11918334Speter
120169689Skanstatic FILE *
121132718Skanopen_repo_file (const char *filename)
12218334Speter{
123132718Skan  const char *p;
12452284Sobrien  const char *s = get_base_filename (filename);
12518334Speter
12618334Speter  if (s == NULL)
127169689Skan    return NULL;
12818334Speter
12990075Sobrien  p = lbasename (s);
13090075Sobrien  p = strrchr (p, '.');
13118334Speter  if (! p)
13218334Speter    p = s + strlen (s);
13318334Speter
134169689Skan  repo_name = XNEWVEC (char, p - s + 5);
135117395Skan  memcpy (repo_name, s, p - s);
136117395Skan  memcpy (repo_name + (p - s), ".rpo", 5);
13718334Speter
138169689Skan  return fopen (repo_name, "r");
13918334Speter}
14018334Speter
14118334Speterstatic char *
142132718Skanafgets (FILE *stream)
14318334Speter{
14418334Speter  int c;
14518334Speter  while ((c = getc (stream)) != EOF && c != '\n')
14618334Speter    obstack_1grow (&temporary_obstack, c);
14718334Speter  if (obstack_object_size (&temporary_obstack) == 0)
14818334Speter    return NULL;
14918334Speter  obstack_1grow (&temporary_obstack, '\0');
150169689Skan  return (char *) obstack_finish (&temporary_obstack);
15118334Speter}
15218334Speter
15318334Spetervoid
154169689Skaninit_repo (void)
15518334Speter{
15618334Speter  char *buf;
157169689Skan  FILE *repo_file;
15818334Speter
15918334Speter  if (! flag_use_repository)
16018334Speter    return;
16118334Speter
162169689Skan  /* When a PCH file is loaded, the entire identifier table is
163169689Skan     replaced, with the result that IDENTIFIER_REPO_CHOSEN is cleared.
164169689Skan     So, we have to reread the repository file.  */
165169689Skan  lang_post_pch_load = init_repo;
16690075Sobrien
167169689Skan  if (!temporary_obstack_initialized_p)
168169689Skan    gcc_obstack_init (&temporary_obstack);
16918334Speter
170169689Skan  repo_file = open_repo_file (main_input_filename);
171169689Skan
17218334Speter  if (repo_file == 0)
17318334Speter    return;
17418334Speter
17550397Sobrien  while ((buf = afgets (repo_file)))
17618334Speter    {
17718334Speter      switch (buf[0])
17818334Speter	{
17918334Speter	case 'A':
180117395Skan	  old_args = ggc_strdup (buf + 2);
18150397Sobrien	  break;
18218334Speter	case 'D':
183117395Skan	  old_dir = ggc_strdup (buf + 2);
18450397Sobrien	  break;
18518334Speter	case 'M':
186117395Skan	  old_main = ggc_strdup (buf + 2);
18718334Speter	  break;
188169689Skan	case 'O':
189169689Skan	  /* A symbol that we were able to define the last time this
190169689Skan	     file was compiled.  */
191169689Skan	  break;
19218334Speter	case 'C':
193169689Skan	  /* A symbol that the prelinker has requested that we
194169689Skan	     define.  */
19518334Speter	  {
19618334Speter	    tree id = get_identifier (buf + 2);
197169689Skan	    IDENTIFIER_REPO_CHOSEN (id) = 1;
19818334Speter	  }
19918334Speter	  break;
20018334Speter	default:
20118334Speter	  error ("mysterious repository information in %s", repo_name);
20218334Speter	}
20318334Speter      obstack_free (&temporary_obstack, buf);
20418334Speter    }
205169689Skan  fclose (repo_file);
20618334Speter}
20718334Speter
208169689Skanstatic FILE *
209132718Skanreopen_repo_file_for_write (void)
21018334Speter{
211169689Skan  FILE *repo_file = fopen (repo_name, "w");
21218334Speter
21318334Speter  if (repo_file == 0)
21418334Speter    {
215169689Skan      error ("can't create repository information file %qs", repo_name);
21618334Speter      flag_use_repository = 0;
21718334Speter    }
218169689Skan
219169689Skan  return repo_file;
22018334Speter}
22118334Speter
22218334Speter/* Emit any pending repos.  */
22318334Speter
22418334Spetervoid
225132718Skanfinish_repo (void)
22618334Speter{
22718334Speter  tree t;
22850397Sobrien  char *dir, *args;
229169689Skan  FILE *repo_file;
23018334Speter
231132718Skan  if (!flag_use_repository)
23218334Speter    return;
23318334Speter
234169689Skan  if (errorcount || sorrycount)
235169689Skan    return;
23618334Speter
237169689Skan  repo_file = reopen_repo_file_for_write ();
23818334Speter  if (repo_file == 0)
23918334Speter    goto out;
24018334Speter
24118334Speter  fprintf (repo_file, "M %s\n", main_input_filename);
242169689Skan  dir = getpwd ();
24350397Sobrien  fprintf (repo_file, "D %s\n", dir);
244169689Skan  args = getenv ("COLLECT_GCC_OPTIONS");
24550397Sobrien  if (args)
246169689Skan    {
247169689Skan      fprintf (repo_file, "A %s", args);
248169689Skan      /* If -frandom-seed is not among the ARGS, then add the value
249169689Skan	 that we chose.  That will ensure that the names of types from
250169689Skan	 anonymous namespaces will get the same mangling when this
251169689Skan	 file is recompiled.  */
252169689Skan      if (!strstr (args, "'-frandom-seed="))
253169689Skan	fprintf (repo_file, " '-frandom-seed=%s'", flag_random_seed);
254169689Skan      fprintf (repo_file, "\n");
255169689Skan    }
25618334Speter
25718334Speter  for (t = pending_repo; t; t = TREE_CHAIN (t))
25818334Speter    {
25918334Speter      tree val = TREE_VALUE (t);
260169689Skan      tree name = DECL_ASSEMBLER_NAME (val);
261169689Skan      char type = IDENTIFIER_REPO_CHOSEN (name) ? 'C' : 'O';
262169689Skan      fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (name));
26318334Speter    }
26418334Speter
26518334Speter out:
26618334Speter  if (repo_file)
26718334Speter    fclose (repo_file);
26818334Speter}
269117395Skan
270169689Skan/* DECL is a FUNCTION_DECL or VAR_DECL with vague linkage whose
271169689Skan   definition is available in this translation unit.  Returns 0 if
272169689Skan   this definition should not be emitted in this translation unit
273169689Skan   because it will be emitted elsewhere.  Returns 1 if the repository
274169689Skan   file indicates that that DECL should be emitted in this translation
275169689Skan   unit, or 2 if the repository file is not in use.  */
276169689Skan
277169689Skanint
278169689Skanrepo_emit_p (tree decl)
279169689Skan{
280169689Skan  gcc_assert (TREE_PUBLIC (decl));
281169689Skan  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
282169689Skan	      || TREE_CODE (decl) == VAR_DECL);
283169689Skan  gcc_assert (!DECL_REALLY_EXTERN (decl));
284169689Skan
285169689Skan  /* When not using the repository, emit everything.  */
286169689Skan  if (!flag_use_repository)
287169689Skan    return 2;
288169689Skan
289169689Skan  /* Only template instantiations are managed by the repository.  This
290169689Skan     is an artificial restriction; the code in the prelinker and here
291169689Skan     will work fine if all entities with vague linkage are managed by
292169689Skan     the repository.  */
293169689Skan  if (TREE_CODE (decl) == VAR_DECL)
294169689Skan    {
295169689Skan      tree type = NULL_TREE;
296169689Skan      if (DECL_VTABLE_OR_VTT_P (decl))
297169689Skan	type = DECL_CONTEXT (decl);
298169689Skan      else if (DECL_TINFO_P (decl))
299169689Skan	type = TREE_TYPE (DECL_NAME (decl));
300169689Skan      if (!DECL_TEMPLATE_INSTANTIATION (decl)
301169689Skan	  && (!TYPE_LANG_SPECIFIC (type)
302169689Skan	      || !CLASSTYPE_TEMPLATE_INSTANTIATION (type)))
303169689Skan	return 2;
304169689Skan      /* Static data members initialized by constant expressions must
305169689Skan	 be processed where needed so that their definitions are
306169689Skan	 available.  */
307169689Skan      if (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
308169689Skan	  && DECL_CLASS_SCOPE_P (decl))
309169689Skan	return 2;
310169689Skan    }
311169689Skan  else if (!DECL_TEMPLATE_INSTANTIATION (decl))
312169689Skan    return 2;
313169689Skan
314169689Skan  /* For constructors and destructors, the repository contains
315169689Skan     information about the clones -- not the original function --
316169689Skan     because only the clones are emitted in the object file.  */
317169689Skan  if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
318169689Skan      || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
319169689Skan    {
320169689Skan      int emit_p = 0;
321169689Skan      tree clone;
322169689Skan      /* There is no early exit from this loop because we want to
323169689Skan	 ensure that all of the clones are marked as available in this
324169689Skan	 object file.  */
325169689Skan      FOR_EACH_CLONE (clone, decl)
326169689Skan	/* The only possible results from the recursive call to
327169689Skan	   repo_emit_p are 0 or 1.  */
328169689Skan	if (repo_emit_p (clone))
329169689Skan	  emit_p = 1;
330169689Skan      return emit_p;
331169689Skan    }
332169689Skan
333169689Skan  /* Keep track of all available entities.  */
334169689Skan  if (!DECL_REPO_AVAILABLE_P (decl))
335169689Skan    {
336169689Skan      DECL_REPO_AVAILABLE_P (decl) = 1;
337169689Skan      pending_repo = tree_cons (NULL_TREE, decl, pending_repo);
338169689Skan    }
339169689Skan
340169689Skan  return IDENTIFIER_REPO_CHOSEN (DECL_ASSEMBLER_NAME (decl));
341169689Skan}
342169689Skan
343169689Skan/* Returns true iff the prelinker has explicitly marked CLASS_TYPE for
344169689Skan   export from this translation unit.  */
345169689Skan
346169689Skanbool
347169689Skanrepo_export_class_p (tree class_type)
348169689Skan{
349169689Skan  if (!flag_use_repository)
350169689Skan    return false;
351169689Skan  if (!CLASSTYPE_VTABLES (class_type))
352169689Skan    return false;
353169689Skan  /* If the virtual table has been assigned to this translation unit,
354169689Skan     export the class.  */
355169689Skan  return (IDENTIFIER_REPO_CHOSEN
356169689Skan	  (DECL_ASSEMBLER_NAME (CLASSTYPE_VTABLES (class_type))));
357169689Skan}
358169689Skan
359117395Skan#include "gt-cp-repo.h"
360