123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- /* Code to maintain a C++ template repository.
- Copyright (C) 1995-2015 Free Software Foundation, Inc.
- Contributed by Jason Merrill (jason@cygnus.com)
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- GCC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- /* My strategy here is as follows:
- Everything should be emitted in a translation unit where it is used.
- The results of the automatic process should be easily reproducible with
- explicit code. */
- #include "config.h"
- #include "system.h"
- #include "coretypes.h"
- #include "tm.h"
- #include "hash-set.h"
- #include "machmode.h"
- #include "vec.h"
- #include "double-int.h"
- #include "input.h"
- #include "alias.h"
- #include "symtab.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "tree.h"
- #include "stringpool.h"
- #include "cp-tree.h"
- #include "input.h"
- #include "obstack.h"
- #include "toplev.h"
- #include "diagnostic-core.h"
- #include "flags.h"
- static const char *extract_string (const char **);
- static const char *get_base_filename (const char *);
- static FILE *open_repo_file (const char *);
- static char *afgets (FILE *);
- static FILE *reopen_repo_file_for_write (void);
- static GTY(()) vec<tree, va_gc> *pending_repo;
- static char *repo_name;
- static const char *old_args, *old_dir, *old_main;
- static struct obstack temporary_obstack;
- static bool temporary_obstack_initialized_p;
- /* Parse a reasonable subset of shell quoting syntax. */
- static const char *
- extract_string (const char **pp)
- {
- const char *p = *pp;
- int backquote = 0;
- int inside = 0;
- for (;;)
- {
- char c = *p;
- if (c == '\0')
- break;
- ++p;
- if (backquote)
- {
- obstack_1grow (&temporary_obstack, c);
- backquote = 0;
- }
- else if (! inside && c == ' ')
- break;
- else if (! inside && c == '\\')
- backquote = 1;
- else if (c == '\'')
- inside = !inside;
- else
- obstack_1grow (&temporary_obstack, c);
- }
- obstack_1grow (&temporary_obstack, '\0');
- *pp = p;
- return (char *) obstack_finish (&temporary_obstack);
- }
- static const char *
- get_base_filename (const char *filename)
- {
- const char *p = getenv ("COLLECT_GCC_OPTIONS");
- const char *output = NULL;
- int compiling = 0;
- while (p && *p)
- {
- const char *q = extract_string (&p);
- if (strcmp (q, "-o") == 0)
- {
- if (flag_compare_debug)
- /* Just in case aux_base_name was based on a name with two
- or more '.'s, add an arbitrary extension that will be
- stripped by the caller. */
- output = concat (aux_base_name, ".o", NULL);
- else
- output = extract_string (&p);
- }
- else if (strcmp (q, "-c") == 0)
- compiling = 1;
- }
- if (compiling && output)
- return output;
- if (p && ! compiling)
- {
- warning (0, "-frepo must be used with -c");
- flag_use_repository = 0;
- return NULL;
- }
- return lbasename (filename);
- }
- static FILE *
- open_repo_file (const char *filename)
- {
- const char *p;
- const char *s = get_base_filename (filename);
- if (s == NULL)
- return NULL;
- p = lbasename (s);
- p = strrchr (p, '.');
- if (! p)
- p = s + strlen (s);
- repo_name = XNEWVEC (char, p - s + 5);
- memcpy (repo_name, s, p - s);
- memcpy (repo_name + (p - s), ".rpo", 5);
- return fopen (repo_name, "r");
- }
- static char *
- afgets (FILE *stream)
- {
- int c;
- while ((c = getc (stream)) != EOF && c != '\n')
- obstack_1grow (&temporary_obstack, c);
- if (obstack_object_size (&temporary_obstack) == 0)
- return NULL;
- obstack_1grow (&temporary_obstack, '\0');
- return (char *) obstack_finish (&temporary_obstack);
- }
- void
- init_repo (void)
- {
- char *buf;
- const char *p;
- FILE *repo_file;
- if (! flag_use_repository)
- return;
- /* When a PCH file is loaded, the entire identifier table is
- replaced, with the result that IDENTIFIER_REPO_CHOSEN is cleared.
- So, we have to reread the repository file. */
- lang_post_pch_load = init_repo;
- if (!temporary_obstack_initialized_p)
- gcc_obstack_init (&temporary_obstack);
- repo_file = open_repo_file (main_input_filename);
- if (repo_file == 0)
- return;
- while ((buf = afgets (repo_file)))
- {
- switch (buf[0])
- {
- case 'A':
- old_args = ggc_strdup (buf + 2);
- break;
- case 'D':
- old_dir = ggc_strdup (buf + 2);
- break;
- case 'M':
- old_main = ggc_strdup (buf + 2);
- break;
- case 'O':
- /* A symbol that we were able to define the last time this
- file was compiled. */
- break;
- case 'C':
- /* A symbol that the prelinker has requested that we
- define. */
- {
- tree id = get_identifier (buf + 2);
- IDENTIFIER_REPO_CHOSEN (id) = 1;
- }
- break;
- default:
- error ("mysterious repository information in %s", repo_name);
- }
- obstack_free (&temporary_obstack, buf);
- }
- fclose (repo_file);
- if (old_args && !get_random_seed (true)
- && (p = strstr (old_args, "'-frandom-seed=")))
- set_random_seed (extract_string (&p) + strlen ("-frandom-seed="));
- }
- static FILE *
- reopen_repo_file_for_write (void)
- {
- FILE *repo_file = fopen (repo_name, "w");
- if (repo_file == 0)
- {
- error ("can%'t create repository information file %qs", repo_name);
- flag_use_repository = 0;
- }
- return repo_file;
- }
- /* Emit any pending repos. */
- void
- finish_repo (void)
- {
- tree val;
- char *dir, *args;
- FILE *repo_file;
- unsigned ix;
- if (!flag_use_repository || flag_compare_debug)
- return;
- if (seen_error ())
- return;
- repo_file = reopen_repo_file_for_write ();
- if (repo_file == 0)
- goto out;
- fprintf (repo_file, "M %s\n", main_input_filename);
- dir = getpwd ();
- fprintf (repo_file, "D %s\n", dir);
- args = getenv ("COLLECT_GCC_OPTIONS");
- if (args)
- {
- fprintf (repo_file, "A %s", args);
- /* If -frandom-seed is not among the ARGS, then add the value
- that we chose. That will ensure that the names of types from
- anonymous namespaces will get the same mangling when this
- file is recompiled. */
- if (!strstr (args, "'-frandom-seed="))
- fprintf (repo_file, " '-frandom-seed=" HOST_WIDE_INT_PRINT_HEX_PURE "'",
- get_random_seed (false));
- fprintf (repo_file, "\n");
- }
- FOR_EACH_VEC_SAFE_ELT_REVERSE (pending_repo, ix, val)
- {
- tree name = DECL_ASSEMBLER_NAME (val);
- char type = IDENTIFIER_REPO_CHOSEN (name) ? 'C' : 'O';
- fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (name));
- }
- out:
- if (repo_file)
- fclose (repo_file);
- }
- /* DECL is a FUNCTION_DECL or VAR_DECL with vague linkage whose
- definition is available in this translation unit. Returns 0 if
- this definition should not be emitted in this translation unit
- because it will be emitted elsewhere. Returns 1 if the repository
- file indicates that that DECL should be emitted in this translation
- unit, or 2 if the repository file is not in use. */
- int
- repo_emit_p (tree decl)
- {
- int ret = 0;
- gcc_assert (TREE_PUBLIC (decl));
- gcc_assert (VAR_OR_FUNCTION_DECL_P (decl));
- gcc_assert (!DECL_REALLY_EXTERN (decl)
- /* A clone might not have its linkage flags updated yet
- because we call import_export_decl before
- maybe_clone_body. */
- || DECL_ABSTRACT_ORIGIN (decl));
- /* When not using the repository, emit everything. */
- if (!flag_use_repository)
- return 2;
- /* Only template instantiations are managed by the repository. This
- is an artificial restriction; the code in the prelinker and here
- will work fine if all entities with vague linkage are managed by
- the repository. */
- if (VAR_P (decl))
- {
- tree type = NULL_TREE;
- if (DECL_VTABLE_OR_VTT_P (decl))
- type = DECL_CONTEXT (decl);
- else if (DECL_TINFO_P (decl))
- type = TREE_TYPE (DECL_NAME (decl));
- if (!DECL_TEMPLATE_INSTANTIATION (decl)
- && (!TYPE_LANG_SPECIFIC (type)
- || !CLASSTYPE_TEMPLATE_INSTANTIATION (type)))
- return 2;
- /* Const static data members initialized by constant expressions must
- be processed where needed so that their definitions are
- available. Still record them into *.rpo files, so if they
- weren't actually emitted and collect2 requests them, they can
- be provided. */
- if (decl_maybe_constant_var_p (decl)
- && DECL_CLASS_SCOPE_P (decl))
- ret = 2;
- }
- else if (!DECL_TEMPLATE_INSTANTIATION (decl))
- return 2;
- if (DECL_EXPLICIT_INSTANTIATION (decl))
- return 2;
- /* For constructors and destructors, the repository contains
- information about the clones -- not the original function --
- because only the clones are emitted in the object file. */
- if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
- || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
- {
- int emit_p = 0;
- tree clone;
- /* There is no early exit from this loop because we want to
- ensure that all of the clones are marked as available in this
- object file. */
- FOR_EACH_CLONE (clone, decl)
- /* The only possible results from the recursive call to
- repo_emit_p are 0 or 1. */
- if (repo_emit_p (clone))
- emit_p = 1;
- return emit_p;
- }
- /* Keep track of all available entities. */
- if (!DECL_REPO_AVAILABLE_P (decl))
- {
- DECL_REPO_AVAILABLE_P (decl) = 1;
- vec_safe_push (pending_repo, decl);
- }
- return IDENTIFIER_REPO_CHOSEN (DECL_ASSEMBLER_NAME (decl)) ? 1 : ret;
- }
- /* Returns true iff the prelinker has explicitly marked CLASS_TYPE for
- export from this translation unit. */
- bool
- repo_export_class_p (const_tree class_type)
- {
- if (!flag_use_repository)
- return false;
- if (!CLASSTYPE_VTABLES (class_type))
- return false;
- /* If the virtual table has been assigned to this translation unit,
- export the class. */
- return (IDENTIFIER_REPO_CHOSEN
- (DECL_ASSEMBLER_NAME (CLASSTYPE_VTABLES (class_type))));
- }
- #include "gt-cp-repo.h"
|