11debfc3dSmrg /* Code to maintain a C++ template repository.
2*c0a68be4Smrg Copyright (C) 1995-2019 Free Software Foundation, Inc.
31debfc3dSmrg Contributed by Jason Merrill (jason@cygnus.com)
41debfc3dSmrg
51debfc3dSmrg This file is part of GCC.
61debfc3dSmrg
71debfc3dSmrg GCC is free software; you can redistribute it and/or modify
81debfc3dSmrg it under the terms of the GNU General Public License as published by
91debfc3dSmrg the Free Software Foundation; either version 3, or (at your option)
101debfc3dSmrg any later version.
111debfc3dSmrg
121debfc3dSmrg GCC is distributed in the hope that it will be useful,
131debfc3dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
141debfc3dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
151debfc3dSmrg GNU General Public License for more details.
161debfc3dSmrg
171debfc3dSmrg You should have received a copy of the GNU General Public License
181debfc3dSmrg along with GCC; see the file COPYING3. If not see
191debfc3dSmrg <http://www.gnu.org/licenses/>. */
201debfc3dSmrg
211debfc3dSmrg /* My strategy here is as follows:
221debfc3dSmrg
231debfc3dSmrg Everything should be emitted in a translation unit where it is used.
241debfc3dSmrg The results of the automatic process should be easily reproducible with
251debfc3dSmrg explicit code. */
261debfc3dSmrg
271debfc3dSmrg #include "config.h"
281debfc3dSmrg #include "system.h"
291debfc3dSmrg #include "coretypes.h"
301debfc3dSmrg #include "cp-tree.h"
311debfc3dSmrg #include "stringpool.h"
321debfc3dSmrg #include "toplev.h"
331debfc3dSmrg
341debfc3dSmrg static const char *extract_string (const char **);
351debfc3dSmrg static const char *get_base_filename (const char *);
361debfc3dSmrg static FILE *open_repo_file (const char *);
371debfc3dSmrg static char *afgets (FILE *);
381debfc3dSmrg static FILE *reopen_repo_file_for_write (void);
391debfc3dSmrg
401debfc3dSmrg static GTY(()) vec<tree, va_gc> *pending_repo;
411debfc3dSmrg static char *repo_name;
421debfc3dSmrg
431debfc3dSmrg static const char *old_args, *old_dir, *old_main;
441debfc3dSmrg
451debfc3dSmrg static struct obstack temporary_obstack;
461debfc3dSmrg static bool temporary_obstack_initialized_p;
471debfc3dSmrg
481debfc3dSmrg /* Parse a reasonable subset of shell quoting syntax. */
491debfc3dSmrg
501debfc3dSmrg static const char *
extract_string(const char ** pp)511debfc3dSmrg extract_string (const char **pp)
521debfc3dSmrg {
531debfc3dSmrg const char *p = *pp;
541debfc3dSmrg int backquote = 0;
551debfc3dSmrg int inside = 0;
561debfc3dSmrg
571debfc3dSmrg for (;;)
581debfc3dSmrg {
591debfc3dSmrg char c = *p;
601debfc3dSmrg if (c == '\0')
611debfc3dSmrg break;
621debfc3dSmrg ++p;
631debfc3dSmrg if (backquote)
641debfc3dSmrg {
651debfc3dSmrg obstack_1grow (&temporary_obstack, c);
661debfc3dSmrg backquote = 0;
671debfc3dSmrg }
681debfc3dSmrg else if (! inside && c == ' ')
691debfc3dSmrg break;
701debfc3dSmrg else if (! inside && c == '\\')
711debfc3dSmrg backquote = 1;
721debfc3dSmrg else if (c == '\'')
731debfc3dSmrg inside = !inside;
741debfc3dSmrg else
751debfc3dSmrg obstack_1grow (&temporary_obstack, c);
761debfc3dSmrg }
771debfc3dSmrg
781debfc3dSmrg obstack_1grow (&temporary_obstack, '\0');
791debfc3dSmrg *pp = p;
801debfc3dSmrg return (char *) obstack_finish (&temporary_obstack);
811debfc3dSmrg }
821debfc3dSmrg
831debfc3dSmrg static const char *
get_base_filename(const char * filename)841debfc3dSmrg get_base_filename (const char *filename)
851debfc3dSmrg {
861debfc3dSmrg const char *p = getenv ("COLLECT_GCC_OPTIONS");
871debfc3dSmrg const char *output = NULL;
881debfc3dSmrg int compiling = 0;
891debfc3dSmrg
901debfc3dSmrg while (p && *p)
911debfc3dSmrg {
921debfc3dSmrg const char *q = extract_string (&p);
931debfc3dSmrg
941debfc3dSmrg if (strcmp (q, "-o") == 0)
951debfc3dSmrg {
961debfc3dSmrg if (flag_compare_debug)
971debfc3dSmrg /* Just in case aux_base_name was based on a name with two
981debfc3dSmrg or more '.'s, add an arbitrary extension that will be
991debfc3dSmrg stripped by the caller. */
1001debfc3dSmrg output = concat (aux_base_name, ".o", NULL);
1011debfc3dSmrg else
1021debfc3dSmrg output = extract_string (&p);
1031debfc3dSmrg }
1041debfc3dSmrg else if (strcmp (q, "-c") == 0)
1051debfc3dSmrg compiling = 1;
1061debfc3dSmrg }
1071debfc3dSmrg
1081debfc3dSmrg if (compiling && output)
1091debfc3dSmrg return output;
1101debfc3dSmrg
1111debfc3dSmrg if (p && ! compiling)
1121debfc3dSmrg {
113*c0a68be4Smrg warning (0, "%<-frepo%> must be used with %<-c%>");
1141debfc3dSmrg flag_use_repository = 0;
1151debfc3dSmrg return NULL;
1161debfc3dSmrg }
1171debfc3dSmrg
1181debfc3dSmrg return lbasename (filename);
1191debfc3dSmrg }
1201debfc3dSmrg
1211debfc3dSmrg static FILE *
open_repo_file(const char * filename)1221debfc3dSmrg open_repo_file (const char *filename)
1231debfc3dSmrg {
1241debfc3dSmrg const char *p;
1251debfc3dSmrg const char *s = get_base_filename (filename);
1261debfc3dSmrg
1271debfc3dSmrg if (s == NULL)
1281debfc3dSmrg return NULL;
1291debfc3dSmrg
1301debfc3dSmrg p = lbasename (s);
1311debfc3dSmrg p = strrchr (p, '.');
1321debfc3dSmrg if (! p)
1331debfc3dSmrg p = s + strlen (s);
1341debfc3dSmrg
1351debfc3dSmrg repo_name = XNEWVEC (char, p - s + 5);
1361debfc3dSmrg memcpy (repo_name, s, p - s);
1371debfc3dSmrg memcpy (repo_name + (p - s), ".rpo", 5);
1381debfc3dSmrg
1391debfc3dSmrg return fopen (repo_name, "r");
1401debfc3dSmrg }
1411debfc3dSmrg
1421debfc3dSmrg static char *
afgets(FILE * stream)1431debfc3dSmrg afgets (FILE *stream)
1441debfc3dSmrg {
1451debfc3dSmrg int c;
1461debfc3dSmrg while ((c = getc (stream)) != EOF && c != '\n')
1471debfc3dSmrg obstack_1grow (&temporary_obstack, c);
1481debfc3dSmrg if (obstack_object_size (&temporary_obstack) == 0)
1491debfc3dSmrg return NULL;
1501debfc3dSmrg obstack_1grow (&temporary_obstack, '\0');
1511debfc3dSmrg return (char *) obstack_finish (&temporary_obstack);
1521debfc3dSmrg }
1531debfc3dSmrg
1541debfc3dSmrg void
init_repo(void)1551debfc3dSmrg init_repo (void)
1561debfc3dSmrg {
1571debfc3dSmrg char *buf;
1581debfc3dSmrg const char *p;
1591debfc3dSmrg FILE *repo_file;
1601debfc3dSmrg
1611debfc3dSmrg if (! flag_use_repository)
1621debfc3dSmrg return;
1631debfc3dSmrg
1641debfc3dSmrg /* When a PCH file is loaded, the entire identifier table is
1651debfc3dSmrg replaced, with the result that IDENTIFIER_REPO_CHOSEN is cleared.
1661debfc3dSmrg So, we have to reread the repository file. */
1671debfc3dSmrg lang_post_pch_load = init_repo;
1681debfc3dSmrg
1691debfc3dSmrg if (!temporary_obstack_initialized_p)
1701debfc3dSmrg gcc_obstack_init (&temporary_obstack);
1711debfc3dSmrg
1721debfc3dSmrg repo_file = open_repo_file (main_input_filename);
1731debfc3dSmrg
1741debfc3dSmrg if (repo_file == 0)
1751debfc3dSmrg return;
1761debfc3dSmrg
1771debfc3dSmrg while ((buf = afgets (repo_file)))
1781debfc3dSmrg {
1791debfc3dSmrg switch (buf[0])
1801debfc3dSmrg {
1811debfc3dSmrg case 'A':
1821debfc3dSmrg old_args = ggc_strdup (buf + 2);
1831debfc3dSmrg break;
1841debfc3dSmrg case 'D':
1851debfc3dSmrg old_dir = ggc_strdup (buf + 2);
1861debfc3dSmrg break;
1871debfc3dSmrg case 'M':
1881debfc3dSmrg old_main = ggc_strdup (buf + 2);
1891debfc3dSmrg break;
1901debfc3dSmrg case 'O':
1911debfc3dSmrg /* A symbol that we were able to define the last time this
1921debfc3dSmrg file was compiled. */
1931debfc3dSmrg break;
1941debfc3dSmrg case 'C':
1951debfc3dSmrg /* A symbol that the prelinker has requested that we
1961debfc3dSmrg define. */
1971debfc3dSmrg {
1981debfc3dSmrg tree id = get_identifier (buf + 2);
1991debfc3dSmrg IDENTIFIER_REPO_CHOSEN (id) = 1;
2001debfc3dSmrg }
2011debfc3dSmrg break;
2021debfc3dSmrg default:
2031debfc3dSmrg error ("mysterious repository information in %s", repo_name);
2041debfc3dSmrg }
2051debfc3dSmrg obstack_free (&temporary_obstack, buf);
2061debfc3dSmrg }
2071debfc3dSmrg fclose (repo_file);
2081debfc3dSmrg
2091debfc3dSmrg if (old_args && !get_random_seed (true)
2101debfc3dSmrg && (p = strstr (old_args, "'-frandom-seed=")))
2111debfc3dSmrg set_random_seed (extract_string (&p) + strlen ("-frandom-seed="));
2121debfc3dSmrg }
2131debfc3dSmrg
2141debfc3dSmrg static FILE *
reopen_repo_file_for_write(void)2151debfc3dSmrg reopen_repo_file_for_write (void)
2161debfc3dSmrg {
2171debfc3dSmrg FILE *repo_file = fopen (repo_name, "w");
2181debfc3dSmrg
2191debfc3dSmrg if (repo_file == 0)
2201debfc3dSmrg {
2211debfc3dSmrg error ("can%'t create repository information file %qs", repo_name);
2221debfc3dSmrg flag_use_repository = 0;
2231debfc3dSmrg }
2241debfc3dSmrg
2251debfc3dSmrg return repo_file;
2261debfc3dSmrg }
2271debfc3dSmrg
2281debfc3dSmrg /* Emit any pending repos. */
2291debfc3dSmrg
2301debfc3dSmrg void
finish_repo(void)2311debfc3dSmrg finish_repo (void)
2321debfc3dSmrg {
2331debfc3dSmrg tree val;
2341debfc3dSmrg char *dir, *args;
2351debfc3dSmrg FILE *repo_file;
2361debfc3dSmrg unsigned ix;
2371debfc3dSmrg
2381debfc3dSmrg if (!flag_use_repository || flag_compare_debug)
2391debfc3dSmrg return;
2401debfc3dSmrg
2411debfc3dSmrg if (seen_error ())
2421debfc3dSmrg return;
2431debfc3dSmrg
2441debfc3dSmrg repo_file = reopen_repo_file_for_write ();
2451debfc3dSmrg if (repo_file == 0)
2461debfc3dSmrg goto out;
2471debfc3dSmrg
2481debfc3dSmrg fprintf (repo_file, "M %s\n", main_input_filename);
2491debfc3dSmrg dir = getpwd ();
2501debfc3dSmrg fprintf (repo_file, "D %s\n", dir);
2511debfc3dSmrg args = getenv ("COLLECT_GCC_OPTIONS");
2521debfc3dSmrg if (args)
2531debfc3dSmrg {
2541debfc3dSmrg fprintf (repo_file, "A %s", args);
2551debfc3dSmrg /* If -frandom-seed is not among the ARGS, then add the value
2561debfc3dSmrg that we chose. That will ensure that the names of types from
2571debfc3dSmrg anonymous namespaces will get the same mangling when this
2581debfc3dSmrg file is recompiled. */
2591debfc3dSmrg if (!strstr (args, "'-frandom-seed="))
2601debfc3dSmrg fprintf (repo_file, " '-frandom-seed=" HOST_WIDE_INT_PRINT_HEX_PURE "'",
2611debfc3dSmrg get_random_seed (false));
2621debfc3dSmrg fprintf (repo_file, "\n");
2631debfc3dSmrg }
2641debfc3dSmrg
2651debfc3dSmrg FOR_EACH_VEC_SAFE_ELT_REVERSE (pending_repo, ix, val)
2661debfc3dSmrg {
2671debfc3dSmrg tree name = DECL_ASSEMBLER_NAME (val);
2681debfc3dSmrg char type = IDENTIFIER_REPO_CHOSEN (name) ? 'C' : 'O';
2691debfc3dSmrg fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (name));
2701debfc3dSmrg }
2711debfc3dSmrg
2721debfc3dSmrg out:
2731debfc3dSmrg if (repo_file)
2741debfc3dSmrg fclose (repo_file);
2751debfc3dSmrg }
2761debfc3dSmrg
2771debfc3dSmrg /* DECL is a FUNCTION_DECL or VAR_DECL with vague linkage whose
2781debfc3dSmrg definition is available in this translation unit. Returns 0 if
2791debfc3dSmrg this definition should not be emitted in this translation unit
2801debfc3dSmrg because it will be emitted elsewhere. Returns 1 if the repository
2811debfc3dSmrg file indicates that that DECL should be emitted in this translation
2821debfc3dSmrg unit, or 2 if the repository file is not in use. */
2831debfc3dSmrg
2841debfc3dSmrg int
repo_emit_p(tree decl)2851debfc3dSmrg repo_emit_p (tree decl)
2861debfc3dSmrg {
2871debfc3dSmrg int ret = 0;
2881debfc3dSmrg gcc_assert (TREE_PUBLIC (decl));
2891debfc3dSmrg gcc_assert (VAR_OR_FUNCTION_DECL_P (decl));
2901debfc3dSmrg gcc_assert (!DECL_REALLY_EXTERN (decl)
2911debfc3dSmrg /* A clone might not have its linkage flags updated yet
2921debfc3dSmrg because we call import_export_decl before
2931debfc3dSmrg maybe_clone_body. */
2941debfc3dSmrg || DECL_ABSTRACT_ORIGIN (decl));
2951debfc3dSmrg
2961debfc3dSmrg /* When not using the repository, emit everything. */
2971debfc3dSmrg if (!flag_use_repository)
2981debfc3dSmrg return 2;
2991debfc3dSmrg
3001debfc3dSmrg /* Only template instantiations are managed by the repository. This
3011debfc3dSmrg is an artificial restriction; the code in the prelinker and here
3021debfc3dSmrg will work fine if all entities with vague linkage are managed by
3031debfc3dSmrg the repository. */
3041debfc3dSmrg if (VAR_P (decl))
3051debfc3dSmrg {
3061debfc3dSmrg tree type = NULL_TREE;
3071debfc3dSmrg if (DECL_VTABLE_OR_VTT_P (decl))
3081debfc3dSmrg type = DECL_CONTEXT (decl);
3091debfc3dSmrg else if (DECL_TINFO_P (decl))
3101debfc3dSmrg type = TREE_TYPE (DECL_NAME (decl));
3111debfc3dSmrg if (!DECL_TEMPLATE_INSTANTIATION (decl)
3121debfc3dSmrg && (!TYPE_LANG_SPECIFIC (type)
3131debfc3dSmrg || !CLASSTYPE_TEMPLATE_INSTANTIATION (type)))
3141debfc3dSmrg return 2;
3151debfc3dSmrg /* Const static data members initialized by constant expressions must
3161debfc3dSmrg be processed where needed so that their definitions are
3171debfc3dSmrg available. Still record them into *.rpo files, so if they
3181debfc3dSmrg weren't actually emitted and collect2 requests them, they can
3191debfc3dSmrg be provided. */
3201debfc3dSmrg if (decl_maybe_constant_var_p (decl)
3211debfc3dSmrg && DECL_CLASS_SCOPE_P (decl))
3221debfc3dSmrg ret = 2;
3231debfc3dSmrg }
3241debfc3dSmrg else if (!DECL_TEMPLATE_INSTANTIATION (decl))
3251debfc3dSmrg return 2;
3261debfc3dSmrg
3271debfc3dSmrg if (DECL_EXPLICIT_INSTANTIATION (decl))
3281debfc3dSmrg return 2;
3291debfc3dSmrg
3301debfc3dSmrg /* For constructors and destructors, the repository contains
3311debfc3dSmrg information about the clones -- not the original function --
3321debfc3dSmrg because only the clones are emitted in the object file. */
333*c0a68be4Smrg if (DECL_MAYBE_IN_CHARGE_CDTOR_P (decl))
3341debfc3dSmrg {
3351debfc3dSmrg int emit_p = 0;
3361debfc3dSmrg tree clone;
3371debfc3dSmrg /* There is no early exit from this loop because we want to
3381debfc3dSmrg ensure that all of the clones are marked as available in this
3391debfc3dSmrg object file. */
3401debfc3dSmrg FOR_EACH_CLONE (clone, decl)
3411debfc3dSmrg /* The only possible results from the recursive call to
3421debfc3dSmrg repo_emit_p are 0 or 1. */
3431debfc3dSmrg if (repo_emit_p (clone))
3441debfc3dSmrg emit_p = 1;
3451debfc3dSmrg return emit_p;
3461debfc3dSmrg }
3471debfc3dSmrg
3481debfc3dSmrg /* Keep track of all available entities. */
3491debfc3dSmrg if (!DECL_REPO_AVAILABLE_P (decl))
3501debfc3dSmrg {
3511debfc3dSmrg DECL_REPO_AVAILABLE_P (decl) = 1;
3521debfc3dSmrg vec_safe_push (pending_repo, decl);
3531debfc3dSmrg }
3541debfc3dSmrg
3551debfc3dSmrg return IDENTIFIER_REPO_CHOSEN (DECL_ASSEMBLER_NAME (decl)) ? 1 : ret;
3561debfc3dSmrg }
3571debfc3dSmrg
3581debfc3dSmrg /* Returns true iff the prelinker has explicitly marked CLASS_TYPE for
3591debfc3dSmrg export from this translation unit. */
3601debfc3dSmrg
3611debfc3dSmrg bool
repo_export_class_p(const_tree class_type)3621debfc3dSmrg repo_export_class_p (const_tree class_type)
3631debfc3dSmrg {
3641debfc3dSmrg if (!flag_use_repository)
3651debfc3dSmrg return false;
3661debfc3dSmrg if (!CLASSTYPE_VTABLES (class_type))
3671debfc3dSmrg return false;
3681debfc3dSmrg /* If the virtual table has been assigned to this translation unit,
3691debfc3dSmrg export the class. */
3701debfc3dSmrg return (IDENTIFIER_REPO_CHOSEN
3711debfc3dSmrg (DECL_ASSEMBLER_NAME (CLASSTYPE_VTABLES (class_type))));
3721debfc3dSmrg }
3731debfc3dSmrg
3741debfc3dSmrg #include "gt-cp-repo.h"
375