1/* Code to maintain a C++ template repository. 2 Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001 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#include "ggc.h" 36#include "diagnostic.h" 37 38static tree repo_get_id PARAMS ((tree)); 39static char *extract_string PARAMS ((char **)); 40static const char *get_base_filename PARAMS ((const char *)); 41static void open_repo_file PARAMS ((const char *)); 42static char *afgets PARAMS ((FILE *)); 43static void reopen_repo_file_for_write PARAMS ((void)); 44 45static GTY(()) tree pending_repo; 46static GTY(()) tree original_repo; 47static char *repo_name; 48static FILE *repo_file; 49 50static const char *old_args, *old_dir, *old_main; 51 52static struct obstack temporary_obstack; 53 54#define IDENTIFIER_REPO_USED(NODE) (TREE_LANG_FLAG_3 (NODE)) 55#define IDENTIFIER_REPO_CHOSEN(NODE) (TREE_LANG_FLAG_4 (NODE)) 56 57#if 0 58/* Record the flags used to compile this translation unit. */ 59 60void 61repo_compile_flags (argc, argv) 62 int argc; 63 char **argv; 64{ 65} 66 67/* If this template has not been seen before, add a note to the repository 68 saying where the declaration was. This may be used to find the 69 definition at link time. */ 70 71void 72repo_template_declared (t) 73 tree t; 74{} 75 76/* Note where the definition of a template lives so that instantiations can 77 be generated later. */ 78 79void 80repo_template_defined (t) 81 tree t; 82{} 83 84/* Note where the definition of a class lives to that template 85 instantiations can use it. */ 86 87void 88repo_class_defined (t) 89 tree t; 90{} 91#endif 92 93static tree 94repo_get_id (t) 95 tree t; 96{ 97 if (TYPE_P (t)) 98 { 99 tree vtable; 100 101 /* If we're not done setting up the class, we may not have set up 102 the vtable, so going ahead would give the wrong answer. 103 See g++.pt/instantiate4.C. */ 104 if (!COMPLETE_TYPE_P (t) || TYPE_BEING_DEFINED (t)) 105 abort (); 106 107 vtable = get_vtbl_decl_for_binfo (TYPE_BINFO (t)); 108 109 t = vtable; 110 if (t == NULL_TREE) 111 return t; 112 } 113 return DECL_ASSEMBLER_NAME (t); 114} 115 116/* Note that a template has been used. If we can see the definition, offer 117 to emit it. */ 118 119void 120repo_template_used (t) 121 tree t; 122{ 123 tree id; 124 125 if (! flag_use_repository) 126 return; 127 128 id = repo_get_id (t); 129 if (id == NULL_TREE) 130 return; 131 132 if (TYPE_P (t)) 133 { 134 if (IDENTIFIER_REPO_CHOSEN (id)) 135 mark_class_instantiated (t, 0); 136 } 137 else if (DECL_P (t)) 138 { 139 if (IDENTIFIER_REPO_CHOSEN (id)) 140 /* It doesn't make sense to instantiate a clone, so we 141 instantiate the cloned function instead. Note that this 142 approach will not work correctly if collect2 assigns 143 different clones to different files -- but it shouldn't. */ 144 mark_decl_instantiated (DECL_CLONED_FUNCTION_P (t) 145 ? DECL_CLONED_FUNCTION (t) : t, 146 0); 147 } 148 else 149 abort (); 150 151 if (! IDENTIFIER_REPO_USED (id)) 152 { 153 IDENTIFIER_REPO_USED (id) = 1; 154 pending_repo = tree_cons (NULL_TREE, id, pending_repo); 155 } 156} 157 158#if 0 159/* Note that the vtable for a class has been used, and offer to emit it. */ 160 161static void 162repo_vtable_used (t) 163 tree t; 164{ 165 if (! flag_use_repository) 166 return; 167 168 pending_repo = tree_cons (NULL_TREE, t, pending_repo); 169} 170 171/* Note that an inline with external linkage has been used, and offer to 172 emit it. */ 173 174void 175repo_inline_used (fn) 176 tree fn; 177{ 178 if (! flag_use_repository) 179 return; 180 181 /* Member functions of polymorphic classes go with their vtables. */ 182 if (DECL_FUNCTION_MEMBER_P (fn) 183 && TYPE_POLYMORPHIC_P (DECL_CONTEXT (fn))) 184 { 185 repo_vtable_used (DECL_CONTEXT (fn)); 186 return; 187 } 188 189 pending_repo = tree_cons (NULL_TREE, fn, pending_repo); 190} 191 192/* Note that a particular typeinfo node has been used, and offer to 193 emit it. */ 194 195void 196repo_tinfo_used (ti) 197 tree ti; 198{ 199} 200#endif 201 202void 203repo_template_instantiated (t, extern_p) 204 tree t; 205 int extern_p; 206{ 207 if (! extern_p) 208 { 209 tree id = repo_get_id (t); 210 if (id) 211 IDENTIFIER_REPO_CHOSEN (id) = 1; 212 } 213} 214 215/* Parse a reasonable subset of shell quoting syntax. */ 216 217static char * 218extract_string (pp) 219 char **pp; 220{ 221 char *p = *pp; 222 int backquote = 0; 223 int inside = 0; 224 225 for (;;) 226 { 227 char c = *p; 228 if (c == '\0') 229 break; 230 ++p; 231 if (backquote) 232 obstack_1grow (&temporary_obstack, c); 233 else if (! inside && c == ' ') 234 break; 235 else if (! inside && c == '\\') 236 backquote = 1; 237 else if (c == '\'') 238 inside = !inside; 239 else 240 obstack_1grow (&temporary_obstack, c); 241 } 242 243 obstack_1grow (&temporary_obstack, '\0'); 244 *pp = p; 245 return obstack_finish (&temporary_obstack); 246} 247 248const char * 249get_base_filename (filename) 250 const char *filename; 251{ 252 char *p = getenv ("COLLECT_GCC_OPTIONS"); 253 char *output = NULL; 254 int compiling = 0; 255 256 while (p && *p) 257 { 258 char *q = extract_string (&p); 259 260 if (strcmp (q, "-o") == 0) 261 output = extract_string (&p); 262 else if (strcmp (q, "-c") == 0) 263 compiling = 1; 264 } 265 266 if (compiling && output) 267 return output; 268 269 if (p && ! compiling) 270 { 271 warning ("-frepo must be used with -c"); 272 flag_use_repository = 0; 273 return NULL; 274 } 275 276 return lbasename (filename); 277} 278 279static void 280open_repo_file (filename) 281 const char *filename; 282{ 283 register const char *p; 284 const char *s = get_base_filename (filename); 285 286 if (s == NULL) 287 return; 288 289 p = lbasename (s); 290 p = strrchr (p, '.'); 291 if (! p) 292 p = s + strlen (s); 293 294 repo_name = xmalloc (p - s + 5); 295 memcpy (repo_name, s, p - s); 296 memcpy (repo_name + (p - s), ".rpo", 5); 297 298 repo_file = fopen (repo_name, "r"); 299} 300 301static char * 302afgets (stream) 303 FILE *stream; 304{ 305 int c; 306 while ((c = getc (stream)) != EOF && c != '\n') 307 obstack_1grow (&temporary_obstack, c); 308 if (obstack_object_size (&temporary_obstack) == 0) 309 return NULL; 310 obstack_1grow (&temporary_obstack, '\0'); 311 return obstack_finish (&temporary_obstack); 312} 313 314void 315init_repo (filename) 316 const char *filename; 317{ 318 char *buf; 319 320 if (! flag_use_repository) 321 return; 322 323 gcc_obstack_init (&temporary_obstack); 324 325 open_repo_file (filename); 326 327 if (repo_file == 0) 328 return; 329 330 while ((buf = afgets (repo_file))) 331 { 332 switch (buf[0]) 333 { 334 case 'A': 335 old_args = ggc_strdup (buf + 2); 336 break; 337 case 'D': 338 old_dir = ggc_strdup (buf + 2); 339 break; 340 case 'M': 341 old_main = ggc_strdup (buf + 2); 342 break; 343 case 'C': 344 case 'O': 345 { 346 tree id = get_identifier (buf + 2); 347 tree orig; 348 349 if (buf[0] == 'C') 350 { 351 IDENTIFIER_REPO_CHOSEN (id) = 1; 352 orig = integer_one_node; 353 } 354 else 355 orig = NULL_TREE; 356 357 original_repo = tree_cons (orig, id, original_repo); 358 } 359 break; 360 default: 361 error ("mysterious repository information in %s", repo_name); 362 } 363 obstack_free (&temporary_obstack, buf); 364 } 365} 366 367static void 368reopen_repo_file_for_write () 369{ 370 if (repo_file) 371 fclose (repo_file); 372 repo_file = fopen (repo_name, "w"); 373 374 if (repo_file == 0) 375 { 376 error ("can't create repository information file `%s'", repo_name); 377 flag_use_repository = 0; 378 } 379} 380 381/* Emit any pending repos. */ 382 383void 384finish_repo () 385{ 386 tree t; 387 int repo_changed = 0; 388 char *dir, *args; 389 390 if (! flag_use_repository) 391 return; 392 393 /* Do we have to write out a new info file? */ 394 395 /* Are there any old templates that aren't used any longer or that are 396 newly chosen? */ 397 398 for (t = original_repo; t; t = TREE_CHAIN (t)) 399 { 400 if (! IDENTIFIER_REPO_USED (TREE_VALUE (t)) 401 || (! TREE_PURPOSE (t) && IDENTIFIER_REPO_CHOSEN (TREE_VALUE (t)))) 402 { 403 repo_changed = 1; 404 break; 405 } 406 IDENTIFIER_REPO_USED (TREE_VALUE (t)) = 0; 407 } 408 409 /* Are there any templates that are newly used? */ 410 411 if (! repo_changed) 412 for (t = pending_repo; t; t = TREE_CHAIN (t)) 413 { 414 if (IDENTIFIER_REPO_USED (TREE_VALUE (t))) 415 { 416 repo_changed = 1; 417 break; 418 } 419 } 420 421 dir = getpwd (); 422 args = getenv ("COLLECT_GCC_OPTIONS"); 423 424 if (! repo_changed && pending_repo) 425 if (strcmp (old_main, main_input_filename) != 0 426 || strcmp (old_dir, dir) != 0 427 || (args == NULL) != (old_args == NULL) 428 || (args && strcmp (old_args, args) != 0)) 429 repo_changed = 1; 430 431 if (! repo_changed || errorcount || sorrycount) 432 goto out; 433 434 reopen_repo_file_for_write (); 435 436 if (repo_file == 0) 437 goto out; 438 439 fprintf (repo_file, "M %s\n", main_input_filename); 440 fprintf (repo_file, "D %s\n", dir); 441 if (args) 442 fprintf (repo_file, "A %s\n", args); 443 444 for (t = pending_repo; t; t = TREE_CHAIN (t)) 445 { 446 tree val = TREE_VALUE (t); 447 char type = IDENTIFIER_REPO_CHOSEN (val) ? 'C' : 'O'; 448 449 fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (val)); 450 } 451 452 out: 453 if (repo_file) 454 fclose (repo_file); 455} 456 457#include "gt-cp-repo.h" 458