mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-24 03:14:08 +08:00
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:
parent
ebd247d4b3
commit
67f6e64994
@ -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>
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -332,8 +332,6 @@ cxx_init (void)
|
||||
|
||||
init_cp_pragma ();
|
||||
|
||||
init_repo ();
|
||||
|
||||
input_location = saved_loc;
|
||||
return true;
|
||||
}
|
||||
|
@ -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. */
|
||||
|
18
gcc/cp/pt.c
18
gcc/cp/pt.c
@ -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;
|
||||
|
374
gcc/cp/repo.c
374
gcc/cp/repo.c
@ -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"
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
// { dg-options "-frepo" }
|
||||
// { dg-require-host-local "" }
|
||||
|
||||
extern "C" inline void f() {}
|
||||
|
||||
int main () {
|
||||
f();
|
||||
}
|
||||
|
||||
// { dg-final { cleanup-repo-files } }
|
@ -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 } }
|
@ -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 } }
|
@ -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;
|
||||
}
|
@ -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); }
|
@ -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 } }
|
@ -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 } }
|
@ -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());
|
||||
}
|
@ -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 () {}
|
@ -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();
|
||||
}
|
@ -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 ()
|
||||
{
|
||||
}
|
@ -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 ()
|
||||
{
|
||||
}
|
@ -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');
|
||||
}
|
@ -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 } }
|
@ -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 } }
|
@ -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 } }
|
@ -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 } }
|
@ -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 } }
|
@ -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 } }
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
867
gcc/tlink.c
867
gcc/tlink.c
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user