When we're devirtualizing, we need to make sure that any virtual
functions are synthesized or instantiated even if the vtable isn't going
to be emitted. My earlier patches for 53808 handled this for
synthesized destructors, but the issue is more general.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 3019e719de4a7d5972b0057c7da6bb40b198d3ab
Author: Jason Merrill <ja...@redhat.com>
Date: Mon Jun 30 14:39:17 2014 -0400
PR c++/61659
PR lto/53808
gcc/cp
* decl2.c (maybe_emit_vtables): Mark all vtable entries if
devirtualizing.
* init.c (build_vtbl_address): Don't mark destructor.
* class.c (finish_struct_1): Add all classes to keyed_classes
if devirtualizing.
libstdc++-v3/
* libsupc++/cxxabi.h (class __pbase_type_info): __pointer_catch
is pure, not inline.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index d3bc71e..1c28dd6 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6405,8 +6405,10 @@ finish_struct_1 (tree t)
determine_key_method (t);
/* If a polymorphic class has no key method, we may emit the vtable
- in every translation unit where the class definition appears. */
- if (CLASSTYPE_KEY_METHOD (t) == NULL_TREE)
+ in every translation unit where the class definition appears. If
+ we're devirtualizing, we can look into the vtable even if we
+ aren't emitting it. */
+ if (CLASSTYPE_KEY_METHOD (t) == NULL_TREE || flag_devirtualize)
keyed_classes = tree_cons (NULL_TREE, t, keyed_classes);
}
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 99ea582..98897f4 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -2009,6 +2009,11 @@ maybe_emit_vtables (tree ctype)
if (DECL_COMDAT (primary_vtbl)
&& CLASSTYPE_DEBUG_REQUESTED (ctype))
note_debug_info_needed (ctype);
+ if (flag_devirtualize)
+ /* Make sure virtual functions get instantiated/synthesized so that
+ they can be inlined after devirtualization even if the vtable is
+ never emitted. */
+ mark_vtable_entries (primary_vtbl);
return false;
}
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 8edf519..f8cae28 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1155,12 +1155,6 @@ build_vtbl_address (tree binfo)
/* Figure out what vtable BINFO's vtable is based on, and mark it as
used. */
vtbl = get_vtbl_decl_for_binfo (binfo_for);
- if (tree dtor = CLASSTYPE_DESTRUCTORS (DECL_CONTEXT (vtbl)))
- if (!TREE_USED (vtbl) && DECL_VIRTUAL_P (dtor) && DECL_DEFAULTED_FN (dtor))
- /* Make sure the destructor gets synthesized so that it can be
- inlined after devirtualization even if the vtable is never
- emitted. */
- note_vague_linkage_fn (dtor);
TREE_USED (vtbl) = true;
/* Now compute the address to use when initializing the vptr. */
diff --git a/gcc/testsuite/g++.dg/opt/devirt5.C b/gcc/testsuite/g++.dg/opt/devirt5.C
new file mode 100644
index 0000000..f839cbe
--- /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/libstdc++-v3/libsupc++/cxxabi.h b/libstdc++-v3/libsupc++/cxxabi.h
index ab87321..5b77aee 100644
--- a/libstdc++-v3/libsupc++/cxxabi.h
+++ b/libstdc++-v3/libsupc++/cxxabi.h
@@ -298,9 +298,9 @@ namespace __cxxabiv1
__do_catch(const std::type_info* __thr_type, void** __thr_obj,
unsigned int __outer) const;
- inline virtual bool
+ virtual bool
__pointer_catch(const __pbase_type_info* __thr_type, void** __thr_obj,
- unsigned __outer) const;
+ unsigned __outer) const = 0;
};
// Type information for simple pointers.