diff mbox

C++ PATCH for c++/61659 (undefined symbol with devirtualization)

Message ID 53B1C69C.8000409@redhat.com
State New
Headers show

Commit Message

Jason Merrill June 30, 2014, 8:20 p.m. UTC
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.

Comments

Andreas Schwab July 1, 2014, 9:45 a.m. UTC | #1
Jason Merrill <jason@redhat.com> writes:

>     libstdc++-v3/
>     	* libsupc++/cxxabi.h (class __pbase_type_info): __pointer_catch
>     	is pure, not inline.

I'm getting this ABI change, is that OK?

-FUNC:_ZNK10__cxxabiv117__pbase_type_info15__pointer_catchEPKS0_PPvj@@CXXABI_1.3

Andreas.
Jason Merrill July 1, 2014, 10:38 p.m. UTC | #2
On 07/01/2014 02:45 AM, Andreas Schwab wrote:
> I'm getting this ABI change, is that OK?
>
> -FUNC:_ZNK10__cxxabiv117__pbase_type_info15__pointer_catchEPKS0_PPvj@@CXXABI_1.3

Hmm, probably not, thanks.

Jason
diff mbox

Patch

commit 3019e719de4a7d5972b0057c7da6bb40b198d3ab
Author: Jason Merrill <jason@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.