Remove support for repo files (PR c++/91125).

2019-09-06  Martin Liska  <mliska@suse.cz>

	PR c++/91125
	* Makefile.in: Remove tlink.o.
	* collect2.c (do_link): New function isolated
	from do_tlink.
	(main): Use.
	* collect2.h (do_tlink): Remove declaration of do_tlink.
	* doc/extend.texi: Remove documentation of -frepo.
	* doc/invoke.texi: Likewise.
	* doc/sourcebuild.texi: Remove cleanup-repo-files.
	* tlink.c: Remove.
2019-09-06  Martin Liska  <mliska@suse.cz>

	PR c++/91125
	* c-common.c: Remove definition of flag_use_repository.
	* c-common.h: Likewise.
	* c-opts.c (c_common_handle_option):
	Do not handle OPT_frepo option.
	* c.opt: Mark the option with Deprecated.
2019-09-06  Martin Liska  <mliska@suse.cz>

	PR c++/91125
	* Make-lang.in: Remove repo.o.
	* config-lang.in: Likewise.
	* cp-tree.h (init_repo): Remove declarations
	of repo-related functions.
	(repo_emit_p): Likewise.
	(repo_export_class_p): Likewise.
	(finish_repo): Likewise.
	* decl2.c (import_export_class): Always
	set -1 value/
	(mark_needed): Remove -frepo from comment.
	(import_export_decl): Similarly here.
	(c_parse_final_cleanups): Remove call of finish_repo.
	* lex.c (cxx_init): Remove call to init_repo.
	* optimize.c (can_alias_cdtor): Remove dead condition.
	* pt.c (push_template_decl_real): Update comment.
	(instantiate_decl): Remove dead code used for -frepo.
	* repo.c: Remove.
2019-09-06  Martin Liska  <mliska@suse.cz>

	PR c++/91125
	* g++.dg/parse/repo1.C: Remove.
	* g++.dg/rtti/repo1.C: Remove.
	* g++.dg/template/repo1.C: Remove.
	* g++.dg/template/repo10.C: Remove.
	* g++.dg/template/repo11.C: Remove.
	* g++.dg/template/repo2.C: Remove.
	* g++.dg/template/repo3.C: Remove.
	* g++.dg/template/repo4.C: Remove.
	* g++.dg/template/repo5.C: Remove.
	* g++.dg/template/repo6.C: Remove.
	* g++.dg/template/repo7.C: Remove.
	* g++.dg/template/repo8.C: Remove.
	* g++.dg/template/repo9.C: Remove.
	* g++.old-deja/g++.pt/instantiate4.C: Remove.
	* g++.old-deja/g++.pt/instantiate6.C: Remove.
	* g++.old-deja/g++.pt/repo1.C: Remove.
	* g++.old-deja/g++.pt/repo2.C: Remove.
	* g++.old-deja/g++.pt/repo3.C: Remove.
	* g++.old-deja/g++.pt/repo4.C: Remove.
	* lib/g++.exp: Remove removal of repo files.
	* lib/gcc-dg.exp: Likewise.
	* lib/obj-c++.exp: Likewise.

From-SVN: r275450
This commit is contained in:
Martin Liska 2019-09-06 08:58:42 +02:00 committed by Martin Liska
parent ebd247d4b3
commit 67f6e64994
45 changed files with 112 additions and 1855 deletions

View File

@ -1,3 +1,16 @@
2019-09-06 Martin Liska <mliska@suse.cz>
PR c++/91125
* Makefile.in: Remove tlink.o.
* collect2.c (do_link): New function isolated
from do_tlink.
(main): Use.
* collect2.h (do_tlink): Remove declaration of do_tlink.
* doc/extend.texi: Remove documentation of -frepo.
* doc/invoke.texi: Likewise.
* doc/sourcebuild.texi: Remove cleanup-repo-files.
* tlink.c: Remove.
2019-09-05 Jakub Jelinek <jakub@redhat.com>
Jim Wilson <jimw@sifive.com>

View File

@ -2118,7 +2118,7 @@ gcc-ranlib.c: gcc-ar.c
gcc-nm.c: gcc-ar.c
cp $^ $@
COLLECT2_OBJS = collect2.o collect2-aix.o tlink.o vec.o ggc-none.o \
COLLECT2_OBJS = collect2.o collect2-aix.o vec.o ggc-none.o \
collect-utils.o file-find.o hash-table.o selftest.o
COLLECT2_LIBS = @COLLECT2_LIBS@
collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS)

View File

@ -1,3 +1,12 @@
2019-09-06 Martin Liska <mliska@suse.cz>
PR c++/91125
* c-common.c: Remove definition of flag_use_repository.
* c-common.h: Likewise.
* c-opts.c (c_common_handle_option):
Do not handle OPT_frepo option.
* c.opt: Mark the option with Deprecated.
2019-09-04 Marek Polacek <polacek@redhat.com>
* c.opt (fdeduce-init-list): Ignored.

View File

@ -249,11 +249,6 @@ const char *constant_string_class_name;
int warn_abi_version = -1;
/* Nonzero means generate separate instantiation control files and
juggle them at link time. */
int flag_use_repository;
/* The C++ dialect being used. Default set in c_common_post_options. */
enum cxx_dialect cxx_dialect = cxx_unset;

View File

