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
This commit is contained in:
parent
18c4fa8ef0
commit
7ac2c0bd17
|
@ -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>
|
||||
|
|
|
@ -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,6 +170,7 @@ add_friend (tree type, tree decl, bool complain)
|
|||
|
||||
maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1);
|
||||
|
||||
if (!list)
|
||||
DECL_FRIENDLIST (typedecl)
|
||||
= tree_cons (DECL_NAME (decl), build_tree_list (NULL_TREE, decl),
|
||||
DECL_FRIENDLIST (typedecl));
|
||||
|
|
218
gcc/cp/search.c
218
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)))
|
||||
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,14 +805,13 @@ 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))
|
||||
if (friend_accessible_p (TYPE_CONTEXT (scope), decl, type, otype))
|
||||
return 1;
|
||||
|
||||
if (DECL_DECLARES_FUNCTION_P (scope))
|
||||
|
@ -798,41 +819,101 @@ friend_accessible_p (tree scope, tree decl, tree binfo)
|
|||
/* 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))
|
||||
case ak_none:
|
||||
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
|
||||
accessible in TYPE to all possible instantiations of the template. */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// PR c++/66957
|
||||
|
||||
class BaseClass {
|
||||
protected:
|
||||
static int x;
|
||||
};
|
||||
|
||||
struct DerivedA : BaseClass { };
|
||||
|
||||
struct DerivedB : BaseClass {
|
||||
DerivedB() {
|
||||
(void) DerivedA::x;
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue