This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

PATCH: Better -Woverloaded-virtual diagnostics


Hi,
Attached is a patch which gives better diagnostics for the -Woverloaded-virtual
warning flag. As I queried earlier
(http://egcs.cygnus.com/ml/egcs/1999-02/msg00178.html), the current behaviour
seems a little strange, and at variance with the documentation. Indeed, when I
investigated the code, I found that the order of derived class member functions
would affect whether you got a warning or not - not good! Here is such code
struct A
{
  virtual void foo(int);
  virtual void foo(double);
  virtual void baz(int);
  virtual void baz(double);
};

struct B : A
{
  void foo();
  void foo(int);
  void baz(int);
  void baz();
};

g++ reports
foo.cc:4: warning: `A::foo(double)' was hidden
foo.cc:12: warning:   by `B::foo(int)'

missing the identical hiding of baz! In this case I don't think it sensible to
warn any way, because one might well want to override a subset of virtual
functions -- what one doesn't want to do is introduce a new virtual function
that looks similar to a base virtual function.

So, here is a reimplementation of the warning. For each member function name in
a derrived class I build a list of all base class functions with the same name.
I do both virtual and non-virtual functions in base and derrived, 'cos I'm
looking for near hits where we might have assumed an implicit virtual on a
derrived function. So with these lists I knock out functions that are actually
overridden by the derrived class and then look for a 'near hit' between a base
and derrived function. If one is found, where at least one of the two functions
is virtual, I issue a diagnostic. A near hit is where it is possible to convert
the derrived argument list to the base argument parameter types via non-user
implicit conversions.

I modified testcase g++.mike/warn6.C, as that specifies what I consider a
spurious warning on D::both12diff(int). I attach a new testcase which should
probably go in as g++.other/warn4.C

The 19990307 snapshot gives the following g++ check
FAIL: g++.brendan/asm-extn1.C caused compiler crash

                === g++ Summary ===

# of expected passes            4925
# of unexpected failures        1
# of expected failures          82
# of untested testcases         7

With the patch and new test case I get,
FAIL: g++.brendan/asm-extn1.C caused compiler crash

                === g++ Summary ===

# of expected passes            4966
# of unexpected failures        1
# of expected failures          82
# of untested testcases         7

I.e. no additional failures

The patch includes updates to invoke.texi, to more accurately specify what the
warning is trying to tell you.

Enjoy,
nathan
-- 
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
      You can up the bandwidth, but you can't up the speed of light      
nathan@acm.org  http://www.cs.bris.ac.uk/~nathan/  nathan@cs.bris.ac.uk
egcs/gcc/cp/ChangeLog:
Mon Mar  8 17:28:49 GMT 1999  Nathan Sidwell  <nathan@acm.org>

	* class.c (nearly_overrides): New function.
	(get_basefndecls_inner): New function.
	(get_basefndecls): Changed arguments, mutually recurses to
	get_basefndecls_inner.
	(mark_overriders): Deleted.
	(warn_hidden): Renamed to ...
	(warn_nearly_overrides): ... here. Changed semantics to match
	what the documentation intended. Warn about derrived class
	functions which look like they were meant to override base class
	functions.
	(finish_struct_1): Adjust for new name.

egcs/gcc/ChangeLog:
Mon Mar  8 17:27:46 GMT 1999  Nathan Sidwell  <nathan@acm.org>

	* invoke.text (-Woverloaded-virtual): Update documentation so it
	matches new implementation.

Index: egcs/gcc/invoke.texi
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/invoke.texi,v
retrieving revision 1.96
diff -c -3 -p -r1.96 invoke.texi
*** invoke.texi	1999/02/28 01:05:37	1.96
--- invoke.texi	1999/03/08 17:50:01
*************** Warn if an old-style (C-style) cast is u
*** 1702,1714 ****
  @item -Woverloaded-virtual
  @cindex overloaded virtual fn, warning
  @cindex warning for overloaded virtual fn
! Warn when a derived class function declaration may be an error in
! defining a virtual function (C++ only).  In a derived class, the
! definitions of virtual functions must match the type signature of a
! virtual function declared in the base class.  With this option, the
! compiler warns when you define a function with the same name as a
! virtual function, but with a type signature that does not match any
! declarations from the base class.
  
  @item -Wsynth (C++ only)
  @cindex warning for synthesized methods
--- 1702,1727 ----
  @item -Woverloaded-virtual
  @cindex overloaded virtual fn, warning
  @cindex warning for overloaded virtual fn
! Warn when a derived class function declaration may be an erroneous
! attempt to override a base class virtual function.  In a derived class,
! the declarations of overriding virtual functions must match the type
! signature of a virtual function declared in a base class.  With this
! option, the compiler warns when you declare a function in a derived
! class which doesn't override a base class function, but it has the same
! name and similar type signature as a non-overridden base class
! function. Both virtual and non-virtual functions are considered, but at
! least one of the two functions under consideration has to be virtual.
! Considering non-virtual functions is necessary, as it is a common C++
! idiom to omit the @samp{virtual} specifier on an overriding virtual
! function. This warning will also catch the case where the derived
! function has an explicit @samp{virtual} specifier, but the
! corresponding base function is not virtual. G++ considers a derived
! class function parameter as being similar to a base class function
! parameter, if a standard conversion exists between them. This warning
! catches errors such as attempting to override @samp{virtual T
! A::operator=(A const &)} by @samp{T B::operator=(B const &)} (including
! an implicitly generated copy assignment operator), the correct
! overrider is @samp{T B::operator=(A const &)}.
  
  @item -Wsynth (C++ only)
  @cindex warning for synthesized methods
Index: egcs/gcc/cp/class.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/class.c,v
retrieving revision 1.134
diff -c -3 -p -r1.134 class.c
*** class.c	1999/03/03 11:24:37	1.134
--- class.c	1999/03/08 17:50:04
*************** static tree build_vbase_pointer PROTO((t
*** 96,102 ****
  static tree build_vtable_entry PROTO((tree, tree));
  static tree get_vtable_name PROTO((tree));
  static tree get_derived_offset PROTO((tree, tree));
! static tree get_basefndecls PROTO((tree, tree));
  static void set_rtti_entry PROTO((tree, tree, tree));
  static tree build_vtable PROTO((tree, tree));
  static void prepare_fresh_vtable PROTO((tree, tree));
--- 96,103 ----
  static tree build_vtable_entry PROTO((tree, tree));
  static tree get_vtable_name PROTO((tree));
  static tree get_derived_offset PROTO((tree, tree));
! static void get_basefndecls_inner PROTO((tree, tree, tree, tree, tree *, tree *));
! static void get_basefndecls PROTO((tree, tree, tree *, tree *));
  static void set_rtti_entry PROTO((tree, tree, tree));
  static tree build_vtable PROTO((tree, tree));
  static void prepare_fresh_vtable PROTO((tree, tree));
*************** static void finish_struct_bits PROTO((tr
*** 112,121 ****
  static int alter_access PROTO((tree, tree, tree, tree));
  static void handle_using_decl PROTO((tree, tree, tree, tree));
  static int overrides PROTO((tree, tree));
  static int strictly_overrides PROTO((tree, tree));
  static void merge_overrides PROTO((tree, tree, int, tree));
  static void override_one_vtable PROTO((tree, tree, tree));
- static void mark_overriders PROTO((tree, tree));
  static void check_for_override PROTO((tree, tree));
  static tree maybe_fixup_vptrs PROTO((tree, tree, tree));
  static tree get_class_offset_1 PROTO((tree, tree, tree, tree, tree));
--- 113,123 ----
  static int alter_access PROTO((tree, tree, tree, tree));
  static void handle_using_decl PROTO((tree, tree, tree, tree));
  static int overrides PROTO((tree, tree));
+ static int nearly_overrides PROTO((tree, tree));
  static int strictly_overrides PROTO((tree, tree));
+ static void warn_nearly_overrides PROTO((tree));
  static void merge_overrides PROTO((tree, tree, int, tree));
  static void override_one_vtable PROTO((tree, tree, tree));
  static void check_for_override PROTO((tree, tree));
  static tree maybe_fixup_vptrs PROTO((tree, tree, tree));
  static tree get_class_offset_1 PROTO((tree, tree, tree, tree, tree));
*************** overrides (fndecl, base_fndecl)
*** 2405,2410 ****
--- 2407,2442 ----
    return 0;
  }
  
+ /* True the given BASE_FNDECL is nearly overridden by FNDECL. 
+    Used for common error detection. */
+ 
+ static int
+ nearly_overrides (fndecl, base_fndecl)
+      tree fndecl, base_fndecl;
+ {
+   tree args, base_args;
+   
+   if (DECL_NAME (fndecl) != DECL_NAME (base_fndecl))
+     return 0;
+   
+   args = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
+   base_args = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (base_fndecl)));
+   
+   while (args || base_args)
+     {
+       tree arg_type = args ? TREE_VALUE (args) : NULL_TREE;
+       tree base_type = base_args ? TREE_VALUE (base_args) : NULL_TREE;
+       
+       if (arg_type != base_type 
+           && (!arg_type != !base_type
+               || !can_convert (base_type, arg_type)))
+         return 0;
+       args = TREE_CHAIN (args);
+       base_args = TREE_CHAIN (base_args);
+     }
+   return 1;
+ }
+ 
  static tree
  get_class_offset_1 (parent, binfo, context, t, fndecl)
       tree parent, binfo, context, t, fndecl;
*************** merge_overrides (binfo, old, do_self, t)
*** 2925,2983 ****
      }
  }
  
