aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2015-08-19 21:45:49 -0400
committerJason Merrill <jason@gcc.gnu.org>2015-08-19 21:45:49 -0400
commit7ac2c0bd17900b3c0e078479b46de64563a16c9f (patch)
treeb65582f3511b73960f319ef3ff55d38d73013c57 /gcc
parent18c4fa8ef0c5e3d705be8f50860b3e58be672256 (diff)
downloadgcc-7ac2c0bd17900b3c0e078479b46de64563a16c9f.zip
gcc-7ac2c0bd17900b3c0e078479b46de64563a16c9f.tar.gz
gcc-7ac2c0bd17900b3c0e078479b46de64563a16c9f.tar.bz2
re PR c++/66957 (incorrect "is protected within this context" error)
PR c++/66957 * search.c (protected_accessible_p): Remove redundant access_in_type. Add otype parm instead of walking binfo. (friend_accessible_p): Check SCOPE itself. Handle class templates. Pass through otype. (dfs_accessible_post): Handle all accessibility cases. (dfs_accessible_pre): New. (accessible_p): Use it. Don't check protected access here. Pass decl and otype to dfs_walk. (member_declared_in_type, dfs_access_in_type_pre): New. (access_in_type): Use dfs_access_in_type_pre. * friend.c (add_friend): Fix multiple friends with the same name. From-SVN: r227023
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog13
-rw-r--r--gcc/cp/friend.c11
-rw-r--r--gcc/cp/search.c228
-rw-r--r--gcc/testsuite/g++.dg/inherit/access9.C14
4 files changed, 180 insertions, 86 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 155f86a..2a083c8 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,18 @@
2015-08-19 Jason Merrill <jason@redhat.com>
+ PR c++/66957
+ * search.c (protected_accessible_p): Remove redundant access_in_type.
+ Add otype parm instead of walking binfo.
+ (friend_accessible_p): Check SCOPE itself. Handle class
+ templates. Pass through otype.
+ (dfs_accessible_post): Handle all accessibility cases.
+ (dfs_accessible_pre): New.
+ (accessible_p): Use it. Don't check protected access here. Pass
+ decl and otype to dfs_walk.
+ (member_declared_in_type, dfs_access_in_type_pre): New.
+ (access_in_type): Use dfs_access_in_type_pre.
+ * friend.c (add_friend): Fix multiple friends with the same name.
+
* lambda.c (current_nonlambda_scope): New.
2015-08-18 Trevor Saunders <tbsaunde@tbsaunde.org>
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index e107cee..f53ce27 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -156,11 +156,9 @@ add_friend (tree type, tree decl, bool complain)
}
}
- maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1);
-
TREE_VALUE (list) = tree_cons (NULL_TREE, decl,
TREE_VALUE (list));
- return;
+ break;
}
list = TREE_CHAIN (list);
}
@@ -172,9 +170,10 @@ add_friend (tree type, tree decl, bool complain)
maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1);
- DECL_FRIENDLIST (typedecl)
- = tree_cons (DECL_NAME (decl), build_tree_list (NULL_TREE, decl),
- DECL_FRIENDLIST (typedecl));
+ if (!list)
+ DECL_FRIENDLIST (typedecl)
+ = tree_cons (DECL_NAME (decl), build_tree_list (NULL_TREE, decl),
+ DECL_FRIENDLIST (typedecl));
if (!uses_template_parms (type))
DECL_BEFRIENDING_CLASSES (decl)
= tree_cons (NULL_TREE, type,
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 90cd243..42db122 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -58,8 +58,6 @@ static tree dfs_walk_once_accessible (tree, bool,
void *data);
static tree dfs_access_in_type (tree, void *);
static access_kind access_in_type (tree, tree);
-static int protected_accessible_p (tree, tree, tree);
-static int friend_accessible_p (tree, tree, tree);
static tree dfs_get_pure_virtuals (tree, void *);
@@ -582,9 +580,36 @@ context_for_name_lookup (tree decl)
return context;
}
+/* Returns true iff DECL is declared in TYPE. */
+
+static bool
+member_declared_in_type (tree decl, tree type)
+{
+ /* A normal declaration obviously counts. */
+ if (context_for_name_lookup (decl) == type)
+ return true;
+ /* So does a using or access declaration. */
+ if (DECL_LANG_SPECIFIC (decl) && !DECL_DISCRIMINATOR_P (decl)
+ && purpose_member (type, DECL_ACCESS (decl)))
+ return true;
+ return false;
+}
+
/* The accessibility routines use BINFO_ACCESS for scratch space
during the computation of the accessibility of some declaration. */
+/* Avoid walking up past a declaration of the member. */
+
+static tree
+dfs_access_in_type_pre (tree binfo, void *data)
+{
+ tree decl = (tree) data;
+ tree type = BINFO_TYPE (binfo);
+ if (member_declared_in_type (decl, type))
+ return dfs_skip_bases;
+ return NULL_TREE;
+}
+
#define BINFO_ACCESS(NODE) \
((access_kind) ((TREE_PUBLIC (NODE) << 1) | TREE_PRIVATE (NODE)))
@@ -705,19 +730,17 @@ access_in_type (tree type, tree decl)
The algorithm we use is to make a post-order depth-first traversal
of the base-class hierarchy. As we come up the tree, we annotate
each node with the most lenient access. */
- dfs_walk_once (binfo, NULL, dfs_access_in_type, decl);
+ dfs_walk_once (binfo, dfs_access_in_type_pre, dfs_access_in_type, decl);
return BINFO_ACCESS (binfo);
}
-/* Returns nonzero if it is OK to access DECL through an object
- indicated by BINFO in the context of DERIVED. */
+/* Returns nonzero if it is OK to access DECL named in TYPE through an object
+ of OTYPE in the context of DERIVED. */
static int
-protected_accessible_p (tree decl, tree derived, tree binfo)
+protected_accessible_p (tree decl, tree derived, tree type, tree otype)
{
- access_kind access;
-
/* We're checking this clause from [class.access.base]
m as a member of N is protected, and the reference occurs in a
@@ -725,16 +748,10 @@ protected_accessible_p (tree decl, tree derived, tree binfo)
class P derived from N, where m as a member of P is public, private
or protected.
- Here DERIVED is a possible P, DECL is m and BINFO_TYPE (binfo) is N. */
+ Here DERIVED is a possible P, DECL is m and TYPE is N. */
/* If DERIVED isn't derived from N, then it can't be a P. */
- if (!DERIVED_FROM_P (BINFO_TYPE (binfo), derived))
- return 0;
-
- access = access_in_type (derived, decl);
-
- /* If m is inaccessible in DERIVED, then it's not a P. */
- if (access == ak_none)
+ if (!DERIVED_FROM_P (type, derived))
return 0;
/* [class.protected]
@@ -748,33 +765,38 @@ protected_accessible_p (tree decl, tree derived, tree binfo)
derived from that class) (_expr.ref_). If the access is to form
a pointer to member, the nested-name-specifier shall name the
derived class (or any class derived from that class). */
- if (DECL_NONSTATIC_MEMBER_P (decl))
- {
- /* We can tell through what the reference is occurring by
- chasing BINFO up to the root. */
- tree t = binfo;
- while (BINFO_INHERITANCE_CHAIN (t))
- t = BINFO_INHERITANCE_CHAIN (t);
-
- if (!DERIVED_FROM_P (derived, BINFO_TYPE (t)))
- return 0;
- }
+ if (DECL_NONSTATIC_MEMBER_P (decl)
+ && !DERIVED_FROM_P (derived, otype))
+ return 0;
return 1;
}
-/* Returns nonzero if SCOPE is a friend of a type which would be able
- to access DECL through the object indicated by BINFO. */
+/* Returns nonzero if SCOPE is a type or a friend of a type which would be able
+ to access DECL through TYPE. OTYPE is the type of the object. */
static int
-friend_accessible_p (tree scope, tree decl, tree binfo)
+friend_accessible_p (tree scope, tree decl, tree type, tree otype)
{
+ /* We're checking this clause from [class.access.base]
+
+ m as a member of N is protected, and the reference occurs in a
+ member or friend of class N, or in a member or friend of a
+ class P derived from N, where m as a member of P is public, private
+ or protected.
+
+ Here DECL is m and TYPE is N. SCOPE is the current context,
+ and we check all its possible Ps. */
tree befriending_classes;
tree t;
if (!scope)
return 0;
+ /* Is SCOPE itself a suitable P? */
+ if (TYPE_P (scope) && protected_accessible_p (decl, scope, type, otype))
+ return 1;
+
if (DECL_DECLARES_FUNCTION_P (scope))
befriending_classes = DECL_BEFRIENDING_CLASSES (scope);
else if (TYPE_P (scope))
@@ -783,54 +805,113 @@ friend_accessible_p (tree scope, tree decl, tree binfo)
return 0;
for (t = befriending_classes; t; t = TREE_CHAIN (t))
- if (protected_accessible_p (decl, TREE_VALUE (t), binfo))
+ if (protected_accessible_p (decl, TREE_VALUE (t), type, otype))
return 1;
/* Nested classes have the same access as their enclosing types, as
- per DR 45 (this is a change from the standard). */
+ per DR 45 (this is a change from C++98). */
if (TYPE_P (scope))
- for (t = TYPE_CONTEXT (scope); t && TYPE_P (t); t = TYPE_CONTEXT (t))
- if (protected_accessible_p (decl, t, binfo))
- return 1;
+ if (friend_accessible_p (TYPE_CONTEXT (scope), decl, type, otype))
+ return 1;
if (DECL_DECLARES_FUNCTION_P (scope))
{
/* Perhaps this SCOPE is a member of a class which is a
friend. */
if (DECL_CLASS_SCOPE_P (scope)
- && friend_accessible_p (DECL_CONTEXT (scope), decl, binfo))
+ && friend_accessible_p (DECL_CONTEXT (scope), decl, type, otype))
return 1;
+ }
- /* Or an instantiation of something which is a friend. */
- if (DECL_TEMPLATE_INFO (scope))
+ /* Maybe scope's template is a friend. */
+ if (tree tinfo = get_template_info (scope))
+ {
+ tree tmpl = TI_TEMPLATE (tinfo);
+ if (DECL_CLASS_TEMPLATE_P (tmpl))
+ tmpl = TREE_TYPE (tmpl);
+ else
+ tmpl = DECL_TEMPLATE_RESULT (tmpl);
+ if (tmpl != scope)
{
- int ret;
/* Increment processing_template_decl to make sure that
dependent_type_p works correctly. */
++processing_template_decl;
- ret = friend_accessible_p (DECL_TI_TEMPLATE (scope), decl, binfo);
+ int ret = friend_accessible_p (tmpl, decl, type, otype);
--processing_template_decl;
- return ret;
+ if (ret)
+ return 1;
}
}
+ /* If is_friend is true, we should have found a befriending class. */
+ gcc_checking_assert (!is_friend (type, scope));
+
return 0;
}
+struct dfs_accessible_data
+{
+ tree decl;
+ tree object_type;
+};
+
+/* Avoid walking up past a declaration of the member. */
+
+static tree
+dfs_accessible_pre (tree binfo, void *data)
+{
+ dfs_accessible_data *d = (dfs_accessible_data *)data;
+ tree type = BINFO_TYPE (binfo);
+ if (member_declared_in_type (d->decl, type))
+ return dfs_skip_bases;
+ return NULL_TREE;
+}
+
/* Called via dfs_walk_once_accessible from accessible_p */
static tree
-dfs_accessible_post (tree binfo, void * /*data*/)
+dfs_accessible_post (tree binfo, void *data)
{
- if (BINFO_ACCESS (binfo) != ak_none)
+ /* access_in_type already set BINFO_ACCESS for us. */
+ access_kind access = BINFO_ACCESS (binfo);
+ tree N = BINFO_TYPE (binfo);
+ dfs_accessible_data *d = (dfs_accessible_data *)data;
+ tree decl = d->decl;
+ tree scope = current_nonlambda_scope ();
+
+ /* A member m is accessible at the point R when named in class N if */
+ switch (access)
{
- tree scope = current_scope ();
- if (scope && TREE_CODE (scope) != NAMESPACE_DECL
- && is_friend (BINFO_TYPE (binfo), scope))
- return binfo;
- }
+ case ak_none:
+ return NULL_TREE;
- return NULL_TREE;
+ case ak_public:
+ /* m as a member of N is public, or */
+ return binfo;
+
+ case ak_private:
+ {
+ /* m as a member of N is private, and R occurs in a member or friend of
+ class N, or */
+ if (scope && TREE_CODE (scope) != NAMESPACE_DECL
+ && is_friend (N, scope))
+ return binfo;
+ return NULL_TREE;
+ }
+
+ case ak_protected:
+ {
+ /* m as a member of N is protected, and R occurs in a member or friend
+ of class N, or in a member or friend of a class P derived from N,
+ where m as a member of P is public, private, or protected */
+ if (friend_accessible_p (scope, decl, N, d->object_type))
+ return binfo;
+ return NULL_TREE;
+ }
+
+ default:
+ gcc_unreachable ();
+ }
}
/* Like accessible_p below, but within a template returns true iff DECL is
@@ -858,21 +939,15 @@ int
accessible_p (tree type, tree decl, bool consider_local_p)
{
tree binfo;
- tree scope;
access_kind access;
- /* Nonzero if it's OK to access DECL if it has protected
- accessibility in TYPE. */
- int protected_ok = 0;
-
/* If this declaration is in a block or namespace scope, there's no
access control. */
if (!TYPE_P (context_for_name_lookup (decl)))
return 1;
/* There is no need to perform access checks inside a thunk. */
- scope = current_scope ();
- if (scope && DECL_THUNK_P (scope))
+ if (current_function_decl && DECL_THUNK_P (current_function_decl))
return 1;
/* In a template declaration, we cannot be sure whether the
@@ -886,13 +961,18 @@ accessible_p (tree type, tree decl, bool consider_local_p)
&& (!processing_template_parmlist || processing_template_decl > 1))
return 1;
+ tree otype;
if (!TYPE_P (type))
{
- binfo = type;
+ /* When accessing a non-static member, the most derived type in the
+ binfo chain is the type of the object; remember that type for
+ protected_accessible_p. */
+ for (tree b = type; b; b = BINFO_INHERITANCE_CHAIN (b))
+ otype = BINFO_TYPE (b);
type = BINFO_TYPE (type);
}
else
- binfo = TYPE_BINFO (type);
+ otype = type;
/* [class.access.base]
@@ -905,7 +985,7 @@ accessible_p (tree type, tree decl, bool consider_local_p)
--m as a member of N is protected, and the reference occurs in a
member or friend of class N, or in a member or friend of a
- class P derived from N, where m as a member of P is private or
+ class P derived from N, where m as a member of P is public, private or
protected, or
--there exists a base class B of N that is accessible at the point
@@ -913,40 +993,28 @@ accessible_p (tree type, tree decl, bool consider_local_p)
We walk the base class hierarchy, checking these conditions. */
- if (consider_local_p)
- {
- /* Figure out where the reference is occurring. Check to see if
- DECL is private or protected in this scope, since that will
- determine whether protected access is allowed. */
- tree ct = current_nonlambda_class_type ();
- if (ct)
- protected_ok = protected_accessible_p (decl,
- ct,
- binfo);
-
- /* Now, loop through the classes of which we are a friend. */
- if (!protected_ok)
- protected_ok = friend_accessible_p (scope, decl, binfo);
- }
-
- /* Standardize the binfo that access_in_type will use. We don't
- need to know what path was chosen from this point onwards. */
+ /* We walk using TYPE_BINFO (type) because access_in_type will set
+ BINFO_ACCESS on it and its bases. */
binfo = TYPE_BINFO (type);
/* Compute the accessibility of DECL in the class hierarchy
dominated by type. */
access = access_in_type (type, decl);
- if (access == ak_public
- || (access == ak_protected && protected_ok))
+ if (access == ak_public)
return 1;
+ /* If we aren't considering the point of reference, only the first bullet
+ applies. */
if (!consider_local_p)
return 0;
+ dfs_accessible_data d = { decl, otype };
+
/* Walk the hierarchy again, looking for a base class that allows
access. */
return dfs_walk_once_accessible (binfo, /*friends=*/true,
- NULL, dfs_accessible_post, NULL)
+ dfs_accessible_pre,
+ dfs_accessible_post, &d)
!= NULL_TREE;
}
diff --git a/gcc/testsuite/g++.dg/inherit/access9.C b/gcc/testsuite/g++.dg/inherit/access9.C
new file mode 100644
index 0000000..cdbc640
--- /dev/null
+++ b/gcc/testsuite/g++.dg/inherit/access9.C
@@ -0,0 +1,14 @@
+// PR c++/66957
+
+class BaseClass {
+protected:
+ static int x;
+};
+
+struct DerivedA : BaseClass { };
+
+struct DerivedB : BaseClass {
+ DerivedB() {
+ (void) DerivedA::x;
+ }
+};