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