! /* Get the base virtual function declarations in T that are either
!    overridden or hidden by FNDECL as a list.  We set TREE_PURPOSE with
!    the overrider/hider.  */
  
! static tree
! get_basefndecls (fndecl, t)
!      tree fndecl, t;
  {
!   tree methods = TYPE_METHODS (t);
!   tree base_fndecls = NULL_TREE;
!   tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
!   int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
! 
!   while (methods)
      {
!       if (TREE_CODE (methods) == FUNCTION_DECL
! 	  && DECL_VINDEX (methods) != NULL_TREE
! 	  && DECL_NAME (fndecl) == DECL_NAME (methods))
! 	base_fndecls = temp_tree_cons (fndecl, methods, base_fndecls);
! 
!       methods = TREE_CHAIN (methods);
      }
! 
!   if (base_fndecls)
!     return base_fndecls;
! 
!   for (i = 0; i < n_baseclasses; i++)
      {
!       tree base_binfo = TREE_VEC_ELT (binfos, i);
!       tree basetype = BINFO_TYPE (base_binfo);
! 
!       base_fndecls = chainon (get_basefndecls (fndecl, basetype),
! 			      base_fndecls);
      }
- 
-   return base_fndecls;
  }
! 
! /* Mark the functions that have been hidden with their overriders.
!    Since we start out with all functions already marked with a hider,
!    no need to mark functions that are just hidden.  */
! 
  static void
