diff gcc/cp/repo.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/cp/repo.c	Fri Oct 27 22:46:09 2017 +0900
@@ -0,0 +1,375 @@
+/* Code to maintain a C++ template repository.
+   Copyright (C) 1995-2017 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 "cp-tree.h"
+#include "stringpool.h"
+#include "toplev.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"