xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/cp/repo.c (revision c0a68be459da21030695f60d10265c2fc49758f8)
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