! mark_overriders (fndecl, base_fndecls)
!      tree fndecl, base_fndecls;
  {
!   while (base_fndecls)
      {
!       if (overrides (TREE_VALUE (base_fndecls), fndecl))
! 	TREE_PURPOSE (base_fndecls) = fndecl;
! 
!       base_fndecls = TREE_CHAIN (base_fndecls);
      }
  }
  
  /* If this declaration supersedes the declaration of
--- 2957,3061 ----
      }
  }
  
! /* Get the function declarations in T that match FNNAME, separate into
!    VIRTUALS_OUT and NON_VIRTUALS_OUT. VIRTUALS_IN and NON_VIRTUALS_IN
!    are descendants of this class already discovered. We do not add
!    functions which are already overridden by these lists. */
  
! static void
! get_basefndecls_inner (fnname, t, virtuals_in, non_virtuals_in, virtuals_out, non_virtuals_out)
!       tree fnname, t;
!       tree virtuals_in, non_virtuals_in;
!       tree *virtuals_out, *non_virtuals_out;
  {
!   tree base_fndecls;
!   int i;
!   tree v = NULL_TREE, nv = NULL_TREE;
!   tree last_v = tree_last (virtuals_in);
!   tree last_nv = tree_last (non_virtuals_in);
! 
!   i = lookup_fnfields_1 (t, fnname);
!   for (base_fndecls = i < 0 ? NULL_TREE
!                             : TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (t), i);
!        base_fndecls; base_fndecls = OVL_NEXT (base_fndecls))
      {
!       tree fn = OVL_CURRENT (base_fndecls);
!       tree pos;
!       
!       if (DECL_VINDEX (fn))
!         {
!           for (pos = virtuals_in; pos; pos = TREE_CHAIN (pos))
!             if (overrides (TREE_PURPOSE (pos), fn))
!               break;
!           if (!pos)
!             v = scratch_tree_cons (fn, NULL_TREE, v);
!         }
!       else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
!         {
!           for (pos = non_virtuals_in; pos; pos = TREE_CHAIN (pos))
!             if (overrides (TREE_PURPOSE (pos), fn))
!               break;
!           if (!pos)
!             for (pos = virtuals_in; pos; pos = TREE_CHAIN (pos))
!               if (overrides (TREE_PURPOSE (pos), fn))
!                 break;
!           if (!pos)
!             nv = scratch_tree_cons (fn, NULL_TREE, nv);
!         }
!     }
!   /* Nconc these funcs onto the current list, so they are visible to our
!      parents. */
!   if (last_v)
!     TREE_CHAIN (last_v) = v;
!   else
!     virtuals_in = v;
!   if (last_nv)
!     TREE_CHAIN (last_nv) = nv;
!   else
!     non_virtuals_in = nv;
!   
!   get_basefndecls (fnname, t, &virtuals_in, &non_virtuals_in);
!   
!   *virtuals_out = virtuals_in;
!   *non_virtuals_out = non_virtuals_in;
!   /* Remove those at this level from the current list, so our
!      caller sees no change to the input parameters. */
!   if (last_v)
!     {
!       *virtuals_out = TREE_CHAIN (last_v);
!       TREE_CHAIN (last_v) = NULL_TREE;
      }
