@@ -3243,10 +3243,15 @@ warn_hidden (tree t)
continue;
tree name = OVL_NAME (fns);
+ size_t num_fns = 0; /* The number of fndecls in fns. */
auto_vec<tree, 20> base_fndecls;
tree base_binfo;
tree binfo;
unsigned j;
+ hash_set<tree> overriden_base_fndecls, overrider_fndecls;
+ /* base_fndecls that are hidden but not overriden. The "value"
+ contains a vector of fndecls that hide the "key". */
+ hash_map<tree, auto_vec<tree> > hidden_base_fndecls;
if (IDENTIFIER_CDTOR_P (name))
continue;
@@ -3264,47 +3269,69 @@ warn_hidden (tree t)
if (base_fndecls.is_empty ())
continue;
- /* Remove any overridden functions. */
- bool seen_non_override = false;
+ /* Find all the base_fndecls that are overridden, as well as those
+ that are hidden, in T. */
for (tree fndecl : ovl_range (fns))
{
- bool any_override = false;
- if (TREE_CODE (fndecl) == FUNCTION_DECL
- && DECL_VINDEX (fndecl))
+ fndecl = STRIP_TEMPLATE (fndecl);
+ if (TREE_CODE (fndecl) != FUNCTION_DECL
+ || fndecl == conv_op_marker)
+ continue;
+ num_fns++;
+ for (size_t k = 0; k < base_fndecls.length (); k++)
{
- /* If the method from the base class has the same
- signature as the method from the derived class, it
- has been overridden. Note that we can't move on
- after finding one match: fndecl might override
- multiple base fns. */
- for (size_t k = 0; k < base_fndecls.length (); k++)
- if (base_fndecls[k]
- && same_signature_p (fndecl, base_fndecls[k]))
- {
- base_fndecls[k] = NULL_TREE;
- any_override = true;
- }
+ if (!base_fndecls[k] || !DECL_VINDEX (base_fndecls[k]))
+ continue;
+ if (IDENTIFIER_CONV_OP_P (name)
+ && !same_type_p (DECL_CONV_FN_TYPE (fndecl),
+ DECL_CONV_FN_TYPE (base_fndecls[k])))
+ /* If base_fndecl[k] and fndecl are conversion operators
+ to different types, they're unrelated. */
+ ;
+ else if (same_signature_p (fndecl, base_fndecls[k])
+ && overrides_p (fndecl, base_fndecls[k]))
+ {
+ /* We cannot simply compare DECL_VINDEX (it won't work if
+ there's multiple inheritance, or single inheritance with
+ bases with bases), so we determine whether fndecl
+ overrides base_fndecls[k] by first comparing the
+ signatures and if they match, using the more expensive
+ is_overrider function. */
+ overriden_base_fndecls.add (base_fndecls[k]);
+ overrider_fndecls.add (fndecl);
+ }
+ else
+ {
+ /* fndecls hides base_fndecls[k]. */
+ auto_vec<tree> &hiders =
+ hidden_base_fndecls.get_or_insert (base_fndecls[k]);
+ if (!hiders.contains (fndecl))
+ hiders.safe_push (fndecl);
+ }
}
- if (!any_override)
- seen_non_override = true;
}
- if (!seen_non_override && warn_overloaded_virtual == 1)
- /* All the derived fns override base virtuals. */
- return;
+ if (warn_overloaded_virtual == 1
+ && overrider_fndecls.elements () == num_fns)
+ /* All the fns override a base virtual. */
+ continue;
- /* Now give a warning for all base functions without overriders,
- as they are hidden. */
- for (tree base_fndecl : base_fndecls)
- if (base_fndecl)
- {
- auto_diagnostic_group d;
- /* Here we know it is a hider, and no overrider exists. */
- if (warning_at (location_of (base_fndecl),
- OPT_Woverloaded_virtual_,
- "%qD was hidden", base_fndecl))
- inform (location_of (fns), " by %qD", fns);
- }
+ /* Now give a warning for all hidden methods. Note that a method that
+ is both in hidden_base_fndecls and overriden_base_fndecls is not
+ hidden. */
+ for (auto hidden_base_fndecl : hidden_base_fndecls)
+ {
+ tree hidden_fndecl = hidden_base_fndecl.first;
+ if (!hidden_fndecl
+ || overriden_base_fndecls.contains (hidden_fndecl))
+ continue;
+ auto_diagnostic_group d;
+ if (warning_at (location_of (hidden_fndecl),
+ OPT_Woverloaded_virtual_,
+ "%qD was hidden", hidden_fndecl))
+ for (auto h : hidden_base_fndecl.second)
+ inform (location_of (h), " by %qD", h);
+ }
}
}
@@ -7744,6 +7744,7 @@ extern tree type_context_for_name_lookup (tree);
extern tree lookup_conversions (tree);
extern tree binfo_from_vbase (tree);
extern tree binfo_for_vbase (tree, tree);
+extern bool overrides_p (tree, tree);
extern tree look_for_overrides_here (tree, tree);
#define dfs_skip_bases ((tree)1)
extern tree dfs_walk_all (tree, tree (*) (tree, void *),
@@ -3397,7 +3397,8 @@ location_of (tree t)
return input_location;
}
else if (TREE_CODE (t) == OVERLOAD)
- t = OVL_FIRST (t);
+ t = OVL_FIRST (t) != conv_op_marker ? OVL_FIRST (t)
+ : OVL_FIRST (OVL_CHAIN (t));
if (DECL_P (t))
return DECL_SOURCE_LOCATION (t);
@@ -2014,10 +2014,12 @@ maybe_check_overriding_exception_spec (tree overrider, tree basefn)
}
/* Check that virtual overrider OVERRIDER is acceptable for base function
- BASEFN. Issue diagnostic, and return zero, if unacceptable. */
+ BASEFN. Issue diagnostic if COMPLAIN & TF_ERROR, and return zero, if
+ unacceptable. */
static int
-check_final_overrider (tree overrider, tree basefn)
+check_final_overrider (tree overrider, tree basefn,
+ tsubst_flags_t complain = tf_error)
{
tree over_type = TREE_TYPE (overrider);
tree base_type = TREE_TYPE (basefn);
@@ -2080,8 +2082,10 @@ check_final_overrider (tree overrider, tree basefn)
converting to void *, or qualification conversion. */
{
auto_diagnostic_group d;
- if (pedwarn (DECL_SOURCE_LOCATION (overrider), 0,
- "invalid covariant return type for %q#D", overrider))
+ if ((complain & tf_error)
+ && pedwarn (DECL_SOURCE_LOCATION (overrider), 0,
+ "invalid covariant return type for %q#D",
+ overrider))
inform (DECL_SOURCE_LOCATION (basefn),
"overridden function is %q#D", basefn);
}
@@ -2095,6 +2099,8 @@ check_final_overrider (tree overrider, tree basefn)
else
{
auto_diagnostic_group d;
+ if (!(complain & tf_error))
+ return 0;
if (fail == 1)
error ("invalid covariant return type for %q+#D", overrider);
else
@@ -2114,6 +2120,8 @@ check_final_overrider (tree overrider, tree basefn)
&& !tx_safe_fn_type_p (base_type)
&& !tx_safe_fn_type_p (over_type))
{
+ if (!(complain & tf_error))
+ return 0;
auto_diagnostic_group d;
error ("conflicting type attributes specified for %q+#D", overrider);
inform (DECL_SOURCE_LOCATION (basefn),
@@ -2128,6 +2136,8 @@ check_final_overrider (tree overrider, tree basefn)
if (DECL_IMMEDIATE_FUNCTION_P (overrider)
!= DECL_IMMEDIATE_FUNCTION_P (basefn))
{
+ if (!(complain & tf_error))
+ return 0;
auto_diagnostic_group d;
if (DECL_IMMEDIATE_FUNCTION_P (overrider))
error ("%<consteval%> function %q+D overriding non-%<consteval%> "
@@ -2148,7 +2158,8 @@ check_final_overrider (tree overrider, tree basefn)
&& lookup_attribute ("transaction_safe_dynamic",
DECL_ATTRIBUTES (overrider))
&& !lookup_attribute ("transaction_safe_dynamic",
- DECL_ATTRIBUTES (basefn)))
+ DECL_ATTRIBUTES (basefn))
+ && (complain & tf_error))
{
auto_diagnostic_group d;
error_at (DECL_SOURCE_LOCATION (overrider),
@@ -2159,6 +2170,8 @@ check_final_overrider (tree overrider, tree basefn)
if (DECL_DELETED_FN (basefn) != DECL_DELETED_FN (overrider))
{
+ if (!(complain & tf_error))
+ return 0;
if (DECL_DELETED_FN (overrider))
{
auto_diagnostic_group d;
@@ -2181,6 +2194,8 @@ check_final_overrider (tree overrider, tree basefn)
if (!DECL_HAS_CONTRACTS_P (basefn) && DECL_HAS_CONTRACTS_P (overrider))
{
+ if (!(complain & tf_error))
+ return 0;
auto_diagnostic_group d;
error ("function with contracts %q+D overriding contractless function",
overrider);
@@ -2207,6 +2222,8 @@ check_final_overrider (tree overrider, tree basefn)
if (DECL_FINAL_P (basefn))
{
+ if (!(complain & tf_error))
+ return 0;
auto_diagnostic_group d;
error ("virtual function %q+D overriding final function", overrider);
inform (DECL_SOURCE_LOCATION (basefn),
@@ -2216,6 +2233,15 @@ check_final_overrider (tree overrider, tree basefn)
return 1;
}
+/* Check whether FN is a valid overrider for base function BASEFN. Note that
+ no diagnostic is emitted if FN is not a valid overrider. */
+
+bool
+overrides_p (tree fn, tree basefn)
+{
+ return check_final_overrider (fn, basefn, /*complain=*/tf_none);
+}
+
/* Given a class TYPE, and a function decl FNDECL, look for
virtual functions in TYPE's hierarchy which FNDECL overrides.
We do not look in TYPE itself, only its bases.
@@ -5,10 +5,12 @@ class Foo
{
public:
virtual void f(int); // { dg-warning "hidden" }
+ void g(int); // Not virtual, so no warning
};
class Bar : public Foo
{
public:
virtual void f(short); // { dg-message "by" }
+ virtual void g(short);
};
new file mode 100644
@@ -0,0 +1,11 @@
+// PR c++/117114 - Test case from PR c++/117114
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -Woverloaded-virtual }
+
+struct Troops { virtual ~Troops(); };
+struct Control { virtual int GetControl() const = 0; };
+struct Army : Troops, Control { int GetControl() const override; };
+
+struct VirtualControl : virtual Control {
+ int GetControl() const override;
+};
new file mode 100644
@@ -0,0 +1,25 @@
+// PR c++/109918 - More tests with multiple inheritance
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -Woverloaded-virtual }
+
+struct Troops { virtual ~Troops(); };
+struct Control {
+ virtual int GetControl() const { return 42; } // { dg-warning "was hidden" }
+};
+struct Army : Troops, Control {
+ template<class T> void GetControl() const; // { dg-message "by" }
+};
+
+
+struct A {
+ virtual void get() const;
+};
+struct B {
+ virtual void get() const;
+ virtual void get(char) const; // { dg-warning "was hidden" }
+};
+
+struct C : A, B {
+ virtual void get() const; // { dg-message "by" }
+ virtual void get(int) const; // { dg-message "by" }
+};
new file mode 100644
@@ -0,0 +1,23 @@
+// PR c++/109918 - Test covariant return types
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -Woverloaded-virtual }
+
+struct Big { virtual ~Big () {} };
+struct Smaller : Big {};
+
+// Single inheritance case
+struct Foo {
+ virtual Big* getMe() const;
+};
+struct Bar : Foo {
+ virtual Smaller* getMe() const;
+};
+
+// Multiple inheritance case
+struct Troops { virtual ~Troops(); };
+struct Control {
+ virtual Big* GetControl() const;
+};
+struct Army : Troops, Control {
+ virtual Smaller* GetControl() const;
+};
new file mode 100644
@@ -0,0 +1,28 @@
+// PR c++/117114 - Reduced version of another bootstrap error
+// Unrelated methods can have the same DECL_VINDEX when the class hierarchy
+// depth is 2 or more.
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -Woverloaded-virtual }
+
+class HIRFullVisitor;
+class HIRTypeVisitor;
+
+struct FullVisitable {
+ virtual void accept_vis (HIRFullVisitor &vis) = 0;
+};
+
+struct Node {
+ virtual ~Node() {}
+};
+
+struct Type : Node, FullVisitable
+{
+ using FullVisitable::accept_vis;
+ virtual void accept_vis (HIRTypeVisitor &vis) = 0;
+};
+
+struct TypePath : Type
+{
+ void accept_vis (HIRFullVisitor &vis) override;
+ void accept_vis (HIRTypeVisitor &vis) override;
+};
new file mode 100644
@@ -0,0 +1,12 @@
+// PR c++/109918 - Exact PR testcase
+// { dg-do compile }
+// { dg-additional-options -Wall }
+
+struct A {
+ virtual operator int() { return 42; }
+ virtual operator char() = 0;
+};
+
+struct B : public A {
+ operator char() { return 'A'; }
+};
new file mode 100644
@@ -0,0 +1,12 @@
+// PR c++/109918 - PR testcase with -Woverloaded-virtual=2
+// { dg-do compile }
+// { dg-additional-options -Woverloaded-virtual=2 }
+
+struct A {
+ virtual operator int() { return 42; }
+ virtual operator char() = 0;
+};
+
+struct B : public A {
+ operator char() { return 'A'; }
+};
new file mode 100644
@@ -0,0 +1,31 @@
+// PR c++/109918 - Test different CV-quals and usage of typedefs
+// { dg-do compile }
+// { dg-additional-options -Woverloaded-virtual }
+
+struct A {
+ virtual operator char() { return 'a'; }
+ virtual operator char() const { return 'b'; } // { dg-warning "was hidden" }
+ virtual operator int() { return 42; }
+};
+
+struct B : public A {
+ operator char() { return 'A'; } // { dg-note "by" }
+ operator int() { return 43; }
+};
+
+typedef char MyChar;
+struct C : public A {
+ operator MyChar() { return 'A'; } // { dg-note "by" }
+ operator int() { return 43; }
+};
+
+struct AA {
+ virtual char func(char) { return 'a'; }
+ virtual char func(char) const { return 'b'; } // { dg-warning "was hidden" }
+ virtual int func(int) { return 42; }
+};
+
+struct BB : public AA {
+ char func(char) { return 'A'; } // { dg-note "by" }
+ int func(int) { return 43; } // { dg-note "by" }
+};
new file mode 100644
@@ -0,0 +1,15 @@
+// Identified when investigating PR c++/109918: no warning was emitted due to
+// an incorrect early return in warn_hidden.
+// { dg-additional-options -Wall }
+
+struct Foo
+{
+ virtual void f(int); // { dg-warning "hidden" }
+ virtual void g() {}
+};
+
+struct Bar : Foo
+{
+ virtual void f(short); // { dg-message "by" }
+ virtual void g() {}
+};
new file mode 100644
@@ -0,0 +1,14 @@
+// PR c++/109918: Non virtual overloads in derived classes that don't override
+// anything shouldn't cause warnings, even at -Woverloaded-virtual=2
+// { dg-additional-options -Woverloaded-virtual=2 }
+
+struct Foo
+{
+ virtual void g() {}
+};
+
+struct Bar : Foo
+{
+ virtual void g() {}
+ void g(int) {}
+};