1/* Code to maintain a C++ template repository. 2 Copyright (C) 1995, 96-97, 1998 Free Software Foundation, Inc. 3 Contributed by Jason Merrill (jason@cygnus.com) 4 5This file is part of GNU CC. 6 7GNU CC is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2, or (at your option) 10any later version. 11 12GNU CC is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with GNU CC; see the file COPYING. If not, write to 19the Free Software Foundation, 59 Temple Place - Suite 330, 20Boston, MA 02111-1307, USA. */ 21 22/* My strategy here is as follows: 23 24 Everything should be emitted in a translation unit where it is used. 25 The results of the automatic process should be easily reproducible with 26 explicit code. */ 27 28#include "config.h" 29#include "system.h" 30#include "tree.h" 31#include "cp-tree.h" 32#include "input.h" 33#include "obstack.h" 34#include "toplev.h" 35 36extern char *getpwd PROTO((void)); 37 38static tree repo_get_id PROTO((tree)); 39static char *extract_string PROTO((char **)); 40static char *get_base_filename PROTO((const char *)); 41static void open_repo_file PROTO((const char *)); 42static char *afgets PROTO((FILE *)); 43static void reopen_repo_file_for_write PROTO((void)); 44 45static tree pending_repo; 46static tree original_repo; 47static char *repo_name; 48static FILE *repo_file; 49 50static char *old_args, *old_dir, *old_main; 51 52extern int flag_use_repository; 53extern int errorcount, sorrycount; 54extern struct obstack temporary_obstack; 55extern struct obstack permanent_obstack; 56 57#define IDENTIFIER_REPO_USED(NODE) (TREE_LANG_FLAG_3 (NODE)) 58#define IDENTIFIER_REPO_CHOSEN(NODE) (TREE_LANG_FLAG_4 (NODE)) 59 60#if 0 61/* Record the flags used to compile this translation unit. */ 62 63void 64repo_compile_flags (argc, argv) 65 int argc; 66 char **argv; 67{ 68} 69 70/* If this template has not been seen before, add a note to the repository 71 saying where the declaration was. This may be used to find the 72 definition at link time. */ 73 74void 75repo_template_declared (t) 76 tree t; 77{} 78 79/* Note where the definition of a template lives so that instantiations can 80 be generated later. */ 81 82void 83repo_template_defined (t) 84 tree t; 85{} 86 87/* Note where the definition of a class lives to that template 88 instantiations can use it. */ 89 90void 91repo_class_defined (t) 92 tree t; 93{} 94#endif 95 96static tree 97repo_get_id (t) 98 tree t; 99{ 100 if (TREE_CODE_CLASS (TREE_CODE (t)) == 't') 101 { 102 /* If we're not done setting up the class, we may not have set up 103 the vtable, so going ahead would give the wrong answer. 104 See g++.pt/instantiate4.C. */ 105 if (TYPE_SIZE (t) == NULL_TREE || TYPE_BEING_DEFINED (t)) 106 my_friendly_abort (981113); 107 108 t = TYPE_BINFO_VTABLE (t); 109 if (t == NULL_TREE) 110 return t; 111 } 112 return DECL_ASSEMBLER_NAME (t); 113} 114 115/* Note that a template has been used. If we can see the definition, offer 116 to emit it. */ 117 118void 119repo_template_used (t) 120 tree t; 121{ 122 tree id; 123 124 if (! flag_use_repository) 125 return; 126 127 id = repo_get_id (t); 128 if (id == NULL_TREE) 129 return; 130 131 if (TREE_CODE_CLASS (TREE_CODE (t)) == 't') 132 { 133 if (IDENTIFIER_REPO_CHOSEN (id)) 134 mark_class_instantiated (t, 0); 135 } 136 else if (TREE_CODE_CLASS (TREE_CODE (t)) == 'd') 137 { 138 if (IDENTIFIER_REPO_CHOSEN (id)) 139 mark_decl_instantiated (t, 0); 140 } 141 else 142 my_friendly_abort (1); 143 144 if (! IDENTIFIER_REPO_USED (id)) 145 { 146 IDENTIFIER_REPO_USED (id) = 1; 147 pending_repo = perm_tree_cons (NULL_TREE, id, pending_repo); 148 } 149} 150 151#if 0 152/* Note that the vtable for a class has been used, and offer to emit it. */ 153 154static void 155repo_vtable_used (t) 156 tree t; 157{ 158 if (! flag_use_repository) 159 return; 160 161 pending_repo = perm_tree_cons (NULL_TREE, t, pending_repo); 162} 163 164/* Note that an inline with external linkage has been used, and offer to 165 emit it. */ 166 167void 168repo_inline_used (fn) 169 tree fn; 170{ 171 if (! flag_use_repository) 172 return; 173 174 /* Member functions of polymorphic classes go with their vtables. */ 175 if (DECL_FUNCTION_MEMBER_P (fn) && TYPE_VIRTUAL_P (DECL_CLASS_CONTEXT (fn))) 176 { 177 repo_vtable_used (DECL_CLASS_CONTEXT (fn)); 178 return; 179 } 180 181 pending_repo = perm_tree_cons (NULL_TREE, fn, pending_repo); 182} 183 184/* Note that a particular typeinfo node has been used, and offer to 185 emit it. */ 186 187void 188repo_tinfo_used (ti) 189 tree ti; 190{ 191} 192#endif 193 194void 195repo_template_instantiated (t, extern_p) 196 tree t; 197 int extern_p; 198{ 199 if (! extern_p) 200 { 201 tree id = repo_get_id (t); 202 if (id) 203 IDENTIFIER_REPO_CHOSEN (id) = 1; 204 } 205} 206 207/* Parse a reasonable subset of shell quoting syntax. */ 208 209static char * 210extract_string (pp) 211 char **pp; 212{ 213 char *p = *pp; 214 int backquote = 0; 215 int inside = 0; 216 217 for (;;) 218 { 219 char c = *p; 220 if (c == '\0') 221 break; 222 ++p; 223 if (backquote) 224 obstack_1grow (&temporary_obstack, c); 225 else if (! inside && c == ' ') 226 break; 227 else if (! inside && c == '\\') 228 backquote = 1; 229 else if (c == '\'') 230 inside = !inside; 231 else 232 obstack_1grow (&temporary_obstack, c); 233 } 234 235 obstack_1grow (&temporary_obstack, '\0'); 236 *pp = p; 237 return obstack_finish (&temporary_obstack); 238} 239 240static char * 241get_base_filename (filename) 242 const char *filename; 243{ 244 char *p = getenv ("COLLECT_GCC_OPTIONS"); 245 char *output = NULL; 246 int compiling = 0; 247 248 while (p && *p) 249 { 250 char *q = extract_string (&p); 251 252 if (strcmp (q, "-o") == 0) 253 output = extract_string (&p); 254 else if (strcmp (q, "-c") == 0) 255 compiling = 1; 256 } 257 258 if (compiling && output) 259 return output; 260 261 if (p && ! compiling) 262 { 263 warning ("-frepo must be used with -c"); 264 flag_use_repository = 0; 265 return NULL; 266 } 267 268 return file_name_nondirectory (filename); 269} 270 271static void 272open_repo_file (filename) 273 const char *filename; 274{ 275 register const char *p; 276 const char *s = get_base_filename (filename); 277 278 if (s == NULL) 279 return; 280 281 p = file_name_nondirectory (s); 282 p = rindex (p, '.'); 283 if (! p) 284 p = s + strlen (s); 285 286 obstack_grow (&permanent_obstack, s, p - s); 287 repo_name = obstack_copy0 (&permanent_obstack, ".rpo", 4); 288 289 repo_file = fopen (repo_name, "r"); 290} 291 292static char * 293afgets (stream) 294 FILE *stream; 295{ 296 int c; 297 while ((c = getc (stream)) != EOF && c != '\n') 298 obstack_1grow (&temporary_obstack, c); 299 if (obstack_object_size (&temporary_obstack) == 0) 300 return NULL; 301 obstack_1grow (&temporary_obstack, '\0'); 302 return obstack_finish (&temporary_obstack); 303} 304 305void 306init_repo (filename) 307 const char *filename; 308{ 309 char *buf; 310 311 if (! flag_use_repository) 312 return; 313 314 open_repo_file (filename); 315 316 if (repo_file == 0) 317 return; 318 319 while ((buf = afgets (repo_file))) 320 { 321 switch (buf[0]) 322 { 323 case 'A': 324 old_args = obstack_copy0 (&permanent_obstack, buf + 2, 325 strlen (buf + 2)); 326 break; 327 case 'D': 328 old_dir = obstack_copy0 (&permanent_obstack, buf + 2, 329 strlen (buf + 2)); 330 break; 331 case 'M': 332 old_main = obstack_copy0 (&permanent_obstack, buf + 2, 333 strlen (buf + 2)); 334 break; 335 case 'C': 336 case 'O': 337 { 338 tree id = get_identifier (buf + 2); 339 tree orig; 340 341 if (buf[0] == 'C') 342 { 343 IDENTIFIER_REPO_CHOSEN (id) = 1; 344 orig = integer_one_node; 345 } 346 else 347 orig = NULL_TREE; 348 349 original_repo = perm_tree_cons (orig, id, original_repo); 350 } 351 break; 352 default: 353 error ("mysterious repository information in %s", repo_name); 354 } 355 obstack_free (&temporary_obstack, buf); 356 } 357} 358 359static void 360reopen_repo_file_for_write () 361{ 362 if (repo_file) 363 fclose (repo_file); 364 repo_file = fopen (repo_name, "w"); 365 366 if (repo_file == 0) 367 { 368 error ("can't create repository information file `%s'", repo_name); 369 flag_use_repository = 0; 370 } 371} 372 373/* Emit any pending repos. */ 374 375void 376finish_repo () 377{ 378 tree t; 379 int repo_changed = 0; 380 char *dir, *args; 381 382 if (! flag_use_repository) 383 return; 384 385 /* Do we have to write out a new info file? */ 386 387 /* Are there any old templates that aren't used any longer or that are 388 newly chosen? */ 389 390 for (t = original_repo; t; t = TREE_CHAIN (t)) 391 { 392 if (! IDENTIFIER_REPO_USED (TREE_VALUE (t)) 393 || (! TREE_PURPOSE (t) && IDENTIFIER_REPO_CHOSEN (TREE_VALUE (t)))) 394 { 395 repo_changed = 1; 396 break; 397 } 398 IDENTIFIER_REPO_USED (TREE_VALUE (t)) = 0; 399 } 400 401 /* Are there any templates that are newly used? */ 402 403 if (! repo_changed) 404 for (t = pending_repo; t; t = TREE_CHAIN (t)) 405 { 406 if (IDENTIFIER_REPO_USED (TREE_VALUE (t))) 407 { 408 repo_changed = 1; 409 break; 410 } 411 } 412 413 dir = getpwd (); 414 args = getenv ("COLLECT_GCC_OPTIONS"); 415 416 if (! repo_changed && pending_repo) 417 if (strcmp (old_main, main_input_filename) != 0 418 || strcmp (old_dir, dir) != 0 419 || (args == NULL) != (old_args == NULL) 420 || (args && strcmp (old_args, args) != 0)) 421 repo_changed = 1; 422 423 if (! repo_changed || errorcount || sorrycount) 424 goto out; 425 426 reopen_repo_file_for_write (); 427 428 if (repo_file == 0) 429 goto out; 430 431 fprintf (repo_file, "M %s\n", main_input_filename); 432 fprintf (repo_file, "D %s\n", dir); 433 if (args) 434 fprintf (repo_file, "A %s\n", args); 435 436 for (t = pending_repo; t; t = TREE_CHAIN (t)) 437 { 438 tree val = TREE_VALUE (t); 439 char type = IDENTIFIER_REPO_CHOSEN (val) ? 'C' : 'O'; 440 441 fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (val)); 442 } 443 444 out: 445 if (repo_file) 446 fclose (repo_file); 447} 448