!   if (last_nv)
      {
!       *non_virtuals_out= TREE_CHAIN (last_nv);
!       TREE_CHAIN (last_nv) = NULL_TREE;
      }
  }
!   
  static void
! get_basefndecls (fnname, t, virtuals, non_virtuals)
!       tree fnname, t;
!       tree *virtuals, *non_virtuals;
  {
!   tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
!   int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
!   tree base_virtuals = NULL_TREE;
!   tree base_non_virtuals = NULL_TREE;
!   
!   for (i = 0; i < n_baseclasses; i++)
      {
!       tree base_binfo = TREE_VEC_ELT (binfos, i);
!       tree basetype = BINFO_TYPE (base_binfo);
!       tree v, nv;
!       
!       get_basefndecls_inner (fnname, basetype, *virtuals, *non_virtuals, &v, &nv);
!       base_virtuals = chainon (base_virtuals, v);
!       base_non_virtuals = chainon (base_non_virtuals, nv);
      }
+   *virtuals = chainon (*virtuals, base_virtuals);
+   *non_virtuals = chainon (*non_virtuals, base_non_virtuals);
+   
+   return;
  }
  
  /* If this declaration supersedes the declaration of
*************** check_for_override (decl, ctype)
*** 3043,3119 ****
      }
  }
  
! /* Warn about hidden virtual functions that are not overridden in t.
     We know that constructors and destructors don't apply.  */
  
