repo.c revision 52284
118334Speter/* Code to maintain a C++ template repository.
252284Sobrien   Copyright (C) 1995, 96-97, 1998 Free Software Foundation, Inc.
318334Speter   Contributed by Jason Merrill (jason@cygnus.com)
418334Speter
518334SpeterThis file is part of GNU CC.
618334Speter
718334SpeterGNU CC is free software; you can redistribute it and/or modify
818334Speterit under the terms of the GNU General Public License as published by
918334Speterthe Free Software Foundation; either version 2, or (at your option)
1018334Speterany later version.
1118334Speter
1218334SpeterGNU CC is distributed in the hope that it will be useful,
1318334Speterbut WITHOUT ANY WARRANTY; without even the implied warranty of
1418334SpeterMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1518334SpeterGNU General Public License for more details.
1618334Speter
1718334SpeterYou should have received a copy of the GNU General Public License
1818334Speteralong with GNU CC; see the file COPYING.  If not, write to
1918334Speterthe Free Software Foundation, 59 Temple Place - Suite 330,
2018334SpeterBoston, MA 02111-1307, USA.  */
2118334Speter
2218334Speter/* My strategy here is as follows:
2318334Speter
2418334Speter   Everything should be emitted in a translation unit where it is used.
2518334Speter   The results of the automatic process should be easily reproducible with
2618334Speter   explicit code.  */
2718334Speter
2818334Speter#include "config.h"
2950397Sobrien#include "system.h"
3018334Speter#include "tree.h"
3118334Speter#include "cp-tree.h"
3218334Speter#include "input.h"
3318334Speter#include "obstack.h"
3450397Sobrien#include "toplev.h"
3518334Speter
3650397Sobrienextern char *getpwd PROTO((void));
3718334Speter
3850397Sobrienstatic tree repo_get_id PROTO((tree));
3950397Sobrienstatic char *extract_string PROTO((char **));
4052284Sobrienstatic char *get_base_filename PROTO((const char *));
4152284Sobrienstatic void open_repo_file PROTO((const char *));
4250397Sobrienstatic char *afgets PROTO((FILE *));
4350397Sobrienstatic void reopen_repo_file_for_write PROTO((void));
4450397Sobrien
4518334Speterstatic tree pending_repo;
4618334Speterstatic tree original_repo;
4718334Speterstatic char *repo_name;
4818334Speterstatic FILE *repo_file;
4918334Speter
5050397Sobrienstatic char *old_args, *old_dir, *old_main;
5150397Sobrien
5218334Speterextern int flag_use_repository;
5318334Speterextern int errorcount, sorrycount;
5418334Speterextern struct obstack temporary_obstack;
5518334Speterextern struct obstack permanent_obstack;
5618334Speter
5718334Speter#define IDENTIFIER_REPO_USED(NODE)   (TREE_LANG_FLAG_3 (NODE))
5818334Speter#define IDENTIFIER_REPO_CHOSEN(NODE) (TREE_LANG_FLAG_4 (NODE))
5918334Speter
6050397Sobrien#if 0
6118334Speter/* Record the flags used to compile this translation unit.  */
6218334Speter
6318334Spetervoid
6418334Speterrepo_compile_flags (argc, argv)
6518334Speter     int argc;
6618334Speter     char **argv;
6718334Speter{
6818334Speter}
6918334Speter
7018334Speter/* If this template has not been seen before, add a note to the repository
7118334Speter   saying where the declaration was.  This may be used to find the
7218334Speter   definition at link time.  */
7318334Speter
7418334Spetervoid
7518334Speterrepo_template_declared (t)
7618334Speter     tree t;
7718334Speter{}
7818334Speter
7918334Speter/* Note where the definition of a template lives so that instantiations can
8018334Speter   be generated later.  */
8118334Speter
8218334Spetervoid
8318334Speterrepo_template_defined (t)
8418334Speter     tree t;
8518334Speter{}
8618334Speter
8718334Speter/* Note where the definition of a class lives to that template
8818334Speter   instantiations can use it.  */
8918334Speter
9018334Spetervoid
9118334Speterrepo_class_defined (t)
9218334Speter     tree t;
9318334Speter{}
9450397Sobrien#endif
9518334Speter
9650397Sobrienstatic tree
9718334Speterrepo_get_id (t)
9818334Speter     tree t;
9918334Speter{
10018334Speter  if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
10118334Speter    {
10252284Sobrien      /* If we're not done setting up the class, we may not have set up
10352284Sobrien	 the vtable, so going ahead would give the wrong answer.
10452284Sobrien         See g++.pt/instantiate4.C.  */
10552284Sobrien      if (TYPE_SIZE (t) == NULL_TREE || TYPE_BEING_DEFINED (t))
10652284Sobrien	my_friendly_abort (981113);
10752284Sobrien
10818334Speter      t = TYPE_BINFO_VTABLE (t);
10918334Speter      if (t == NULL_TREE)
11018334Speter	return t;
11118334Speter    }
11218334Speter  return DECL_ASSEMBLER_NAME (t);
11318334Speter}
11418334Speter
11518334Speter/* Note that a template has been used.  If we can see the definition, offer
11650397Sobrien   to emit it.  */
11718334Speter
11818334Spetervoid
11918334Speterrepo_template_used (t)
12018334Speter     tree t;
12118334Speter{
12218334Speter  tree id;
12318334Speter
12418334Speter  if (! flag_use_repository)
12518334Speter    return;
12618334Speter
12718334Speter  id = repo_get_id (t);
12818334Speter  if (id == NULL_TREE)
12918334Speter    return;
13018334Speter
13118334Speter  if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
13218334Speter    {
13318334Speter      if (IDENTIFIER_REPO_CHOSEN (id))
13418334Speter	mark_class_instantiated (t, 0);
13518334Speter    }
13618334Speter  else if (TREE_CODE_CLASS (TREE_CODE (t)) == 'd')
13718334Speter    {
13818334Speter      if (IDENTIFIER_REPO_CHOSEN (id))
13950397Sobrien	mark_decl_instantiated (t, 0);
14018334Speter    }
14118334Speter  else
14218334Speter    my_friendly_abort (1);
14318334Speter
14418334Speter  if (! IDENTIFIER_REPO_USED (id))
14518334Speter    {
14618334Speter      IDENTIFIER_REPO_USED (id) = 1;
14718334Speter      pending_repo = perm_tree_cons (NULL_TREE, id, pending_repo);
14818334Speter    }
14918334Speter}
15018334Speter
15150397Sobrien#if 0
15218334Speter/* Note that the vtable for a class has been used, and offer to emit it.  */
15318334Speter
15450397Sobrienstatic void
15518334Speterrepo_vtable_used (t)
15618334Speter     tree t;
15718334Speter{
15818334Speter  if (! flag_use_repository)
15918334Speter    return;
16018334Speter
16118334Speter  pending_repo = perm_tree_cons (NULL_TREE, t, pending_repo);
16218334Speter}
16318334Speter
16418334Speter/* Note that an inline with external linkage has been used, and offer to
16518334Speter   emit it.  */
16618334Speter
16718334Spetervoid
16818334Speterrepo_inline_used (fn)
16918334Speter     tree fn;
17018334Speter{
17118334Speter  if (! flag_use_repository)
17218334Speter    return;
17318334Speter
17418334Speter  /* Member functions of polymorphic classes go with their vtables.  */
17518334Speter  if (DECL_FUNCTION_MEMBER_P (fn) && TYPE_VIRTUAL_P (DECL_CLASS_CONTEXT (fn)))
17618334Speter    {
17718334Speter      repo_vtable_used (DECL_CLASS_CONTEXT (fn));
17818334Speter      return;
17918334Speter    }
18018334Speter
18118334Speter  pending_repo = perm_tree_cons (NULL_TREE, fn, pending_repo);
18218334Speter}
18318334Speter
18418334Speter/* Note that a particular typeinfo node has been used, and offer to
18518334Speter   emit it.  */
18618334Speter
18718334Spetervoid
18818334Speterrepo_tinfo_used (ti)
18918334Speter     tree ti;
19018334Speter{
19118334Speter}
19250397Sobrien#endif
19318334Speter
19418334Spetervoid
19518334Speterrepo_template_instantiated (t, extern_p)
19618334Speter     tree t;
19718334Speter     int extern_p;
19818334Speter{
19918334Speter  if (! extern_p)
20018334Speter    {
20118334Speter      tree id = repo_get_id (t);
20218334Speter      if (id)
20318334Speter	IDENTIFIER_REPO_CHOSEN (id) = 1;
20418334Speter    }
20518334Speter}
20618334Speter
20750397Sobrien/* Parse a reasonable subset of shell quoting syntax.  */
20850397Sobrien
20918334Speterstatic char *
21050397Sobrienextract_string (pp)
21150397Sobrien     char **pp;
21218334Speter{
21350397Sobrien  char *p = *pp;
21450397Sobrien  int backquote = 0;
21550397Sobrien  int inside = 0;
21650397Sobrien
21750397Sobrien  for (;;)
21850397Sobrien    {
21950397Sobrien      char c = *p;
22050397Sobrien      if (c == '\0')
22150397Sobrien	break;
22250397Sobrien      ++p;
22350397Sobrien      if (backquote)
22450397Sobrien	obstack_1grow (&temporary_obstack, c);
22550397Sobrien      else if (! inside && c == ' ')
22650397Sobrien	break;
22750397Sobrien      else if (! inside && c == '\\')
22850397Sobrien	backquote = 1;
22950397Sobrien      else if (c == '\'')
23050397Sobrien	inside = !inside;
23150397Sobrien      else
23250397Sobrien	obstack_1grow (&temporary_obstack, c);
23350397Sobrien    }
23450397Sobrien
23550397Sobrien  obstack_1grow (&temporary_obstack, '\0');
23650397Sobrien  *pp = p;
23750397Sobrien  return obstack_finish (&temporary_obstack);
23818334Speter}
23918334Speter
24018334Speterstatic char *
24118334Speterget_base_filename (filename)
24252284Sobrien     const char *filename;
24318334Speter{
24418334Speter  char *p = getenv ("COLLECT_GCC_OPTIONS");
24550397Sobrien  char *output = NULL;
24618334Speter  int compiling = 0;
24718334Speter
24850397Sobrien  while (p && *p)
24950397Sobrien    {
25050397Sobrien      char *q = extract_string (&p);
25118334Speter
25250397Sobrien      if (strcmp (q, "-o") == 0)
25350397Sobrien	output = extract_string (&p);
25450397Sobrien      else if (strcmp (q, "-c") == 0)
25550397Sobrien	compiling = 1;
25618334Speter      }
25718334Speter
25818334Speter  if (compiling && output)
25918334Speter    return output;
26018334Speter
26118334Speter  if (p && ! compiling)
26218334Speter    {
26318334Speter      warning ("-frepo must be used with -c");
26418334Speter      flag_use_repository = 0;
26518334Speter      return NULL;
26618334Speter    }
26718334Speter
26850397Sobrien  return file_name_nondirectory (filename);
26918334Speter}
27018334Speter
27118334Speterstatic void
27218334Speteropen_repo_file (filename)
27352284Sobrien     const char *filename;
27418334Speter{
27552284Sobrien  register const char *p;
27652284Sobrien  const char *s = get_base_filename (filename);
27718334Speter
27818334Speter  if (s == NULL)
27918334Speter    return;
28018334Speter
28150397Sobrien  p = file_name_nondirectory (s);
28218334Speter  p = rindex (p, '.');
28318334Speter  if (! p)
28418334Speter    p = s + strlen (s);
28518334Speter
28618334Speter  obstack_grow (&permanent_obstack, s, p - s);
28718334Speter  repo_name = obstack_copy0 (&permanent_obstack, ".rpo", 4);
28818334Speter
28918334Speter  repo_file = fopen (repo_name, "r");
29018334Speter}
29118334Speter
29218334Speterstatic char *
29318334Speterafgets (stream)
29418334Speter     FILE *stream;
29518334Speter{
29618334Speter  int c;
29718334Speter  while ((c = getc (stream)) != EOF && c != '\n')
29818334Speter    obstack_1grow (&temporary_obstack, c);
29918334Speter  if (obstack_object_size (&temporary_obstack) == 0)
30018334Speter    return NULL;
30118334Speter  obstack_1grow (&temporary_obstack, '\0');
30218334Speter  return obstack_finish (&temporary_obstack);
30318334Speter}
30418334Speter
30518334Spetervoid
30618334Speterinit_repo (filename)
30752284Sobrien     const char *filename;
30818334Speter{
30918334Speter  char *buf;
31018334Speter
31118334Speter  if (! flag_use_repository)
31218334Speter    return;
31318334Speter
31418334Speter  open_repo_file (filename);
31518334Speter
31618334Speter  if (repo_file == 0)
31718334Speter    return;
31818334Speter
31950397Sobrien  while ((buf = afgets (repo_file)))
32018334Speter    {
32118334Speter      switch (buf[0])
32218334Speter	{
32318334Speter	case 'A':
32450397Sobrien	  old_args = obstack_copy0 (&permanent_obstack, buf + 2,
32550397Sobrien				    strlen (buf + 2));
32650397Sobrien	  break;
32718334Speter	case 'D':
32850397Sobrien	  old_dir = obstack_copy0 (&permanent_obstack, buf + 2,
32950397Sobrien				   strlen (buf + 2));
33050397Sobrien	  break;
33118334Speter	case 'M':
33250397Sobrien	  old_main = obstack_copy0 (&permanent_obstack, buf + 2,
33350397Sobrien				    strlen (buf + 2));
33418334Speter	  break;
33518334Speter	case 'C':
33618334Speter	case 'O':
33718334Speter	  {
33818334Speter	    tree id = get_identifier (buf + 2);
33918334Speter	    tree orig;
34018334Speter
34118334Speter	    if (buf[0] == 'C')
34218334Speter	      {
34318334Speter		IDENTIFIER_REPO_CHOSEN (id) = 1;
34418334Speter		orig = integer_one_node;
34518334Speter	      }
34618334Speter	    else
34718334Speter	      orig = NULL_TREE;
34818334Speter
34918334Speter	    original_repo = perm_tree_cons (orig, id, original_repo);
35018334Speter	  }
35118334Speter	  break;
35218334Speter	default:
35318334Speter	  error ("mysterious repository information in %s", repo_name);
35418334Speter	}
35518334Speter      obstack_free (&temporary_obstack, buf);
35618334Speter    }
35718334Speter}
35818334Speter
35918334Speterstatic void
36018334Speterreopen_repo_file_for_write ()
36118334Speter{
36218334Speter  if (repo_file)
36318334Speter    fclose (repo_file);
36418334Speter  repo_file = fopen (repo_name, "w");
36518334Speter
36618334Speter  if (repo_file == 0)
36718334Speter    {
36818334Speter      error ("can't create repository information file `%s'", repo_name);
36918334Speter      flag_use_repository = 0;
37018334Speter    }
37118334Speter}
37218334Speter
37318334Speter/* Emit any pending repos.  */
37418334Speter
37518334Spetervoid
37618334Speterfinish_repo ()
37718334Speter{
37818334Speter  tree t;
37918334Speter  int repo_changed = 0;
38050397Sobrien  char *dir, *args;
38118334Speter
38218334Speter  if (! flag_use_repository)
38318334Speter    return;
38418334Speter
38518334Speter  /* Do we have to write out a new info file?  */
38618334Speter
38718334Speter  /* Are there any old templates that aren't used any longer or that are
38818334Speter     newly chosen?  */
38918334Speter
39018334Speter  for (t = original_repo; t; t = TREE_CHAIN (t))
39118334Speter    {
39218334Speter      if (! IDENTIFIER_REPO_USED (TREE_VALUE (t))
39318334Speter	  || (! TREE_PURPOSE (t) && IDENTIFIER_REPO_CHOSEN (TREE_VALUE (t))))
39418334Speter	{
39518334Speter	  repo_changed = 1;
39618334Speter	  break;
39718334Speter	}
39818334Speter      IDENTIFIER_REPO_USED (TREE_VALUE (t)) = 0;
39918334Speter    }
40018334Speter
40118334Speter  /* Are there any templates that are newly used?  */
40218334Speter
40318334Speter  if (! repo_changed)
40418334Speter    for (t = pending_repo; t; t = TREE_CHAIN (t))
40518334Speter      {
40618334Speter	if (IDENTIFIER_REPO_USED (TREE_VALUE (t)))
40718334Speter	  {
40818334Speter	    repo_changed = 1;
40918334Speter	    break;
41018334Speter	  }
41118334Speter      }
41218334Speter
41350397Sobrien  dir = getpwd ();
41450397Sobrien  args = getenv ("COLLECT_GCC_OPTIONS");
41550397Sobrien
41650397Sobrien  if (! repo_changed && pending_repo)
41750397Sobrien    if (strcmp (old_main, main_input_filename) != 0
41850397Sobrien	|| strcmp (old_dir, dir) != 0
41950397Sobrien	|| (args == NULL) != (old_args == NULL)
42050397Sobrien	|| (args && strcmp (old_args, args) != 0))
42150397Sobrien      repo_changed = 1;
42250397Sobrien
42318334Speter  if (! repo_changed || errorcount || sorrycount)
42418334Speter    goto out;
42518334Speter
42618334Speter  reopen_repo_file_for_write ();
42718334Speter
42818334Speter  if (repo_file == 0)
42918334Speter    goto out;
43018334Speter
43118334Speter  fprintf (repo_file, "M %s\n", main_input_filename);
43250397Sobrien  fprintf (repo_file, "D %s\n", dir);
43350397Sobrien  if (args)
43450397Sobrien    fprintf (repo_file, "A %s\n", args);
43518334Speter
43618334Speter  for (t = pending_repo; t; t = TREE_CHAIN (t))
43718334Speter    {
43818334Speter      tree val = TREE_VALUE (t);
43918334Speter      char type = IDENTIFIER_REPO_CHOSEN (val) ? 'C' : 'O';
44018334Speter
44118334Speter      fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (val));
44218334Speter    }
44318334Speter
44418334Speter out:
44518334Speter  if (repo_file)
44618334Speter    fclose (repo_file);
44718334Speter}
448