@@ -3080,6 +3080,79 @@ warn_hidden (tree t)
}
}
+/* Warn about non-static fields name hiding. */
+
+static void
+warn_name_hiding (tree t)
+{
+ if (is_empty_class (t) || CLASSTYPE_NEARLY_EMPTY_P (t))
+ return;
+
+ for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+ {
+ /* Skip if field is not an user-defined non-static data member. */
+ if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
+ continue;
+
+ unsigned j;
+ tree name = DECL_NAME (field);
+ /* Skip if field is anonymous. */
+ if (!name || !identifier_p (name))
+ continue;
+
+ auto_vec<tree> base_vardecls;
+ tree binfo;
+ tree base_binfo;
+ /* Iterate through all of the base classes looking for possibly
+ shadowed non-static data members. */
+ for (binfo = TYPE_BINFO (t), j = 0;
+ BINFO_BASE_ITERATE (binfo, j, base_binfo); j++)
+ {
+ tree basetype = BINFO_TYPE (base_binfo);
+ tree candidate = lookup_field (basetype, name,
+ /* protect */ 2,
+ /* want_type */ 0,
+ /* once_suffices */ true);
+ if (candidate)
+ {
+ /* If we went up the hierarchy to a base class with multiple
+ inheritance, there could be multiple matches in which case
+ a TREE_LIST is returned. */
+ if (TREE_TYPE (candidate) == error_mark_node)
+ {
+ for (; candidate; candidate = TREE_CHAIN (candidate))
+ {
+ tree candidate_field = TREE_VALUE (candidate);
+ tree candidate_klass = DECL_CONTEXT (candidate_field);
+ if (accessible_base_p (t, candidate_klass, true))
+ base_vardecls.safe_push (candidate_field);
+ }
+ }
+ else if (accessible_base_p (t, DECL_CONTEXT (candidate), true))
+ base_vardecls.safe_push (candidate);
+ }
+ }
+
+ /* Field was not found among the base classes. */
+ if (base_vardecls.is_empty ())
+ continue;
+
+ /* Emit a warning for each field similarly named found
+ in the base class hierarchy. */
+ for (tree base_vardecl : base_vardecls)
+ {
+ if (base_vardecl)
+ {
+ auto_diagnostic_group d;
+ if (warning_at (location_of (field), OPT_Wshadow,
+ "%qD might shadow %qD", field, base_vardecl))
+ inform (location_of (base_vardecl),
+ " %qD name already in use here", base_vardecl);
+ }
+ }
+ }
+}
+
/* Recursive helper for finish_struct_anon. */
static void
@@ -7654,6 +7727,8 @@ finish_struct_1 (tree t)
if (warn_overloaded_virtual)
warn_hidden (t);
+ if (warn_shadow)
+ warn_name_hiding (t);
/* Class layout, assignment of virtual table slots, etc., is now
complete. Give the back end a chance to tweak the visibility of
@@ -7554,11 +7554,13 @@ extern tree lookup_base (tree, tree, base_access,
extern tree dcast_base_hint (tree, tree);
extern int accessible_p (tree, tree, bool);
extern int accessible_in_template_p (tree, tree);
-extern tree lookup_field (tree, tree, int, bool);
+extern tree lookup_field (tree, tree, int, bool,
+ bool once_suffices = false);
extern tree lookup_fnfields (tree, tree, int, tsubst_flags_t);
extern tree lookup_member (tree, tree, int, bool,
tsubst_flags_t,
- access_failure_info *afi = NULL);
+ access_failure_info *afi = NULL,
+ bool once_suffices = false);
extern tree lookup_member_fuzzy (tree, tree, bool);
extern tree locate_field_accessor (tree, tree, bool);
extern int look_for_overrides (tree, tree);
@@ -7577,7 +7579,8 @@ extern tree binfo_for_vbase (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 *),
- tree (*) (tree, void *), void *);
+ tree (*) (tree, void *), void *,
+ bool stop_on_success = false);
extern tree dfs_walk_once (tree, tree (*) (tree, void *),
tree (*) (tree, void *), void *);
extern tree binfo_via_virtual (tree, tree);
@@ -1145,13 +1145,19 @@ build_baselink (tree binfo, tree access_binfo, tree functions, tree optype)
WANT_TYPE is 1 when we should only return TYPE_DECLs.
+ ONCE_SUFFICES is 1 when we should return upon first find of
+ the member in a branch of the inheritance hierarchy tree, rather
+ than collect all similarly named members further in that branch.
+ Does not impede other parallel branches of the tree.
+
If nothing can be found return NULL_TREE and do not issue an error.
If non-NULL, failure information is written back to AFI. */
tree
lookup_member (tree xbasetype, tree name, int protect, bool want_type,
- tsubst_flags_t complain, access_failure_info *afi /* = NULL */)
+ tsubst_flags_t complain, access_failure_info *afi /* = NULL */,
+ bool once_suffices /* = false */)
{
tree rval, rval_binfo = NULL_TREE;
tree type = NULL_TREE, basetype_path = NULL_TREE;
@@ -1202,7 +1208,7 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type,
lfi.type = type;
lfi.name = name;
lfi.want_type = want_type;
- dfs_walk_all (basetype_path, &lookup_field_r, NULL, &lfi);
+ dfs_walk_all (basetype_path, &lookup_field_r, NULL, &lfi, once_suffices);
rval = lfi.rval;
rval_binfo = lfi.rval_binfo;
if (rval_binfo)
@@ -1392,10 +1398,12 @@ lookup_member_fuzzy (tree xbasetype, tree name, bool want_type_p)
return NULL_TREE. */
tree
-lookup_field (tree xbasetype, tree name, int protect, bool want_type)
+lookup_field (tree xbasetype, tree name, int protect, bool want_type,
+ bool once_suffices /* = false */)
{
tree rval = lookup_member (xbasetype, name, protect, want_type,
- tf_warning_or_error);
+ tf_warning_or_error, /* afi */ NULL,
+ once_suffices);
/* Ignore functions, but propagate the ambiguity list. */
if (!error_operand_p (rval)
@@ -1480,11 +1488,14 @@ adjust_result_of_qualified_name_lookup (tree decl,
of PRE_FN and POST_FN can be NULL. At each node, PRE_FN and
POST_FN are passed the binfo to examine and the caller's DATA
value. All paths are walked, thus virtual and morally virtual
- binfos can be multiply walked. */
+ binfos can be multiply walked.
+ If STOP_ON_SUCCESS is 1, do not walk deeper the current hierarchy
+ tree once PRE_FN returns non-NULL. */
tree
dfs_walk_all (tree binfo, tree (*pre_fn) (tree, void *),
- tree (*post_fn) (tree, void *), void *data)
+ tree (*post_fn) (tree, void *), void *data,
+ bool stop_on_success /* = false */)
{
tree rval;
unsigned ix;
@@ -1496,7 +1507,7 @@ dfs_walk_all (tree binfo, tree (*pre_fn) (tree, void *),
rval = pre_fn (binfo, data);
if (rval)
{
- if (rval == dfs_skip_bases)
+ if (rval == dfs_skip_bases || stop_on_success)
goto skip_bases;
return rval;
}
@@ -1505,7 +1516,8 @@ dfs_walk_all (tree binfo, tree (*pre_fn) (tree, void *),
/* Find the next child binfo to walk. */
for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
{
- rval = dfs_walk_all (base_binfo, pre_fn, post_fn, data);
+ rval = dfs_walk_all (base_binfo, pre_fn, post_fn,
+ data, stop_on_success);
if (rval)
return rval;
}
new file mode 100644
@@ -0,0 +1,65 @@
+// PR c++/12341
+/* { dg-do compile } */
+/* { dg-additional-options "-Wshadow" } */
+
+class A {
+protected:
+ int aaa; /* { dg-line A_def_aaa } */
+};
+
+// Check simple inheritance is checked for.
+class B : public A {
+public:
+ int aaa; /* { dg-line B_shadowing_aaa } */
+ /* { dg-warning "'B::aaa' might shadow 'A::aaa'" "" { target *-*-* } .-1 } */
+ /* { dg-note "'A::aaa' name already in use here" "" { target *-*-* } A_def_aaa } */
+private:
+ int bbb; /* { dg-line B_def_bbb } */
+ int eee; /* { dg-line B_def_eee } */
+};
+
+// Check that visibility of base classes's fields is of no concern.
+class C : public B {
+public:
+ int bbb; /* { dg-warning "'C::bbb' might shadow 'B::bbb'" } */
+ /* { dg-note "'B::bbb' name already in use here" "" { target *-*-* } B_def_bbb } */
+};
+
+class D {
+protected:
+ int bbb; /* { dg-line D_def_bbb } */
+ int ddd; /* { dg-line D_def_ddd } */
+};
+
+class E : protected D {
+private:
+ int eee; /* { dg-line E_def_eee } */
+};
+
+// all first-level base classes must be considered.
+class Bi : protected B, public E {
+protected:
+ /* Check that we stop on first ambiguous match,
+ that we don't walk the hierarchy deeper. */
+ int aaa; /* { dg_bogus "'Bi::aaa' might shadow 'A::aaa'" } */
+ /* { dg-warning "'Bi::aaa' might shadow 'B::aaa'" "" { target *-*-* } .-1 } */
+ /* { dg-note "'B::aaa' name already in use here" "" { target *-*-* } B_shadowing_aaa } */
+
+ // All branches of a multiple inheritance tree must be explored.
+ int bbb; /* { dg-warning "'Bi::bbb' might shadow 'D::bbb'" } */
+ /* { dg-note "'D::bbb' name already in use here" "" { target *-*-* } D_def_bbb } */
+ /* { dg-warning "'Bi::bbb' might shadow 'B::bbb'" "" { target *-*-* } .-2 } */
+
+ // Must continue beyond the immediate parent, even in the case of multiple inheritance.
+ int ddd; /* { dg-warning "'Bi::ddd' might shadow 'D::ddd'" } */
+ /* { dg-note "'D::ddd' name already in use here" "" { target *-*-* } D_def_ddd } */
+};
+
+class BiD : public Bi {
+ /* If the base class does not cause a warning,
+ then look into each base classes of the parent's multiple inheritance */
+ int eee; /* { dg-warning "'BiD::eee' might shadow 'B::eee'" } */
+ /* { dg-note "'B::eee' name already in use here" "" { target *-*-* } B_def_eee } */
+ /* { dg-warning "'BiD::eee' might shadow 'E::eee'" "" { target *-*-* } .-2 } */
+ /* { dg-note "'E::eee' name already in use here" "" { target *-*-* } E_def_eee } */
+};
new file mode 100644
@@ -0,0 +1,34 @@
+// PR c++/12341 test anonymous bit field
+/* { dg-do compile } */
+/* { dg-additional-options "-Wshadow" } */
+
+class B {
+protected:
+ unsigned int x : 5;
+ unsigned int : 2;
+ unsigned int y : 1;
+
+ union {
+ float uuu;
+ double vvv;
+ };
+};
+
+// Check that anonymous bit fields do not cause spurious warnings
+class D : private B {
+protected:
+ unsigned int x : 4; /* { dg-warning "'D::x' might shadow 'B::x'" } */
+ unsigned int : 4; // If test for excess errors fails, it might be from here.
+ int uuu; /* { dg-warning "'D::uuu' might shadow 'B::<unnamed union>::uuu'" } */
+};
+
+class E : public D {
+public:
+ /* Do not warn if inheritance is not visible to the class,
+ as there is no risk even with polymorphism to mistake the fields. */
+ unsigned int y; /* { dg-bogus "'E::y' might shadow 'B::y'" } */
+ unsigned int vvv; /* { dg-bogus "'E::vvv' might shadow 'B::<unnamed union>::vvv'" } */
+
+ // Do warn even if the type differs. Should be trivial, still test for it.
+ double x; /* { dg-warning "'E::x' might shadow 'D::x'" } */
+};