! void
! warn_hidden (t)
       tree t;
  {
    tree method_vec = CLASSTYPE_METHOD_VEC (t);
    int n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0;
!   int i;
! 
    /* We go through each separately named virtual function.  */
!   for (i = 2; i < n_methods && TREE_VEC_ELT (method_vec, i); ++i)
!     {
!       tree fns = TREE_VEC_ELT (method_vec, i);
        tree fndecl;
! 
!       tree base_fndecls = NULL_TREE;
!       tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
!       int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
! 
!       fndecl = OVL_CURRENT (fns);
!       if (DECL_VINDEX (fndecl) == NULL_TREE)
! 	continue;
! 
!       /* First we get a list of all possible functions that might be
! 	 hidden from each base class.  */
!       for (i = 0; i < n_baseclasses; i++)
! 	{
! 	  tree base_binfo = TREE_VEC_ELT (binfos, i);
! 	  tree basetype = BINFO_TYPE (base_binfo);
! 
! 	  base_fndecls = chainon (get_basefndecls (fndecl, basetype),
! 				  base_fndecls);
! 	}
! 
!       fns = OVL_NEXT (fns);
!       if (fns)
! 	fndecl = OVL_CURRENT (fns);
!       else
! 	fndecl = NULL_TREE;
! 
!       /* ...then mark up all the base functions with overriders, preferring
! 	 overriders to hiders.  */
!       if (base_fndecls)
! 	while (fndecl)
! 	  {
! 	    mark_overriders (fndecl, base_fndecls);
! 	    
! 	    fns = OVL_NEXT (fns);
! 	    if (fns)
! 	      fndecl = OVL_CURRENT (fns);
! 	    else
! 	      fndecl = NULL_TREE;
! 	  }
! 
!       /* Now give a warning for all base functions without overriders,
! 	 as they are hidden.  */
!       while (base_fndecls)
! 	{
! 	  if (! overrides (TREE_VALUE (base_fndecls),
! 			   TREE_PURPOSE (base_fndecls)))
! 	    {
! 	      /* Here we know it is a hider, and no overrider exists.  */
! 	      cp_warning_at ("`%D' was hidden", TREE_VALUE (base_fndecls));
! 	      cp_warning_at ("  by `%D'", TREE_PURPOSE (base_fndecls));
! 	    }
! 
! 	  base_fndecls = TREE_CHAIN (base_fndecls);
! 	}
      }
  }
  
  /* Check for things that are invalid.  There are probably plenty of other
--- 3121,3238 ----
      }
  }
  
! /* Warn about virtual and non-virtual functions in T that look like they
!    are supposed to override a virtual in a base of T, but don't.
     We know that constructors and destructors don't apply.  */
  
! static void
! warn_nearly_overrides (t)
       tree t;
  {
    tree method_vec = CLASSTYPE_METHOD_VEC (t);
    int n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0;
!   int class_index;
!   
    /* We go through each separately named virtual function.  */
!   for (class_index = 2;
!       class_index < n_methods && TREE_VEC_ELT (method_vec, class_index);
!       class_index++)
!     {
!       tree fns = TREE_VEC_ELT (method_vec, class_index);
!       tree fnname = DECL_NAME (OVL_CURRENT (fns));
!       tree class_virtual_fns = NULL_TREE;
!       tree class_non_virtual_fns = NULL_TREE;
!       tree base_virtual_fns = NULL_TREE;
!       tree base_non_virtual_fns = NULL_TREE;
        tree fndecl;
!       tree prev;
!       
!       /* separate class members into virtual and non-virtual */
!       while (fns)
!         {
!           fndecl = OVL_CURRENT (fns);
!           if (DECL_VINDEX (fndecl))
!             class_virtual_fns =
!                 scratch_tree_cons (fndecl, NULL_TREE, class_virtual_fns);
!           else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl))
!             class_non_virtual_fns =
!                 scratch_tree_cons (fndecl, NULL_TREE, class_non_virtual_fns);
!           fns = OVL_NEXT (fns);
!         }
!       if (!class_virtual_fns && !class_non_virtual_fns)
!         continue;
!       
!       /* Get a list of all possible functions that might be
! 	 hidden from each base class. */
!       get_basefndecls (fnname, t, &base_virtual_fns, &base_non_virtual_fns);
!       if (!class_virtual_fns && !base_virtual_fns)
!         continue;
!       
!       /* Remove virtuals which override/are overridden. */
!       for (prev = NULL, fns = class_virtual_fns; fns;)
!         {
!           tree next = TREE_CHAIN (fns);
!           tree probe, lookat;
!           
!           for (probe = NULL, lookat = base_virtual_fns; lookat;)
!             {
!               tree probe_next = TREE_CHAIN (lookat);
!               
!               if (overrides (TREE_PURPOSE (fns), TREE_PURPOSE (lookat)))
!                 {
!                   if (probe)
!                     TREE_CHAIN (probe) = probe_next;
!                   else
!                     base_virtual_fns = probe_next;
!                   if (prev)
!                     TREE_CHAIN (prev) = next;
!                   else
!                     class_virtual_fns = next;
!                   goto break2;
!                 }
!               probe = lookat;
!               lookat = probe_next;
!             }
!           prev = fns;
!           break2:
!           fns = next;
!         }
!       if (!class_virtual_fns && !class_non_virtual_fns)
!         continue;
!       
!       /* At this point, we've got some unaccounted virtual or non-virtual
!          functions. Concatenate the virtual and non_virtual lists, then
!          look for near matches where at least one function is virtual. */
!       class_virtual_fns = chainon (class_virtual_fns, class_non_virtual_fns);
!       base_virtual_fns = chainon (base_virtual_fns, base_non_virtual_fns);
!       
!       for (fns = class_virtual_fns; fns; fns = TREE_CHAIN (fns))
!         {
!           tree probe;
!           tree fn = TREE_PURPOSE (fns);
!           int once = 0;
!           
!           for (probe = base_virtual_fns; probe; probe = TREE_CHAIN (probe))
!             {
!               tree base_fn = TREE_PURPOSE (probe);
!               
!               if ((DECL_VINDEX (fn) || DECL_VINDEX (base_fn))
!                   && nearly_overrides (fn, base_fn))
!                 {
!                   if (!once++)
!                     cp_warning_at (DECL_VINDEX (fn)
!                                    ? "`virtual %+#D' looks similar to"
!                                    : "non-virtual `%+#D' looks similar to",
!                                    fn);
!                   cp_warning_at (DECL_VINDEX (base_fn)
!                                  ? "  `virtual %+#D', but is not the same"
!                                  : "  non-virtual `%+#D', but cannot override it",
!                                  base_fn);
!                 }
!             }
!         }
      }