@ -701,11 +701,6 @@ extern int warn_abi_version;
!= (warn_abi_version == 0 \
|| warn_abi_version >= (N)))
/* Nonzero means generate separate instantiation control files and
juggle them at link time. */
extern int flag_use_repository;
/* The supported C++ dialects. */
enum cxx_dialect {

View File

@ -501,12 +501,6 @@ c_common_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
cpp_opts->track_macro_expansion = 2;
break;
case OPT_frepo:
flag_use_repository = value;
if (value)
flag_implicit_templates = 0;
break;
case OPT_ftabstop_:
/* It is documented that we silently ignore silly values. */
if (value >= 1 && value <= 100)

View File

@ -1763,8 +1763,8 @@ ObjC ObjC++ LTO Var(flag_replace_objc_classes)
Used in Fix-and-Continue mode to indicate that object files may be swapped in at runtime.
frepo
C++ ObjC++
Enable automatic template instantiation.
C++ ObjC++ Deprecated
Deprecated in GCC 10. This switch has no effect.
frtti
C++ ObjC++ Optimization Var(flag_rtti) Init(1)

View File

@ -825,6 +825,30 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
else
post_ld_pass (false); /* No LTO objects were found, no temp file. */
}
/* Entry point for linker invoation. Called from main in collect2.c.
LD_ARGV is an array of arguments for the linker. */
static void
do_link (char **ld_argv)
{
struct pex_obj *pex;
const char *prog = "ld";
pex = collect_execute (prog, ld_argv, NULL, NULL,
PEX_LAST | PEX_SEARCH,
HAVE_GNU_LD && at_file_supplied);
int ret = collect_wait (prog, pex);
if (ret)
{
error ("ld returned %d exit status", ret);
exit (ret);
}
else
{
/* We have just successfully produced an output file, so assume that we
may unlink it if need be for now on. */
may_unlink_output_file = true;
}
}
/* Main program. */
@ -1704,7 +1728,7 @@ main (int argc, char **argv)
functions from precise cross reference insertions by the compiler. */
if (early_exit || ld1_filter != SCAN_NOTHING)
do_tlink (ld1_argv, object_lst);
do_link (ld1_argv);
if (early_exit)
{
@ -1762,10 +1786,10 @@ main (int argc, char **argv)
#endif
)
{
/* Do tlink without additional code generation now if we didn't
/* Do link without additional code generation now if we didn't
do it earlier for scanning purposes. */
if (ld1_filter == SCAN_NOTHING)
do_tlink (ld1_argv, object_lst);
do_link (ld1_argv);
if (lto_mode)
maybe_run_lto_and_relink (ld1_argv, object_lst, object, false);
@ -1868,13 +1892,13 @@ main (int argc, char **argv)
fork_execute ("gcc", c_argv, at_file_supplied);
#ifdef COLLECT_EXPORT_LIST
/* On AIX we must call tlink because of possible templates resolution. */
do_tlink (ld2_argv, object_lst);
/* On AIX we must call link because of possible templates resolution. */
do_link (ld2_argv);
if (lto_mode)
maybe_run_lto_and_relink (ld2_argv, object_lst, object, false);
#else
/* Otherwise, simply call ld because tlink is already done. */
/* Otherwise, simply call ld because link is already done. */
if (lto_mode)
maybe_run_lto_and_relink (ld2_argv, object_lst, object, true);
else

View File

@ -1,4 +1,4 @@
/* Header file for collect/tlink routines.
/* Header file for collect routines.
Copyright (C) 1998-2019 Free Software Foundation, Inc.
This file is part of GCC.
@ -20,8 +20,6 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_COLLECT2_H
#define GCC_COLLECT2_H
extern void do_tlink (char **, char **);
extern struct pex_obj *collect_execute (const char *, char **, const char *,
const char *, int flags);

View File

@ -1,3 +1,24 @@
2019-09-06 Martin Liska <mliska@suse.cz>
PR c++/91125
* Make-lang.in: Remove repo.o.
* config-lang.in: Likewise.
* cp-tree.h (init_repo): Remove declarations
of repo-related functions.
(repo_emit_p): Likewise.
(repo_export_class_p): Likewise.
(finish_repo): Likewise.
* decl2.c (import_export_class): Always
set -1 value/
(mark_needed): Remove -frepo from comment.
(import_export_decl): Similarly here.
(c_parse_final_cleanups): Remove call of finish_repo.
* lex.c (cxx_init): Remove call to init_repo.
* optimize.c (can_alias_cdtor): Remove dead condition.
* pt.c (push_template_decl_real): Update comment.
(instantiate_decl): Remove dead code used for -frepo.
* repo.c: Remove.
2019-09-05 Marek Polacek <polacek@redhat.com>
PR c++/91644 - ICE with constinit in function template.

View File

@ -83,7 +83,7 @@ CXX_AND_OBJCXX_OBJS = \
cp/mangle.o cp/method.o \
cp/name-lookup.o cp/optimize.o \
cp/parser.o cp/pt.o cp/ptree.o \
cp/repo.o cp/rtti.o \
cp/rtti.o \
cp/search.o cp/semantics.o \
cp/tree.o cp/typeck.o cp/typeck2.o \
cp/vtable-class-hierarchy.o $(CXX_C_OBJS)

View File

@ -49,7 +49,7 @@ gtfiles="\
\$(srcdir)/cp/mangle.c \$(srcdir)/cp/method.c \
\$(srcdir)/cp/name-lookup.c \
\$(srcdir)/cp/parser.c \$(srcdir)/cp/pt.c \
\$(srcdir)/cp/repo.c \$(srcdir)/cp/rtti.c \
\$(srcdir)/cp/rtti.c \
\$(srcdir)/cp/semantics.c \
\$(srcdir)/cp/tree.c \$(srcdir)/cp/typeck2.c \
\$(srcdir)/cp/vtable-class-hierarchy.c \

View File

@ -6903,12 +6903,6 @@ extern bool copy_guide_p (const_tree);
extern bool template_guide_p (const_tree);
extern void store_explicit_specifier (tree, tree);
/* in repo.c */
extern void init_repo (void);
extern int repo_emit_p (tree);
extern bool repo_export_class_p (const_tree);
extern void finish_repo (void);
/* in rtti.c */
/* A vector of all tinfo decls that haven't been emitted yet. */
extern GTY(()) vec<tree, va_gc> *unemitted_tinfo_decls;

View File

@ -2079,7 +2079,7 @@ import_export_class (tree ctype)
repository. If the virtual table is assigned to this
translation unit, then export the class; otherwise, import
it. */
import_export = repo_export_class_p (ctype) ? 1 : -1;
import_export = -1;
else if (TYPE_POLYMORPHIC_P (ctype))
{
/* The ABI specifies that the virtual table and associated
@ -2135,7 +2135,7 @@ mark_needed (tree decl)
struct cgraph_node *node = cgraph_node::get_create (decl);
node->forced_by_abi = true;
/* #pragma interface and -frepo code can call mark_needed for
/* #pragma interface can call mark_needed for
maybe-in-charge 'tors; mark the clones as well. */
tree clone;
FOR_EACH_CLONE (clone, decl)
@ -2969,7 +2969,6 @@ tentative_decl_linkage (tree decl)
void
import_export_decl (tree decl)
{
int emit_p;
bool comdat_p;
bool import_p;
tree class_type = NULL_TREE;
@ -2980,11 +2979,7 @@ import_export_decl (tree decl)
/* We cannot determine what linkage to give to an entity with vague
linkage until the end of the file. For example, a virtual table
for a class will be defined if and only if the key method is
defined in this translation unit. As a further example, consider
that when compiling a translation unit that uses PCH file with
"-frepo" it would be incorrect to make decisions about what
entities to emit when building the PCH; those decisions must be
delayed until the repository information has been processed. */
defined in this translation unit. */
gcc_assert (at_eof);
/* Object file linkage for explicit instantiations is handled in
mark_decl_instantiated. For static variables in functions with
@ -3030,27 +3025,7 @@ import_export_decl (tree decl)
unit. */
import_p = false;
/* See if the repository tells us whether or not to emit DECL in
this translation unit. */
emit_p = repo_emit_p (decl);
if (emit_p == 0)
import_p = true;
else if (emit_p == 1)
{
/* The repository indicates that this entity should be defined
here. Make sure the back end honors that request. */
mark_needed (decl);
/* Output the definition as an ordinary strong definition. */
DECL_EXTERNAL (decl) = 0;
DECL_INTERFACE_KNOWN (decl) = 1;
return;
}
if (import_p)
/* We have already decided what to do with this DECL; there is no
need to check anything further. */
;
else if (VAR_P (decl) && DECL_VTABLE_OR_VTT_P (decl))
if (VAR_P (decl) && DECL_VTABLE_OR_VTT_P (decl))
{
class_type = DECL_CONTEXT (decl);
import_export_class (class_type);
@ -3156,8 +3131,7 @@ import_export_decl (tree decl)
{
/* DECL is an implicit instantiation of a function or static
data member. */
if ((flag_implicit_templates
&& !flag_use_repository)
if (flag_implicit_templates
|| (flag_implicit_inline_templates
&& TREE_CODE (decl) == FUNCTION_DECL
&& DECL_DECLARED_INLINE_P (decl)))
@ -5142,7 +5116,6 @@ c_parse_final_cleanups (void)
perform_deferred_noexcept_checks ();
finish_repo ();
fini_constexpr ();
/* The entire file is now complete. If requested, dump everything

View File

@ -332,8 +332,6 @@ cxx_init (void)
init_cp_pragma ();
init_repo ();
input_location = saved_loc;
return true;
}

View File

@ -223,9 +223,6 @@ can_alias_cdtor (tree fn)
/* We can't use an alias if there are virtual bases. */
if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn)))
return false;
/* ??? Why not use aliases with -frepo? */
if (flag_use_repository)
return false;
gcc_assert (DECL_MAYBE_IN_CHARGE_CDTOR_P (fn));
/* Don't use aliases for weak/linkonce definitions unless we can put both
symbols in the same COMDAT group. */

View File

@ -5835,7 +5835,7 @@ push_template_decl_real (tree decl, bool is_friend)
&& TREE_PUBLIC (decl)
&& VAR_OR_FUNCTION_DECL_P (decl))
/* Set DECL_COMDAT on template instantiations; if we force
them to be emitted by explicit instantiation or -frepo,
them to be emitted by explicit instantiation,
mark_needed will tell cgraph to do the right thing. */
DECL_COMDAT (decl) = true;
@ -24671,22 +24671,6 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
add_pending_template (d);
goto out;
}
/* Tell the repository that D is available in this translation unit
-- and see if it is supposed to be instantiated here. */
if (TREE_PUBLIC (d) && !DECL_REALLY_EXTERN (d) && !repo_emit_p (d))
{
/* In a PCH file, despite the fact that the repository hasn't
requested instantiation in the PCH it is still possible that
an instantiation will be required in a file that includes the
PCH. */
if (pch_file)
add_pending_template (d);
/* Instantiate inline functions so that the inliner can do its
job, even though we'll not be emitting a copy of this
function. */
if (!(TREE_CODE (d) == FUNCTION_DECL && possibly_inlined_p (d)))
goto out;
}
bool push_to_top, nested;
tree fn_context;

View File

@ -1,374 +0,0 @@
/* Code to maintain a C++ template repository.
Copyright (C) 1995-2019 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 ("cannot 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_CDTOR_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"

View File

@ -24423,31 +24423,6 @@ fine-grained control when necessary. It is also the most portable
alternative and programs using this approach will work with most modern
compilers.
@item
@opindex frepo
Compile your template-using code with @option{-frepo}. The compiler
generates files with the extension @samp{.rpo} listing all of the
template instantiations used in the corresponding object files that
could be instantiated there; the link wrapper, @samp{collect2},
then updates the @samp{.rpo} files to tell the compiler where to place
those instantiations and rebuild any affected object files. The
link-time overhead is negligible after the first pass, as the compiler
continues to place the instantiations in the same files.
This can be a suitable option for application code written for the Borland
model, as it usually just works. Code written for the Cfront model
needs to be modified so that the template definitions are available at
one or more points of instantiation; usually this is as simple as adding
@code{#include <tmethods.cc>} to the end of each template header.
For library code, if you want the library to provide all of the template
instantiations it needs, just try to link all of its object files
together; the link will fail, but cause the instantiations to be
generated as a side effect. Be warned, however, that this may cause
conflicts if multiple libraries try to provide the same instantiations.
For greater control, use explicit instantiation as described in the next
option.
@item
@opindex fno-implicit-templates
Compile your code with @option{-fno-implicit-templates} to disable the

View File

@ -222,7 +222,7 @@ in the following sections.
-fno-nonansi-builtins -fnothrow-opt -fno-operator-names @gol
-fno-optional-diags -fpermissive @gol
-fno-pretty-templates @gol
-frepo -fno-rtti -fsized-deallocation @gol
-fno-rtti -fsized-deallocation @gol
-ftemplate-backtrace-limit=@var{n} @gol
-ftemplate-depth=@var{n} @gol
-fno-threadsafe-statics -fuse-cxa-atexit @gol
@ -2701,12 +2701,6 @@ the default template arguments for that template. If either of these
behaviors make it harder to understand the error message rather than
easier, you can use @option{-fno-pretty-templates} to disable them.
@item -frepo
@opindex frepo
Enable automatic template instantiation at link time. This option also
implies @option{-fno-implicit-templates}. @xref{Template
Instantiation}, for more information.
@item -fno-rtti
@opindex fno-rtti
@opindex frtti

View File

@ -2864,9 +2864,6 @@ int main() @{ return 0; @}
@item cleanup-profile-file
Removes profiling files generated for this test.
@item cleanup-repo-files
Removes files generated for this test for @option{-frepo}.
@end table
@node Ada Tests

View File

@ -1,3 +1,29 @@
2019-09-06 Martin Liska <mliska@suse.cz>
PR c++/91125
* g++.dg/parse/repo1.C: Remove.
* g++.dg/rtti/repo1.C: Remove.
* g++.dg/template/repo1.C: Remove.
* g++.dg/template/repo10.C: Remove.
* g++.dg/template/repo11.C: Remove.
* g++.dg/template/repo2.C: Remove.
* g++.dg/template/repo3.C: Remove.
* g++.dg/template/repo4.C: Remove.
* g++.dg/template/repo5.C: Remove.
* g++.dg/template/repo6.C: Remove.
* g++.dg/template/repo7.C: Remove.
* g++.dg/template/repo8.C: Remove.
* g++.dg/template/repo9.C: Remove.
* g++.old-deja/g++.pt/instantiate4.C: Remove.
* g++.old-deja/g++.pt/instantiate6.C: Remove.
* g++.old-deja/g++.pt/repo1.C: Remove.
* g++.old-deja/g++.pt/repo2.C: Remove.
* g++.old-deja/g++.pt/repo3.C: Remove.
* g++.old-deja/g++.pt/repo4.C: Remove.
* lib/g++.exp: Remove removal of repo files.
* lib/gcc-dg.exp: Likewise.
* lib/obj-c++.exp: Likewise.
2019-09-05 Jakub Jelinek <jakub@redhat.com>
Jim Wilson <jimw@sifive.com>

View File

@ -1,10 +0,0 @@
// { dg-options "-frepo" }
// { dg-require-host-local "" }
extern "C" inline void f() {}
int main () {
f();
}
// { dg-final { cleanup-repo-files } }

View File

@ -1,19 +0,0 @@
// PR c++/22204
// { dg-options "-frepo" }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
#include <typeinfo>
template<int>
struct function1
{
function1()
{
typeid(int[100]);
}
};
function1<1> b;
int main () {}
// { dg-final { cleanup-repo-files } }

View File

@ -1,20 +0,0 @@
// { dg-options "-frepo" }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
struct A {
A();
};
A::A() {}
template <typename T>
struct B : public A {
B() {} // { dg-bogus "" }
};
B<int> b;
int main () {}
// { dg-final { cleanup-repo-files } }

View File

@ -1,16 +0,0 @@
// PR c++/51910
// { dg-options -frepo }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
// { dg-final cleanup-repo-files }
template<typename T>
struct Foo
{
virtual ~Foo() { }
};
int main( int, char*[] )
{
Foo<int> test;
}

View File

@ -1,31 +0,0 @@
// PR c++/64521
// { dg-options "-frepo -std=c++11" }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
// { dg-final cleanup-repo-files }
template <typename H> struct J { J(H) {} };
template <unsigned long, typename...> struct K;
template <unsigned long I> struct K<I> {};
template <unsigned long I, typename H, typename... T>
struct K<I, H, T...> : K<I + 1, T...>, J<H> {
K(const H &p1, const T &... p2) : K<I + 1, T...>(p2...), J<H>(p1) {}
};
template <typename... E> struct C : K<0, E...> {
C(const E &... p1) : K<0, E...>(p1...) {}
};
template <typename> struct A {
A() = default;
};
struct M;
template <typename> struct L {
struct B {
template <typename> static M *__test(...);
typedef A<int> _Del;
typedef decltype(__test<_Del>()) type;
};
C<typename B::type, A<M>> _M_t;
L(typename B::type) : _M_t(0, A<M>()) {}
};
struct M {};
int main() { L<int>(new M); }

View File

@ -1,18 +0,0 @@
// PR c++/17163
// { dg-options "-frepo" }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
template <int __inst>
struct __Atomicity_lock
{
static unsigned char _S_atomicity_lock;
};
template <int __inst>
unsigned char __Atomicity_lock<__inst>::_S_atomicity_lock = 0;
template unsigned char __Atomicity_lock<0>::_S_atomicity_lock;
int main () {
}
// { dg-final { cleanup-repo-files } }

View File

@ -1,11 +0,0 @@
// { dg-options "-frepo -DF='a'" }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
template <typename A, typename B> void f () {}
template <typename A, typename B> void g () { f<int,int>(); }
int main () { g<int,int>(); }
char c = F;
// { dg-final { cleanup-repo-files } }

View File

@ -1,18 +0,0 @@
// PR c++/17775
// { dg-options "-frepo" }
// { dg-final { cleanup-repo-files } }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
namespace {
struct Foo {};
}
template <typename Tp>
void foo(Tp) {}
int
main()
{
foo(Foo());
}

View File

@ -1,14 +0,0 @@
// PR c++/25625
// { dg-options "-frepo" }
// { dg-final { cleanup-repo-files } }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
template< typename T, T N > struct integral_c {
static const T value = N;
typedef integral_c< T, value + 1 > next;
};
template< typename T, T N > T const integral_c< T, N >::value;
integral_c<int,0> a;
int main () {}

View File

@ -1,26 +0,0 @@
// PR c++/34178
// { dg-options "-frepo" }
// { dg-final { cleanup-repo-files } }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
template<typename T>
class A
{
private:
static const int x;
static int y;
public:
int getX () { return x + y; }
};
template<typename T> const int A<T>::x = 0;
template<typename T> int A<T>::y = 0;
int
main ()
{
A<int> a;
return a.getX();
}

View File

@ -1,25 +0,0 @@
// PR c++/34340
// { dg-options "-frepo" }
// { dg-final { cleanup-repo-files } }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
struct A
{
int a;
};
template <typename T> struct D
{
static const A b;
};
template<typename T> const A D<T>::b = { 2 };
template class D<A>;
const A *x = &D<A>::b;
int
main ()
{
}

View File

@ -1,24 +0,0 @@
// PR c++/34340
// { dg-options "-frepo" }
// { dg-final { cleanup-repo-files } }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
struct A
{
int a;
};
template <typename T> struct D
{
static const A b;
};
template<typename T> const A D<T>::b = { 2 };
const A *x = &D<A>::b;
int
main ()
{
}

View File

@ -1,49 +0,0 @@
// PR c++/36364
// { dg-options "-frepo" }
// { dg-final { cleanup-repo-files } }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
template <typename C> struct A
{
static void assign (C &c1, const C &c2) { c1 = c2; }
};
template <typename C, typename T> struct B
{
struct D
{
static const C terminal;
static unsigned long stor[];
static D &empty_rep ()
{
void *p = reinterpret_cast <void *>(&stor);
return *reinterpret_cast <D *>(p);
}
void test (unsigned long n)
{
T::assign (this->refdata ()[n], terminal);
}
C *refdata () throw ()
{
return reinterpret_cast <C *>(this + 1);
}
};
C *dataplus;
C *data () const { return dataplus; }
D *rep () const { return &((reinterpret_cast < D * >(data ()))[-1]); }
static D & empty_rep () { return D::empty_rep (); }
B () : dataplus (empty_rep ().refdata ()) { }
~B () { }
void push_back (C c) { rep ()->test (10); }
};
template <typename C, typename T> const C B <C, T>::D::terminal = C ();
template <typename C, typename T> unsigned long B <C, T>::D::stor[64];
int
main ()
{
B <char, A <char> > s;
s.push_back ('a');
}

View File

@ -1,31 +0,0 @@
// { dg-do link }
// { dg-options "-frepo -Werror" }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
// Submitted by Melissa O'Neill <oneill@cs.sfu.ca>
// the vtable of Foo<int> wouldn't be generated
template <typename A>
struct Foo {
virtual void foo() {}
};
template <typename A>
struct Bar {
void bar();
};
template <typename A>
void Bar<A>::bar() {
Foo<A> oof;
}
int main () {
Bar<int> rab;
rab.bar();
}
// { dg-final { cleanup-repo-files } }

View File

@ -1,29 +0,0 @@
// { dg-do link }
// { dg-options "-frepo" }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
// Simplified from testcase by Erez Louidor Lior <s3824888@techst02.technion.ac.il>
template <class T>
class foo{
public:
void g();
void h();
};
template <class T>
void foo<T>::g() {
h();
}
template <class T>
void foo<T>::h() {
}
int main() {
foo<int> f;
f.g();
}
// { dg-final { cleanup-repo-files } }

View File

@ -1,24 +0,0 @@
// { dg-do link }
// { dg-options "-frepo" }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
// Bug: g++ complains about duplicate explicit instantiations with -frepo.
// From Jason Merrill <jason@cygnus.com>
// Build then link:
template <class T> struct A {
virtual ~A () { }
};
template <class T> void g (T t) { }
template class A<int>;
int main ()
{
g (42);
}
// { dg-final { cleanup-repo-files } }

View File

@ -1,28 +0,0 @@
// { dg-do link }
// { dg-options "-frepo" }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
// Test that collect2 isn't confused by GNU ld's "In function `foo':" message.
// Contributed by Jason Merrill <jason@cygnus.com>
// Build then link:
template <class T>
T f (T t)
{
return t;
}
template <class T>
T g (T t)
{
return f (t);
}
int main ()
{
int i = g (42);
}
// { dg-final { cleanup-repo-files } }

View File

@ -1,39 +0,0 @@
// { dg-do link }
// { dg-options "-frepo" }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
// Test that we properly generate the vtable and such for C.
// Contributed by scott snyder <snyder@fnal.gov>
// Build then link:
struct A
{
virtual ~A () {}
};
template <typename T>
struct B : virtual public A
{
virtual void foo () {}
};
template <typename T>
struct C : virtual public A
{
};
template <typename T>
struct D : public B<T>, public C<T>
{
};
int
main ()
{
D<int> x;
return 0;
}
// { dg-final { cleanup-repo-files } }

View File

@ -1,19 +0,0 @@
// { dg-do link }
// { dg-options "-frepo" }
// { dg-require-host-local "" }
// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
template <class T>
struct S {
~S ();
};
template <class T>
S<T>::~S () {}
int main ()
{
S<int> s;
}
// { dg-final { cleanup-repo-files } }

View File

@ -317,12 +317,6 @@ proc g++_target_compile { source dest type options } {
set options [concat "$ALWAYS_CXXFLAGS" $options]
if { [regexp "(^| )-frepo( |$)" $options] && \
[regexp "\.o(|bj)$" $dest] } then {
regsub "\.o(|bj)$" $dest ".rpo" rponame
exec rm -f $rponame
}
# bind_pic_locally adds -fpie/-fPIE flags to flags_to_postpone and it is
# appended here to multilib_flags as it can be overridden by the latter
# if it was added earlier. After the target_compile, multilib_flags is

View File

@ -242,14 +242,6 @@ proc gcc-dg-test-1 { target_compile prog do_what extra_tool_flags } {
set options [list]
# Tests should be able to use "dg-do repo". However, the dg test
# driver checks the argument to dg-do against a list of acceptable
# options, and "repo" is not among them. Therefore, we resort to
# this ugly approach.
if [string match "*-frepo*" $extra_tool_flags] then {
set do_what "repo"
}
switch $do_what {
"preprocess" {
set compile_type "preprocess"
@ -724,24 +716,6 @@ proc cleanup-coverage-files { } {
}
}
# Remove compiler-generated files from -repo for the current test.
proc cleanup-repo-files { } {
global additional_sources_used
set testcase [testname-for-summary]
# The name might include a list of options; extract the file name.
set testcase [lindex $testcase 0]
remove-build-file "[file rootname [file tail $testcase]].o"
remove-build-file "[file rootname [file tail $testcase]].rpo"
# Clean up files for additional source files.
if [info exists additional_sources_used] {
foreach srcfile $additional_sources_used {
remove-build-file "[file rootname [file tail $srcfile]].o"
remove-build-file "[file rootname [file tail $srcfile]].rpo"
}
}
}
# Remove a final insns dump file for the current test.
proc cleanup-final-insns-dump { } {
set testcase [testname-for-summary]

View File

@ -377,12 +377,6 @@ proc obj-c++_target_compile { source dest type options } {
set options [concat "$ALWAYS_OBJCXXFLAGS" $options];
if { [regexp "(^| )-frepo( |$)" $options] && \
[regexp "\.o(|bj)$" $dest] } then {
regsub "\.o(|bj)$" $dest ".rpo" rponame
exec rm -f $rponame
}
set options [dg-additional-files-options $options $source]
set result [target_compile $source $dest $type $options]

View File

@ -1,867 +0,0 @@
/* Scan linker error messages for missing template instantiations and provide
them.
Copyright (C) 1995-2019 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/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "intl.h"
#include "obstack.h"
#include "demangle.h"
#include "collect2.h"
#include "collect-utils.h"
#include "filenames.h"
#include "diagnostic-core.h"
/* TARGET_64BIT may be defined to use driver specific functionality. */
#undef TARGET_64BIT
#define TARGET_64BIT TARGET_64BIT_DEFAULT
#define MAX_ITERATIONS 17
/* Defined in the automatically-generated underscore.c. */
extern int prepends_underscore;
static int tlink_verbose;
static char *initial_cwd;
/* Hash table boilerplate for working with htab_t. We have hash tables
for symbol names, file names, and demangled symbols. */
typedef struct symbol_hash_entry
{
const char *key;
struct file_hash_entry *file;
int chosen;
int tweaking;
int tweaked;
} symbol;
typedef struct file_hash_entry
{
const char *key;
const char *args;
const char *dir;
const char *main;
int tweaking;
} file;
typedef const char *str;
typedef struct demangled_hash_entry
{
const char *key;
vec<str> mangled;
} demangled;
/* Hash and comparison functions for these hash tables. */
static int hash_string_eq (const void *, const void *);
static hashval_t hash_string_hash (const void *);
static int
hash_string_eq (const void *s1_p, const void *s2_p)
{
const char *const *s1 = (const char *const *) s1_p;
const char *s2 = (const char *) s2_p;
return strcmp (*s1, s2) == 0;
}
static hashval_t
hash_string_hash (const void *s_p)
{
const char *const *s = (const char *const *) s_p;
return (*htab_hash_string) (*s);
}
static htab_t symbol_table;
static struct symbol_hash_entry * symbol_hash_lookup (const char *, int);
static struct file_hash_entry * file_hash_lookup (const char *);
static struct demangled_hash_entry *demangled_hash_lookup (const char *, int);
static void symbol_push (symbol *);
static symbol * symbol_pop (void);
static void file_push (file *);
static file * file_pop (void);
static char * frob_extension (const char *, const char *);
static char * obstack_fgets (FILE *, struct obstack *);
static char * tfgets (FILE *);
static char * pfgets (FILE *);
static void freadsym (FILE *, file *, int);
static void read_repo_file (file *);
static void maybe_tweak (char *, file *);
static int recompile_files (void);
static int read_repo_files (char **);
static void demangle_new_symbols (void);
static int scan_linker_output (const char *);
/* Look up an entry in the symbol hash table. */
static struct symbol_hash_entry *
symbol_hash_lookup (const char *string, int create)
{
void **e;
e = htab_find_slot_with_hash (symbol_table, string,
(*htab_hash_string) (string),
create ? INSERT : NO_INSERT);
if (e == NULL)
return NULL;
if (*e == NULL)
{
struct symbol_hash_entry *v;
*e = v = XCNEW (struct symbol_hash_entry);
v->key = xstrdup (string);
}
return (struct symbol_hash_entry *) *e;
}
static htab_t file_table;
/* Look up an entry in the file hash table. */
static struct file_hash_entry *
file_hash_lookup (const char *string)
{
void **e;
e = htab_find_slot_with_hash (file_table, string,
(*htab_hash_string) (string),
INSERT);
if (*e == NULL)
{
struct file_hash_entry *v;
*e = v = XCNEW (struct file_hash_entry);
v->key = xstrdup (string);
}
return (struct file_hash_entry *) *e;
}
static htab_t demangled_table;
/* Look up an entry in the demangled name hash table. */
static struct demangled_hash_entry *
demangled_hash_lookup (const char *string, int create)
{
void **e;
e = htab_find_slot_with_hash (demangled_table, string,
(*htab_hash_string) (string),
create ? INSERT : NO_INSERT);
if (e == NULL)
return NULL;
if (*e == NULL)
{
struct demangled_hash_entry *v;
*e = v = XCNEW (struct demangled_hash_entry);
v->key = xstrdup (string);
}
return (struct demangled_hash_entry *) *e;
}
/* Stack code. */
struct symbol_stack_entry
{
symbol *value;
struct symbol_stack_entry *next;
};
struct obstack symbol_stack_obstack;
struct symbol_stack_entry *symbol_stack;
struct file_stack_entry
{
file *value;
struct file_stack_entry *next;
};
struct obstack file_stack_obstack;
struct file_stack_entry *file_stack;
static void
symbol_push (symbol *p)
{
struct symbol_stack_entry *ep
= XOBNEW (&symbol_stack_obstack, struct symbol_stack_entry);
ep->value = p;
ep->next = symbol_stack;
symbol_stack = ep;
}
static symbol *
symbol_pop (void)
{
struct symbol_stack_entry *ep = symbol_stack;
symbol *p;
if (ep == NULL)
return NULL;
p = ep->value;
symbol_stack = ep->next;
obstack_free (&symbol_stack_obstack, ep);
return p;
}
static void
file_push (file *p)
{
struct file_stack_entry *ep;
if (p->tweaking)
return;
ep = XOBNEW (&file_stack_obstack, struct file_stack_entry);
ep->value = p;
ep->next = file_stack;
file_stack = ep;
p->tweaking = 1;
}
static file *
file_pop (void)
{
struct file_stack_entry *ep = file_stack;
file *p;
if (ep == NULL)
return NULL;
p = ep->value;
file_stack = ep->next;
obstack_free (&file_stack_obstack, ep);
p->tweaking = 0;
return p;
}
/* Other machinery. */
/* Initialize the tlink machinery. Called from do_tlink. */
static void
tlink_init (void)
{
const char *p;
symbol_table = htab_create (500, hash_string_hash, hash_string_eq,
NULL);
file_table = htab_create (500, hash_string_hash, hash_string_eq,
NULL);
demangled_table = htab_create (500, hash_string_hash, hash_string_eq,
NULL);
obstack_begin (&symbol_stack_obstack, 0);
obstack_begin (&file_stack_obstack, 0);
p = getenv ("TLINK_VERBOSE");
if (p)
tlink_verbose = atoi (p);
else
{
tlink_verbose = 1;
if (verbose)
tlink_verbose = 2;
if (debug)
tlink_verbose = 3;
}
initial_cwd = getpwd ();
}
static int
tlink_execute (const char *prog, char **argv, const char *outname,
const char *errname, bool use_atfile)
{
struct pex_obj *pex;
pex = collect_execute (prog, argv, outname, errname,
PEX_LAST | PEX_SEARCH, use_atfile);
return collect_wait (prog, pex);
}
static char *
frob_extension (const char *s, const char *ext)
{
const char *p;
p = strrchr (lbasename (s), '.');
if (! p)
p = s + strlen (s);
obstack_grow (&temporary_obstack, s, p - s);
return (char *) obstack_copy0 (&temporary_obstack, ext, strlen (ext));
}
static char *
obstack_fgets (FILE *stream, struct obstack *ob)
{
int c;
while ((c = getc (stream)) != EOF && c != '\n')
obstack_1grow (ob, c);
if (obstack_object_size (ob) == 0)
return NULL;
obstack_1grow (ob, '\0');
return XOBFINISH (ob, char *);
}
static char *
tfgets (FILE *stream)
{
return obstack_fgets (stream, &temporary_obstack);
}
static char *
pfgets (FILE *stream)
{
return xstrdup (tfgets (stream));
}
/* Real tlink code. */
/* Subroutine of read_repo_file. We are reading the repo file for file F,
which is coming in on STREAM, and the symbol that comes next in STREAM
is offered, chosen or provided if CHOSEN is 0, 1 or 2, respectively.
XXX "provided" is unimplemented, both here and in the compiler. */
static void
freadsym (FILE *stream, file *f, int chosen)
{
symbol *sym;
{
const char *name = tfgets (stream);
sym = symbol_hash_lookup (name, true);
}
if (sym->file == NULL)
{
/* We didn't have this symbol already, so we choose this file. */
symbol_push (sym);
sym->file = f;
sym->chosen = chosen;
}
else if (chosen)
{
/* We want this file; cast aside any pretender. */
if (sym->chosen && sym->file != f)
{
if (sym->chosen == 1)
file_push (sym->file);
else
{
file_push (f);
f = sym->file;
chosen = sym->chosen;
}
}
sym->file = f;
sym->chosen = chosen;
}
}
/* Read in the repo file denoted by F, and record all its information. */
static void
read_repo_file (file *f)
{
char c;
FILE *stream = fopen (f->key, "r");
if (tlink_verbose >= 2)
fprintf (stderr, _("collect: reading %s\n"), f->key);
while (fscanf (stream, "%c ", &c) == 1)
{
switch (c)
{
case 'A':
f->args = pfgets (stream);
break;
case 'D':
f->dir = pfgets (stream);
break;
case 'M':
f->main = pfgets (stream);
break;
case 'P':
freadsym (stream, f, 2);
break;
case 'C':
freadsym (stream, f, 1);
break;
case 'O':
freadsym (stream, f, 0);
break;
}
obstack_free (&temporary_obstack, temporary_firstobj);
}
fclose (stream);
if (f->args == NULL)
f->args = getenv ("COLLECT_GCC_OPTIONS");
if (f->dir == NULL)
f->dir = ".";
}
/* We might want to modify LINE, which is a symbol line from file F. We do
this if either we saw an error message referring to the symbol in
question, or we have already allocated the symbol to another file and
this one wants to emit it as well. */
static void
maybe_tweak (char *line, file *f)
{
symbol *sym = symbol_hash_lookup (line + 2, false);
if ((sym->file == f && sym->tweaking)
|| (sym->file != f && line[0] == 'C'))
{
sym->tweaking = 0;
sym->tweaked = 1;
if (line[0] == 'O')
{
line[0] = 'C';
sym->chosen = 1;
}
else
{
line[0] = 'O';
sym->chosen = 0;
}
}
}
/* Update the repo files for each of the object files we have adjusted and
recompile. */
static int
recompile_files (void)
{
file *f;
putenv (xstrdup ("COMPILER_PATH="));
putenv (xstrdup ("LIBRARY_PATH="));
while ((f = file_pop ()) != NULL)
{
char *line;
const char *p, *q;
char **argv;
struct obstack arg_stack;
FILE *stream = fopen (f->key, "r");
const char *const outname = frob_extension (f->key, ".rnw");
FILE *output = fopen (outname, "w");
while ((line = tfgets (stream)) != NULL)
{
switch (line[0])
{
case 'C':
case 'O':
maybe_tweak (line, f);
}
fprintf (output, "%s\n", line);
}
fclose (stream);
fclose (output);
/* On Windows "rename" returns -1 and sets ERRNO to EACCESS if
the new file name already exists. Therefore, we explicitly
remove the old file first. */
if (remove (f->key) == -1)
fatal_error (input_location,
"removing repository file %qs: %m", f->key);
if (rename (outname, f->key) == -1)
fatal_error (input_location, "renaming repository file from "
"%qs to %qs: %m", outname, f->key);
if (!f->args)
{
error ("repository file %qs does not contain command-line "
"arguments", f->key);
return 0;
}
/* Build a null-terminated argv array suitable for
tlink_execute(). Manipulate arguments on the arg_stack while
building argv on the temporary_obstack. */
obstack_init (&arg_stack);
obstack_ptr_grow (&temporary_obstack, c_file_name);
for (p = f->args; *p != '\0'; p = q + 1)
{
/* Arguments are delimited by single-quotes. Find the
opening quote. */
p = strchr (p, '\'');
if (!p)
goto done;
/* Find the closing quote. */
q = strchr (p + 1, '\'');
if (!q)
goto done;
obstack_grow (&arg_stack, p + 1, q - (p + 1));
/* Replace '\'' with '. This is how set_collect_gcc_options
encodes a single-quote. */
while (q[1] == '\\' && q[2] == '\'' && q[3] == '\'')
{
const char *r;
r = strchr (q + 4, '\'');
if (!r)
goto done;
obstack_grow (&arg_stack, q + 3, r - (q + 3));
q = r;
}
obstack_1grow (&arg_stack, '\0');
obstack_ptr_grow (&temporary_obstack, obstack_finish (&arg_stack));
}
done:
obstack_ptr_grow (&temporary_obstack, f->main);
obstack_ptr_grow (&temporary_obstack, NULL);
argv = XOBFINISH (&temporary_obstack, char **);
if (tlink_verbose)
fprintf (stderr, _("collect: recompiling %s\n"), f->main);
if (chdir (f->dir) != 0
|| tlink_execute (c_file_name, argv, NULL, NULL, false) != 0
|| chdir (initial_cwd) != 0)
return 0;
read_repo_file (f);
obstack_free (&arg_stack, NULL);
obstack_free (&temporary_obstack, temporary_firstobj);
}
return 1;
}
/* The first phase of processing: determine which object files have
.rpo files associated with them, and read in the information. */
static int
read_repo_files (char **object_lst)
{
char **object = object_lst;
for (; *object; object++)
{
const char *p;
file *f;
/* Don't bother trying for ld flags. */
if (*object[0] == '-')
continue;
p = frob_extension (*object, ".rpo");
if (! file_exists (p))
continue;
f = file_hash_lookup (p);
read_repo_file (f);
}
if (file_stack != NULL && ! recompile_files ())
return 0;
return (symbol_stack != NULL);
}
/* Add the demangled forms of any new symbols to the hash table. */
static void
demangle_new_symbols (void)
{
symbol *sym;
while ((sym = symbol_pop ()) != NULL)
{
demangled *dem;
const char *p = cplus_demangle (sym->key, DMGL_PARAMS | DMGL_ANSI);
if (! p)
continue;
dem = demangled_hash_lookup (p, true);
dem->mangled.safe_push (sym->key);
}
}
/* We want to tweak symbol SYM. Return true if all is well, false on
error. */
static bool
start_tweaking (symbol *sym)
{
if (sym && sym->tweaked)
{
error ("%qs was assigned to %qs, but was not defined "
"during recompilation, or vice versa",
sym->key, sym->file->key);
return 0;
}
if (sym && !sym->tweaking)
{
if (tlink_verbose >= 2)
fprintf (stderr, _("collect: tweaking %s in %s\n"),
sym->key, sym->file->key);
sym->tweaking = 1;
file_push (sym->file);
}
return true;
}
/* Step through the output of the linker, in the file named FNAME, and
adjust the settings for each symbol encountered. */
static int
scan_linker_output (const char *fname)
{
FILE *stream = fopen (fname, "r");
char *line;
int skip_next_in_line = 0;
while ((line = tfgets (stream)) != NULL)
{
char *p = line, *q;
symbol *sym;
demangled *dem = 0;
int end;
int ok = 0;
unsigned ix;
str s;
/* On darwin9, we might have to skip " in " lines as well. */
if (skip_next_in_line
&& strstr (p, " in "))
continue;
skip_next_in_line = 0;
while (*p && ISSPACE ((unsigned char) *p))
++p;
if (! *p)
continue;
for (q = p; *q && ! ISSPACE ((unsigned char) *q); ++q)
;
/* Try the first word on the line. */
if (*p == '.')
++p;
if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)))
p += strlen (USER_LABEL_PREFIX);
end = ! *q;
*q = 0;
sym = symbol_hash_lookup (p, false);
/* Some SVR4 linkers produce messages like
ld: 0711-317 ERROR: Undefined symbol: .g__t3foo1Zi
*/
if (! sym && ! end && strstr (q + 1, "Undefined symbol: "))
{
char *p = strrchr (q + 1, ' ');
p++;
if (*p == '.')
p++;
if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)))
p += strlen (USER_LABEL_PREFIX);
sym = symbol_hash_lookup (p, false);
}
if (! sym && ! end)
/* Try a mangled name in quotes. */
{
char *oldq = q + 1;
q = 0;
/* On darwin9, we look for "foo" referenced from:\n\(.* in .*\n\)* */
if (strcmp (oldq, "referenced from:") == 0)
{
/* We have to remember that we found a symbol to tweak. */
ok = 1;
/* We actually want to start from the first word on the
line. */
oldq = p;
/* Since the format is multiline, we have to skip
following lines with " in ". */
skip_next_in_line = 1;
}
/* First try `GNU style'. */
p = strchr (oldq, '`');
if (p)
p++, q = strchr (p, '\'');
/* Then try "double quotes". */
else if (p = strchr (oldq, '"'), p)
p++, q = strchr (p, '"');
/* Then try 'single quotes'. */
else if (p = strchr (oldq, '\''), p)
p++, q = strchr (p, '\'');
else {
/* Then try entire line. */
q = strchr (oldq, 0);
if (q != oldq)
p = (char *)oldq;
}
if (p)
{
/* Don't let the strstr's below see the demangled name; we
might get spurious matches. */
p[-1] = '\0';
/* powerpc64-linux references .foo when calling function foo. */
if (*p == '.')
p++;
}
/* We need to check for certain error keywords here, or we would
mistakenly use GNU ld's "In function `foo':" message. */
if (q && (ok
|| strstr (oldq, "ndefined")
|| strstr (oldq, "nresolved")
|| strstr (oldq, "nsatisfied")
|| strstr (oldq, "ultiple")))
{
*q = 0;
dem = demangled_hash_lookup (p, false);
if (!dem)
{
if (!strncmp (p, USER_LABEL_PREFIX,
strlen (USER_LABEL_PREFIX)))
p += strlen (USER_LABEL_PREFIX);
sym = symbol_hash_lookup (p, false);
}
}
}
if (dem)
{
/* We found a demangled name. If this is the name of a
constructor or destructor, there can be several mangled names
that match it, so choose or unchoose all of them. If some are
chosen and some not, leave the later ones that don't match
alone for now; either this will cause the link to succeed, or
on the next attempt we will switch all of them the other way
and that will cause it to succeed. */
int chosen = 0;
int len = dem->mangled.length ();
ok = true;
FOR_EACH_VEC_ELT (dem->mangled, ix, s)
{
sym = symbol_hash_lookup (s, false);
if (ix == 0)
chosen = sym->chosen;
else if (sym->chosen != chosen)
/* Mismatch. */
continue;
/* Avoid an error about re-tweaking when we guess wrong in
the case of mismatch. */
if (len > 1)
sym->tweaked = false;
ok = start_tweaking (sym);
}
}
else
ok = start_tweaking (sym);
obstack_free (&temporary_obstack, temporary_firstobj);
if (!ok)
{
fclose (stream);
return 0;
}
}
fclose (stream);
return (file_stack != NULL);
}
/* Entry point for tlink. Called from main in collect2.c.
Iteratively try to provide definitions for all the unresolved symbols
mentioned in the linker error messages.
LD_ARGV is an array of arguments for the linker.
OBJECT_LST is an array of object files that we may be able to recompile
to provide missing definitions. Currently ignored. */
void
do_tlink (char **ld_argv, char **object_lst ATTRIBUTE_UNUSED)
{
int ret = tlink_execute ("ld", ld_argv, ldout, lderrout,
HAVE_GNU_LD && at_file_supplied);
tlink_init ();
if (ret)
{
int i = 0;
/* Until collect does a better job of figuring out which are object
files, assume that everything on the command line could be. */
if (read_repo_files (ld_argv))
while (ret && i++ < MAX_ITERATIONS)
{
if (tlink_verbose >= 3)
{
dump_ld_file (ldout, stdout);
dump_ld_file (lderrout, stderr);
}
demangle_new_symbols ();
if (! scan_linker_output (ldout)
&& ! scan_linker_output (lderrout))
break;
if (! recompile_files ())
break;
if (tlink_verbose)
fprintf (stderr, _("collect: relinking\n"));
ret = tlink_execute ("ld", ld_argv, ldout, lderrout,
HAVE_GNU_LD && at_file_supplied);
}
}
dump_ld_file (ldout, stdout);
unlink (ldout);
dump_ld_file (lderrout, stderr);
unlink (lderrout);
if (ret)
{
error ("ld returned %d exit status", ret);
exit (ret);
}
else
{
/* We have just successfully produced an output file, so assume that we
may unlink it if need be for now on. */
may_unlink_output_file = true;
}
}