> My earlier patch for 61659 caused more virtual functions to be
> instantiated when -fdevirtualize is on, leading to additional errors
> appearing at higher optimization levels.  This patch shifts that
> instantiation to a new flag, -fuse-all-virtuals, which is on by
> default, and adds an explanatory note to help people understand why
> their code is breaking and how they can work around it if needed.
> 
> Tested x86_64-pc-linux-gnu, applying to trunk.

> commit 82187fb06863161765a270f8ba00bdbf975b3af2
> Author: Jason Merrill <ja...@redhat.com>
> Date:   Mon Jul 7 03:15:02 2014 -0700
> 
>       PR c++/61659
>       PR c++/61687
>     gcc/c-family/
>       * c.opt (-fuse-all-virtuals): New.
>     gcc/cp/
>       * decl2.c (mark_all_virtuals): New variable.
>       (maybe_emit_vtables): Check it instead of flag_devirtualize.
>       (cp_write_global_declarations): Set it and give helpful diagnostic
>       if it introduces errors.
>       * class.c (finish_struct_1): Check it.
>       * decl.c (grokdeclarator): Clear virtualp after 'virtual auto' error.

Given my experience about numbers of functions that become reachable when you 
stream all virtuals into LTO,
I wonder if we don't want to use possible_polymorphic_call_targets within the 
front-end to avoid instantiating
those that can't be called?
I think it should not be too hard - all we need is to populate the type 
inheritance graph from FE and then
for each polymorphic call produce the list to mark possible targets are 
reachable.

Honza
> 
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index faef774..3a2084f 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -1268,6 +1268,10 @@ funsigned-char
>  C ObjC C++ ObjC++ LTO Var(flag_signed_char, 0)
>  Make \"char\" unsigned by default
>  
> +fuse-all-virtuals
> +C++ ObjC++ Var(flag_use_all_virtuals) Init(1)
> +Treat all virtual functions as odr-used
> +
>  fuse-cxa-atexit
>  C++ ObjC++ Var(flag_use_cxa_atexit) Init(DEFAULT_USE_CXA_ATEXIT)
>  Use __cxa_atexit to register destructors
> diff --git a/gcc/cp/class.c b/gcc/cp/class.c
> index 3a44dba..d0eb103 100644
> --- a/gcc/cp/class.c
> +++ b/gcc/cp/class.c
> @@ -6408,7 +6408,7 @@ finish_struct_1 (tree t)
>        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)
> +      if (CLASSTYPE_KEY_METHOD (t) == NULL_TREE || flag_use_all_virtuals)
>       keyed_classes = tree_cons (NULL_TREE, t, keyed_classes);
>      }
>  
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index 1ade586..01d74e3 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -9631,8 +9631,11 @@ grokdeclarator (const cp_declarator *declarator,
>                                   "-std=gnu++1y");
>                         }
>                       else if (virtualp)
> -                       error ("virtual function cannot "
> -                              "have deduced return type");
> +                       {
> +                         error ("virtual function cannot "
> +                                "have deduced return type");
> +                         virtualp = false;
> +                       }
>                     }
>                   else if (!is_auto (type))
>                     {
> diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
> index 98897f4..0926dbc 100644
> --- a/gcc/cp/decl2.c
> +++ b/gcc/cp/decl2.c
> @@ -106,6 +106,11 @@ static GTY(()) vec<tree, va_gc> *no_linkage_decls;
>  /* Nonzero if we're done parsing and into end-of-file activities.  */
>  
>  int at_eof;
> +
> +/* Nonzero if we've instantiated everything used directly, and now want to
> +   mark all virtual functions as used so that they are available for
> +   devirtualization.  */
> +static int mark_all_virtuals;
>  
>  
>  /* Return a member function type (a METHOD_TYPE), given FNTYPE (a
> @@ -2009,7 +2014,7 @@ maybe_emit_vtables (tree ctype)
>        if (DECL_COMDAT (primary_vtbl)
>         && CLASSTYPE_DEBUG_REQUESTED (ctype))
>       note_debug_info_needed (ctype);
> -      if (flag_devirtualize)
> +      if (mark_all_virtuals)
>       /* Make sure virtual functions get instantiated/synthesized so that
>          they can be inlined after devirtualization even if the vtable is
>          never emitted.  */
> @@ -4340,6 +4345,8 @@ cp_write_global_declarations (void)
>       instantiated, etc., etc.  */
>  
>    emit_support_tinfos ();
> +  int errs = errorcount + sorrycount;
> +  bool explained_devirt = false;
>  
>    do
>      {
> @@ -4572,6 +4579,27 @@ cp_write_global_declarations (void)
>                                        pending_statics->length ()))
>       reconsider = true;
>  
> +      if (flag_use_all_virtuals)
> +     {
> +       if (!reconsider && !mark_all_virtuals)
> +         {
> +           mark_all_virtuals = true;
> +           reconsider = true;
> +           errs = errorcount + sorrycount;
> +         }
> +       else if (mark_all_virtuals
> +                && !explained_devirt
> +                && (errorcount + sorrycount > errs))
> +         {
> +           inform (global_dc->last_location, "this error is seen due to "
> +                   "instantiation of all virtual functions, which the C++ "
> +                   "standard says are always considered used; this is done "
> +                   "to support devirtualization optimizations, but can be "
> +                   "disabled with -fno-use-all-virtuals");
> +           explained_devirt = true;
> +         }
> +     }
> +
>        retries++;
>      }
>    while (reconsider);
> diff --git a/gcc/testsuite/g++.dg/template/dtor9.C 
> b/gcc/testsuite/g++.dg/template/dtor9.C
> index fd71389..006a754 100644
> --- a/gcc/testsuite/g++.dg/template/dtor9.C
> +++ b/gcc/testsuite/g++.dg/template/dtor9.C
> @@ -1,4 +1,5 @@
>  // PR c++/60347
> +// { dg-options "-fno-use-all-virtuals" }
>  
>  struct A;
>  
> diff --git a/gcc/testsuite/g++.dg/template/dtor9a.C 
> b/gcc/testsuite/g++.dg/template/dtor9a.C
> new file mode 100644
> index 0000000..aaae8b6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/dtor9a.C
> @@ -0,0 +1,13 @@
> +// PR c++/60347
> +// { dg-options "-fuse-all-virtuals" }
> +
> +struct A;
> +
> +template <class T>
> +struct B
> +{
> +  T* p;
> +  virtual ~B() { p->~T(); }  // { dg-error "incomplete" }
> +};
> +
> +struct C: B<A> { };

Reply via email to