+   return;
  }
  
  /* Check for things that are invalid.  There are probably plenty of other
*************** finish_struct_1 (t, warn_anon)
*** 4279,4285 ****
    resume_momentary (old);
  
    if (warn_overloaded_virtual)
!     warn_hidden (t);
  
  #if 0
    /* This has to be done after we have sorted out what to do with
--- 4398,4404 ----
    resume_momentary (old);
  
    if (warn_overloaded_virtual)
!     warn_nearly_overrides (t);
  
  #if 0
    /* This has to be done after we have sorted out what to do with
Index: egcs/gcc/testsuite/g++.old-deja/g++.mike/warn6.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.mike/warn6.C,v
retrieving revision 1.2
diff -c -3 -p -r1.2 warn6.C
*** warn6.C	1998/12/16 21:49:35	1.2
--- warn6.C	1999/03/08 17:50:04
*************** struct B {
*** 22,28 ****
    virtual void both2same(float);
  
    virtual void both12diff(int);
!   virtual void both12diff(float);	// WARNING - was hidden
  };
  
  struct D : public B, public B2, public B3 {
--- 22,28 ----
    virtual void both2same(float);
  
    virtual void both12diff(int);
!   virtual void both12diff(float);	// ok, 
  };
  
  struct D : public B, public B2, public B3 {
*************** struct D : public B, public B2, public B
*** 35,41 ****
    virtual void both2same(int);
    virtual void both2same(float);
  
!   virtual void both12diff(int);		// WARNING - 
  
    virtual void bothfardiff(int);	// WARNING - 
  };
--- 35,41 ----
    virtual void both2same(int);
    virtual void both2same(float);
  
!   virtual void both12diff(int);
  
    virtual void bothfardiff(int);	// WARNING - 
  };
// Build don't link:
// Special g++ Options: -Woverloaded-virtual

// Copyright (C) 1999 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 28 Feb 1999 <nathan@acm.org>

// check -Woverloaded-virtual catches the dubious cases and leaves sensible
// ones alone.

struct AA
{
  virtual int f();
  virtual int f(int);       // WARNING - previous declaration
  virtual int g();
  virtual int g(int);       // WARNING - previous declaration
  virtual AA &operator=(AA const &);       // WARNING - previous declaration
};

struct CC
{
  virtual int q(int);       // WARNING - previous declaration
  virtual int f(int);       // WARNING - previous declaration
};

struct BB : public AA, public CC
{
  virtual int f();
  int f(float);      // WARNING - nearly matches
  int g(float);      // WARNING - nearly matches
  virtual int g();
  virtual int q(float);// WARNING - nearly matches
};// WARNING - nearly matches (operator=)

struct BBB : public AA
{
  AA &operator=(AA const &);  // ok
};

struct CCC : public BB
{
  virtual int f(double);  // WARNING - nearly matches
  int f(float);      // WARNING - nearly matches
  int g(double);      // WARNING - nearly matches
}; // WARNING - nearly matches

struct DD : public AA, public CC
{
  int f(float);      // WARNING - nearly matches
}; // WARNING - nearly matches

struct DDD : public DD
{
  virtual int f(float);       // WARNING - nearly matches
  virtual int f(double);      // WARNING - nearly matches
}; // WARNING - nearly matches

struct X; struct Y;
struct A
{
  virtual int foo(A); // WARNING - previous declaration
  virtual int bar(A);
  int baz(A);         // WARNING - previous declaration
  int quux(A);        // WARNING - previous declaration
  virtual int toto(A);// WARNING - previous declaration
  
  virtual int fooPtr(A *); // WARNING - previous declaration
  virtual int barPtr(A *);
  int bazPtr(A *);         // WARNING - previous declaration
  int quuxPtr(A *);        // WARNING - previous declaration
  virtual int totoPtr(A *);// WARNING - previous declaration
  
  virtual int fooRef(A &); // WARNING - previous declaration
  virtual int barRef(A &);
  int bazRef(A &);         // WARNING - previous declaration
  int quuxRef(A &);        // WARNING - previous declaration
  virtual int totoRef(A &);// WARNING - previous declaration

  virtual int func(A *);
  virtual int func(X *);
  
  virtual int fooX(X);
  virtual int barX(X);
  int bazX(X);        
  int quuxX(X);       
  virtual int totoX(X);
  
  virtual int fooPtrX(X *);
  virtual int barPtrX(X *);
  int bazPtrX(X *);        
  int quuxPtrX(X *);        
  virtual int totoPtrX(X *);
  
  virtual int fooRefX(X &); 
  virtual int barRefX(X &);
  int bazRefX(X &);         
  int quuxRefX(X &);        
  virtual int totoRefX(X &);
};

struct B : public A
{
  virtual int foo(B); // WARNING - not overriding
  virtual int bar(A); // ok
  virtual int bar(B); // ok, base overridden too
  virtual int baz(A); // WARNING - not overriding (base is not virtual)
  virtual int quux(B); // WARNING - not overriding
  int toto(B);         // WARNING - not overriding
  
  virtual int fooPtr(B *); // WARNING - not overriding
  virtual int barPtr(A *); // ok
  virtual int barPtr(B *); // ok, base overridden too
  virtual int bazPtr(A *); // WARNING - not overriding Ptr(base is not virtual)
  virtual int quuxPtr(B *); // WARNING - not overriding
  int totoPtr(B *);         // WARNING - not overriding
  
  virtual int fooRef(B &); // WARNING - not overriding
  virtual int barRef(A &); // ok
  virtual int barRef(B &); // ok, base overridden too
  virtual int bazRef(A &); // WARNING - not overriding Ref(base is not virtual)
  virtual int quuxRef(B &); // WARNING - not overriding
  int totoRef(B &);         // WARNING - not overriding
  
  virtual int func(A *);
  
  // no warnings on these, X and Y are unrelated
  virtual int fooX(Y); 
  virtual int barX(Y);
  int bazX(Y);         
  int quuxX(Y);        
  virtual int totoX(Y);
  
  virtual int fooPtrX(Y *); 
  virtual int barPtrX(Y *);
  int bazPtrX(Y *);         
  int quuxPtrX(Y *);        
  virtual int totoPtrX(Y *);
  
  virtual int fooRefX(Y &); 
  virtual int barRefX(Y &);
  int bazRefX(Y &);         
  int quuxRefX(Y &);        
  virtual int totoRefX(Y &);
};

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]