1/* Code to maintain a C++ template repository. 2 Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005 3 Free Software Foundation, Inc. 4 Contributed by Jason Merrill (jason@cygnus.com) 5 6This file is part of GCC. 7 8GCC is free software; you can redistribute it and/or modify 9it under the terms of the GNU General Public License as published by 10the Free Software Foundation; either version 2, or (at your option) 11any later version. 12 13GCC is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16GNU General Public License for more details. 17 18You should have received a copy of the GNU General Public License 19along with GCC; see the file COPYING. If not, write to 20the Free Software Foundation, 51 Franklin Street, Fifth Floor, 21Boston, MA 02110-1301, USA. */ 22 23/* My strategy here is as follows: 24 25 Everything should be emitted in a translation unit where it is used. 26 The results of the automatic process should be easily reproducible with 27 explicit code. */ 28 29#include "config.h" 30#include "system.h" 31#include "coretypes.h" 32#include "tm.h" 33#include "tree.h" 34#include "cp-tree.h" 35#include "input.h" 36#include "obstack.h" 37#include "toplev.h" 38#include "diagnostic.h" 39#include "flags.h" 40 41static char *extract_string (char **); 42static const char *get_base_filename (const char *); 43static FILE *open_repo_file (const char *); 44static char *afgets (FILE *); 45static FILE *reopen_repo_file_for_write (void); 46 47static GTY(()) tree pending_repo; 48static char *repo_name; 49 50static const char *old_args, *old_dir, *old_main; 51 52static struct obstack temporary_obstack; 53static bool temporary_obstack_initialized_p; 54 55/* Parse a reasonable subset of shell quoting syntax. */ 56 57static char * 58extract_string (char **pp) 59{ 60 char *p = *pp; 61 int backquote = 0; 62 int inside = 0; 63 64 for (;;) 65 { 66 char c = *p; 67 if (c == '\0') 68 break; 69 ++p; 70 if (backquote) 71 { 72 obstack_1grow (&temporary_obstack, c); 73 backquote = 0; 74 } 75 else if (! inside && c == ' ') 76 break; 77 else if (! inside && c == '\\') 78 backquote = 1; 79 else if (c == '\'') 80 inside = !inside; 81 else 82 obstack_1grow (&temporary_obstack, c); 83 } 84 85 obstack_1grow (&temporary_obstack, '\0'); 86 *pp = p; 87 return (char *) obstack_finish (&temporary_obstack); 88} 89 90static const char * 91get_base_filename (const char *filename) 92{ 93 char *p = getenv ("COLLECT_GCC_OPTIONS"); 94 char *output = NULL; 95 int compiling = 0; 96 97 while (p && *p) 98 { 99 char *q = extract_string (&p); 100 101 if (strcmp (q, "-o") == 0) 102 output = extract_string (&p); 103 else if (strcmp (q, "-c") == 0) 104 compiling = 1; 105 } 106 107 if (compiling && output) 108 return output; 109 110 if (p && ! compiling) 111 { 112 warning (0, "-frepo must be used with -c"); 113 flag_use_repository = 0; 114 return NULL; 115 } 116 117 return lbasename (filename); 118} 119 120static FILE * 121open_repo_file (const char *filename) 122{ 123 const char *p; 124 const char *s = get_base_filename (filename); 125 126 if (s == NULL) 127 return NULL; 128 129 p = lbasename (s); 130 p = strrchr (p, '.'); 131 if (! p) 132 p = s + strlen (s); 133 134 repo_name = XNEWVEC (char, p - s + 5); 135 memcpy (repo_name, s, p - s); 136 memcpy (repo_name + (p - s), ".rpo", 5); 137 138 return fopen (repo_name, "r"); 139} 140 141static char * 142afgets (FILE *stream) 143{ 144 int c; 145 while ((c = getc (stream)) != EOF && c != '\n') 146 obstack_1grow (&temporary_obstack, c); 147 if (obstack_object_size (&temporary_obstack) == 0) 148 return NULL; 149 obstack_1grow (&temporary_obstack, '\0'); 150 return (char *) obstack_finish (&temporary_obstack); 151} 152 153void 154init_repo (void) 155{ 156 char *buf; 157 FILE *repo_file; 158 159 if (! flag_use_repository) 160 return; 161 162 /* When a PCH file is loaded, the entire identifier table is 163 replaced, with the result that IDENTIFIER_REPO_CHOSEN is cleared. 164 So, we have to reread the repository file. */ 165 lang_post_pch_load = init_repo; 166 167 if (!temporary_obstack_initialized_p) 168 gcc_obstack_init (&temporary_obstack); 169 170 repo_file = open_repo_file (main_input_filename); 171 172 if (repo_file == 0) 173 return; 174 175 while ((buf = afgets (repo_file))) 176 { 177 switch (buf[0]) 178 { 179 case 'A': 180 old_args = ggc_strdup (buf + 2); 181 break; 182 case 'D': 183 old_dir = ggc_strdup (buf + 2); 184 break; 185 case 'M': 186 old_main = ggc_strdup (buf + 2); 187 break; 188 case 'O': 189 /* A symbol that we were able to define the last time this 190 file was compiled. */ 191 break; 192 case 'C': 193 /* A symbol that the prelinker has requested that we 194 define. */ 195 { 196 tree id = get_identifier (buf + 2); 197 IDENTIFIER_REPO_CHOSEN (id) = 1; 198 } 199 break; 200 default: 201 error ("mysterious repository information in %s", repo_name); 202 } 203 obstack_free (&temporary_obstack, buf); 204 } 205 fclose (repo_file); 206} 207 208static FILE * 209reopen_repo_file_for_write (void) 210{ 211 FILE *repo_file = fopen (repo_name, "w"); 212 213 if (repo_file == 0) 214 { 215 error ("can't create repository information file %qs", repo_name); 216 flag_use_repository = 0; 217 } 218 219 return repo_file; 220} 221 222/* Emit any pending repos. */ 223 224void 225finish_repo (void) 226{ 227 tree t; 228 char *dir, *args; 229 FILE *repo_file; 230 231 if (!flag_use_repository) 232 return; 233 234 if (errorcount || sorrycount) 235 return; 236 237 repo_file = reopen_repo_file_for_write (); 238 if (repo_file == 0) 239 goto out; 240 241 fprintf (repo_file, "M %s\n", main_input_filename); 242 dir = getpwd (); 243 fprintf (repo_file, "D %s\n", dir); 244 args = getenv ("COLLECT_GCC_OPTIONS"); 245 if (args) 246 { 247 fprintf (repo_file, "A %s", args); 248 /* If -frandom-seed is not among the ARGS, then add the value 249 that we chose. That will ensure that the names of types from 250 anonymous namespaces will get the same mangling when this 251 file is recompiled. */ 252 if (!strstr (args, "'-frandom-seed=")) 253 fprintf (repo_file, " '-frandom-seed=%s'", flag_random_seed); 254 fprintf (repo_file, "\n"); 255 } 256 257 for (t = pending_repo; t; t = TREE_CHAIN (t)) 258 { 259 tree val = TREE_VALUE (t); 260 tree name = DECL_ASSEMBLER_NAME (val); 261 char type = IDENTIFIER_REPO_CHOSEN (name) ? 'C' : 'O'; 262 fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (name)); 263 } 264 265 out: 266 if (repo_file) 267 fclose (repo_file); 268} 269 270/* DECL is a FUNCTION_DECL or VAR_DECL with vague linkage whose 271 definition is available in this translation unit. Returns 0 if 272 this definition should not be emitted in this translation unit 273 because it will be emitted elsewhere. Returns 1 if the repository 274 file indicates that that DECL should be emitted in this translation 275 unit, or 2 if the repository file is not in use. */ 276 277int 278repo_emit_p (tree decl) 279{ 280 gcc_assert (TREE_PUBLIC (decl)); 281 gcc_assert (TREE_CODE (decl) == FUNCTION_DECL 282 || TREE_CODE (decl) == VAR_DECL); 283 gcc_assert (!DECL_REALLY_EXTERN (decl)); 284 285 /* When not using the repository, emit everything. */ 286 if (!flag_use_repository) 287 return 2; 288 289 /* Only template instantiations are managed by the repository. This 290 is an artificial restriction; the code in the prelinker and here 291 will work fine if all entities with vague linkage are managed by 292 the repository. */ 293 if (TREE_CODE (decl) == VAR_DECL) 294 { 295 tree type = NULL_TREE; 296 if (DECL_VTABLE_OR_VTT_P (decl)) 297 type = DECL_CONTEXT (decl); 298 else if (DECL_TINFO_P (decl)) 299 type = TREE_TYPE (DECL_NAME (decl)); 300 if (!DECL_TEMPLATE_INSTANTIATION (decl) 301 && (!TYPE_LANG_SPECIFIC (type) 302 || !CLASSTYPE_TEMPLATE_INSTANTIATION (type))) 303 return 2; 304 /* Static data members initialized by constant expressions must 305 be processed where needed so that their definitions are 306 available. */ 307 if (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) 308 && DECL_CLASS_SCOPE_P (decl)) 309 return 2; 310 } 311 else if (!DECL_TEMPLATE_INSTANTIATION (decl)) 312 return 2; 313 314 /* For constructors and destructors, the repository contains 315 information about the clones -- not the original function -- 316 because only the clones are emitted in the object file. */ 317 if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl) 318 || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl)) 319 { 320 int emit_p = 0; 321 tree clone; 322 /* There is no early exit from this loop because we want to 323 ensure that all of the clones are marked as available in this 324 object file. */ 325 FOR_EACH_CLONE (clone, decl) 326 /* The only possible results from the recursive call to 327 repo_emit_p are 0 or 1. */ 328 if (repo_emit_p (clone)) 329 emit_p = 1; 330 return emit_p; 331 } 332 333 /* Keep track of all available entities. */ 334 if (!DECL_REPO_AVAILABLE_P (decl)) 335 { 336 DECL_REPO_AVAILABLE_P (decl) = 1; 337 pending_repo = tree_cons (NULL_TREE, decl, pending_repo); 338 } 339 340 return IDENTIFIER_REPO_CHOSEN (DECL_ASSEMBLER_NAME (decl)); 341} 342 343/* Returns true iff the prelinker has explicitly marked CLASS_TYPE for 344 export from this translation unit. */ 345 346bool 347repo_export_class_p (tree class_type) 348{ 349 if (!flag_use_repository) 350 return false; 351 if (!CLASSTYPE_VTABLES (class_type)) 352 return false; 353 /* If the virtual table has been assigned to this translation unit, 354 export the class. */ 355 return (IDENTIFIER_REPO_CHOSEN 356 (DECL_ASSEMBLER_NAME (CLASSTYPE_VTABLES (class_type)))); 357} 358 359#include "gt-cp-repo.h" 360