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 *);
\f
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)))
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
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]
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))
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
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
&& (!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]
--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
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;
}