summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2014-09-10 14:27:40 +0000
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2014-09-10 14:27:40 +0000
commit6b518f5b22a8153d00a2e2b31b82947349ee5c8b (patch)
tree96f3fc7a188437ecb05ef06bc87b6a6767c15e32
parentf0d4f158f3ec3eabd68d6923ca6db1ed5f1a7084 (diff)
downloadppe42-gcc-6b518f5b22a8153d00a2e2b31b82947349ee5c8b.tar.gz
ppe42-gcc-6b518f5b22a8153d00a2e2b31b82947349ee5c8b.zip
PR lto/53808
PR c++/61659 * decl2.c (note_comdat_fn): New. (set_comdat): New. (cp_write_global_declarations): Call set_comdat. * method.c (implicitly_declare_fn): Call note_comdat_fn. * pt.c (tsubst_decl) [FUNCTION_DECL]: Likewise. * decl2.c (mark_needed): Mark clones. (import_export_decl): Not here. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_9-branch@215131 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/cp/ChangeLog10
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/decl2.c54
-rw-r--r--gcc/cp/method.c1
-rw-r--r--gcc/cp/pt.c3
-rw-r--r--gcc/testsuite/g++.dg/abi/no-weak1.C13
-rw-r--r--gcc/testsuite/g++.dg/abi/spec1.C4
-rw-r--r--gcc/testsuite/g++.dg/opt/devirt4.C7
-rw-r--r--gcc/testsuite/g++.dg/opt/devirt5.C19
-rw-r--r--gcc/testsuite/g++.dg/template/friend56.C13
-rw-r--r--gcc/testsuite/g++.dg/template/spec38.C6
11 files changed, 116 insertions, 15 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 5c750b9e441..18ae4f22bcd 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,15 @@
2014-09-09 Jason Merrill <jason@redhat.com>
+ PR lto/53808
+ PR c++/61659
+ * decl2.c (note_comdat_fn): New.
+ (set_comdat): New.
+ (cp_write_global_declarations): Call set_comdat.
+ * method.c (implicitly_declare_fn): Call note_comdat_fn.
+ * pt.c (tsubst_decl) [FUNCTION_DECL]: Likewise.
+ * decl2.c (mark_needed): Mark clones.
+ (import_export_decl): Not here.
+
PR c++/61214
PR c++/62224
* decl2.c (decl_needed_p): Revert virtual functions change.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0b52dff3fdb..99cc7ec64c6 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5352,6 +5352,7 @@ extern tree get_tls_wrapper_fn (tree);
extern void mark_needed (tree);
extern bool decl_needed_p (tree);
extern void note_vague_linkage_fn (tree);
+extern void note_comdat_fn (tree);
extern tree build_artificial_parm (tree, tree);
extern bool possibly_inlined_p (tree);
extern int parm_index (tree);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 6c52e53bca0..a2626d4c77b 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -99,6 +99,10 @@ static GTY(()) vec<tree, va_gc> *pending_statics;
may need to emit outline anyway. */
static GTY(()) vec<tree, va_gc> *deferred_fns;
+/* A list of functions which we might want to set DECL_COMDAT on at EOF. */
+
+static GTY(()) vec<tree, va_gc> *maybe_comdat_fns;
+
/* A list of decls that use types with no linkage, which we need to make
sure are defined. */
static GTY(()) vec<tree, va_gc> *no_linkage_decls;
@@ -1896,6 +1900,12 @@ mark_needed (tree decl)
definition. */
struct cgraph_node *node = cgraph_get_create_node (decl);
node->forced_by_abi = true;
+
+ /* #pragma interface and -frepo code can call mark_needed for
+ maybe-in-charge 'tors; mark the clones as well. */
+ tree clone;
+ FOR_EACH_CLONE (clone, decl)
+ mark_needed (clone);
}
else if (TREE_CODE (decl) == VAR_DECL)
{
@@ -2678,17 +2688,7 @@ import_export_decl (tree decl)
{
/* The repository indicates that this entity should be defined
here. Make sure the back end honors that request. */
- if (VAR_P (decl))
- mark_needed (decl);
- else if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
- || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
- {
- tree clone;
- FOR_EACH_CLONE (clone, decl)
- mark_needed (clone);
- }
- else
- mark_needed (decl);
+ mark_needed (decl);
/* Output the definition as an ordinary strong definition. */
DECL_EXTERNAL (decl) = 0;
DECL_INTERFACE_KNOWN (decl) = 1;
@@ -4231,6 +4231,34 @@ dump_tu (void)
}
}
+/* Much like the above, but not necessarily defined. 4.9 hack for setting
+ DECL_COMDAT on DECL_EXTERNAL functions, along with set_comdat. */
+
+void
+note_comdat_fn (tree decl)
+{
+ vec_safe_push (maybe_comdat_fns, decl);
+}
+
+/* DECL is a function with vague linkage that was not
+ instantiated/synthesized in this translation unit. Set DECL_COMDAT for
+ the benefit of can_refer_decl_in_current_unit_p. */
+
+static void
+set_comdat (tree decl)
+{
+ DECL_COMDAT (decl) = true;
+
+ tree clone;
+ FOR_EACH_CLONE (clone, decl)
+ set_comdat (clone);
+
+ if (DECL_VIRTUAL_P (decl))
+ for (tree thunk = DECL_THUNKS (decl); thunk;
+ thunk = DECL_CHAIN (thunk))
+ DECL_COMDAT (thunk) = true;
+}
+
/* This routine is called at the end of compilation.
Its job is to create all the code needed to initialize and
destroy the global aggregates. We do the destruction
@@ -4608,6 +4636,10 @@ cp_write_global_declarations (void)
vtv_build_vtable_verify_fndecl ();
}
+ FOR_EACH_VEC_SAFE_ELT (maybe_comdat_fns, i, decl)
+ if (!DECL_COMDAT (decl) && vague_linkage_p (decl))
+ set_comdat (decl);
+
finalize_compilation_unit ();
if (flag_vtable_verify)
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 11bff7f4587..b074d7471ed 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1773,6 +1773,7 @@ implicitly_declare_fn (special_function_kind kind, tree type,
DECL_EXTERNAL (fn) = true;
DECL_NOT_REALLY_EXTERN (fn) = 1;
DECL_DECLARED_INLINE_P (fn) = 1;
+ note_comdat_fn (fn);
gcc_assert (!TREE_USED (fn));
/* Restore PROCESSING_TEMPLATE_DECL. */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3296fda4734..91ff32acb26 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10677,6 +10677,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
the type earlier (template/friend54.C). */
RETURN (new_r);
+ if (!DECL_FRIEND_P (r))
+ note_comdat_fn (r);
+
/* We're not supposed to instantiate default arguments
until they are called, for a template. But, for a
declaration like:
diff --git a/gcc/testsuite/g++.dg/abi/no-weak1.C b/gcc/testsuite/g++.dg/abi/no-weak1.C
new file mode 100644
index 00000000000..d539015312f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/no-weak1.C
@@ -0,0 +1,13 @@
+// { dg-options "-fno-weak" }
+// { dg-final { scan-assembler "local\[ \t\]*_ZZL1fvE1i" { target x86_64-*-*gnu } } }
+
+static inline void f()
+{
+ static int i;
+ ++i;
+};
+
+int main()
+{
+ f();
+}
diff --git a/gcc/testsuite/g++.dg/abi/spec1.C b/gcc/testsuite/g++.dg/abi/spec1.C
new file mode 100644
index 00000000000..153c0cfe7f0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/spec1.C
@@ -0,0 +1,4 @@
+// { dg-final { scan-assembler-not "weak" } }
+
+template <class T> struct A { static int i; };
+template<> int A<int>::i = 42;
diff --git a/gcc/testsuite/g++.dg/opt/devirt4.C b/gcc/testsuite/g++.dg/opt/devirt4.C
index 5a24eecbd0a..72f56afcadc 100644
--- a/gcc/testsuite/g++.dg/opt/devirt4.C
+++ b/gcc/testsuite/g++.dg/opt/devirt4.C
@@ -1,8 +1,7 @@
// PR lto/53808
-// Devirtualization + inlining should produce a non-virtual
-// call to ~foo.
-// { dg-options "-O -fdevirtualize" }
-// { dg-final { scan-assembler "_ZN3fooD2Ev" } }
+// Devirtualization should not produce an external ref to ~bar.
+// { dg-options "-O2" }
+// { dg-final { scan-assembler-not "_ZN3barD0Ev" } }
struct foo {
virtual ~foo();
diff --git a/gcc/testsuite/g++.dg/opt/devirt5.C b/gcc/testsuite/g++.dg/opt/devirt5.C
new file mode 100644
index 00000000000..f839cbeae20
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/devirt5.C
@@ -0,0 +1,19 @@
+// PR c++/61659
+// { dg-options "-O3" }
+// { dg-final { scan-assembler-not "_ZN6parserIiE9getOptionEv" } }
+
+struct generic_parser_base {
+ virtual void getOption();
+ void getExtraOptionNames() { getOption(); }
+};
+template <class DataType> struct parser : public generic_parser_base {
+ virtual void getOption() {}
+};
+struct PassNameParser : public parser<int> {
+ PassNameParser();
+};
+struct list {
+ PassNameParser Parser;
+ virtual void getExtraOptionNames() { return Parser.getExtraOptionNames(); }
+};
+list PassList;
diff --git a/gcc/testsuite/g++.dg/template/friend56.C b/gcc/testsuite/g++.dg/template/friend56.C
new file mode 100644
index 00000000000..7dd5d486f86
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend56.C
@@ -0,0 +1,13 @@
+// Make sure we don't mistakenly mark f as DECL_COMDAT.
+// { dg-final { scan-assembler "_Z1fv" } }
+
+void f();
+
+template <class T> struct A
+{
+ friend void f();
+};
+
+A<int> a;
+
+void f() { }
diff --git a/gcc/testsuite/g++.dg/template/spec38.C b/gcc/testsuite/g++.dg/template/spec38.C
new file mode 100644
index 00000000000..6f06f149584
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/spec38.C
@@ -0,0 +1,6 @@
+// PR ipa/61659
+
+// { dg-final { scan-assembler "_Z1fIiEvPT_" } }
+
+template <typename T> inline void f (T *);
+template <> void f (int *) { }
OpenPOWER on IntegriCloud