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