/*
* Copyright (c) 2002, The Tendra Project <http://www.ten15.org/>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Crown Copyright (c) 1997
*
* This TenDRA(r) Computer Program is subject to Copyright
* owned by the United Kingdom Secretary of State for Defence
* acting through the Defence Evaluation and Research Agency
* (DERA). It is made available to Recipients with a
* royalty-free licence for its use, reproduction, transfer
* to other parties and amendment for any purpose not excluding
* product development provided that any such use et cetera
* shall be deemed to be acceptance of the following conditions:-
*
* (1) Its Recipients shall ensure that this Notice is
* reproduced upon any copies or amended versions of it;
*
* (2) Any amended version of it shall be clearly marked to
* show both the nature of and the organisation responsible
* for the relevant amendment or amendments;
*
* (3) Its onward transfer from a recipient to another
* party shall be deemed to be that party's acceptance of
* these conditions;
*
* (4) DERA gives no warranty or assurance as to its
* quality or suitability for any purpose and DERA accepts
* no liability whatsoever in relation to any use to which
* it may be put.
*
* $TenDRA: tendra/src/producers/common/construct/access.c,v 1.6 2004/08/14 15:15:35 bp Exp $
*/
#include "config.h"
#include "producer.h"
#include "c_types.h"
#include "ctype_ops.h"
#include "graph_ops.h"
#include "id_ops.h"
#include "nspace_ops.h"
#include "type_ops.h"
#include "error.h"
#include "catalog.h"
#include "access.h"
#include "chktype.h"
#include "class.h"
#include "derive.h"
#include "function.h"
#include "instance.h"
#include "namespace.h"
#include "predict.h"
#include "redeclare.h"
#include "token.h"
/*
* ACCESS CHECKING FLAGS
*
* The flag do_access_checks may be set to false to suppress access
* checking.
*/
int do_access_checks = 1;
/*
* CURRENT CLASS MEMBER ACCESS
*
* The variable crt_access is used to hold the current access specifier
* during a class definition. prev_access is used to check for dubious
* base class access specifiers.
*/
DECL_SPEC crt_access = dspec_public;
DECL_SPEC prev_access = dspec_public;
/*
* FIND THE COMPOSITE OF TWO ACCESSES
*
* This routine finds the composite of the access specifiers a and b,
* i.e. if Y is a base class of X of access a, and Z is a base class of
* Y of access b, then the result is the access of Z as a sub-class of X.
* Due to the fact that:
*
* dspec_public < dspec_protected < dspec_private
*
* the composite is just the maximum of the access components of a and b.
*/
DECL_SPEC
join_access(DECL_SPEC a, DECL_SPEC b)
{
DECL_SPEC p = (a & dspec_access);
DECL_SPEC q = (b & dspec_access);
if (p >= q) return (p);
return (q);
}
/*
* ADJUST THE ACCESS FOR AN IDENTIFIER
*
* This routine adjusts the access to the identifier id to the access
* level acc. expl is true for explicit using and access declarations
* and false for simple redeclarations.
*/
void
adjust_access(IDENTIFIER id, DECL_SPEC acc, int expl)
{
DECL_SPEC ds = DEREF_dspec (id_storage (id));
DECL_SPEC pacc = (ds & dspec_access);
if (pacc && acc != pacc) {
if (!expl) {
/* Access changed by redeclaration */
PTR (LOCATION) loc = id_loc (id);
report (crt_loc, ERR_class_access_spec_change (id, loc));
}
if (acc > pacc) {
if (expl) {
/* Access reduced by using declaration */
PTR (LOCATION) loc = id_loc (id);
report (crt_loc, ERR_dcl_nspace_udecl_acc (id, loc));
}
acc = pacc;
}
ds = ((ds & ~dspec_access) | acc);
COPY_dspec (id_storage (id), ds);
}
if (IS_id_function_etc (id) && expl) {
/* Deal with overloaded functions */
id = DEREF_id (id_function_etc_over (id));
if (!IS_NULL_id (id)) adjust_access (id, acc, expl);
}
return;
}
/*
* ACCESS DECLARATION FLAG
*
* This flag is set to true by access_decl.
*/
int have_access_decl = 0;
/*
* MAKE AN ACCESS DECLARATION
*
* This routine adjusts the access of the member id of the current class.
* This is equivalent to a using declaration for id.
*/
IDENTIFIER
access_decl(IDENTIFIER id)
{
report (crt_loc, ERR_class_access_dcl_using (id));
have_access_decl = 1;
id = using_identifier (id);
return (id);
}
/*
* MAKE A FRIENDLY FUNCTION
*
* This routine makes the function id into a friend of the class cs.
* The effect of this is to add cs to id's chums list and id to cs's
* pals list.
*/
void
friend_function(CLASS_TYPE cs, IDENTIFIER id, int expl)
{
if (!IS_NULL_ctype (cs)) {
IDENTIFIER cid;
LIST (IDENTIFIER) pl;
LIST (CLASS_TYPE) fr, fs;
/* Make cs a pal of id */
fr = DEREF_list (id_function_etc_chums (id));
fs = fr;
while (!IS_NULL_list (fs)) {
CLASS_TYPE ct = DEREF_ctype (HEAD_list (fs));
if (eq_ctype (ct, cs)) {
/* id is already a friend of ns */
if (expl) {
ERROR err = ERR_class_friend_dup_func (id, cs);
report (crt_loc, err);
}
return;
}
fs = TAIL_list (fs);
}
CONS_ctype (cs, fr, fr);
COPY_list (id_function_etc_chums (id), fr);
/* Make id a pal of cs */
pl = DEREF_list (ctype_pals (cs));
CONS_id (id, pl, pl);
COPY_list (ctype_pals (cs), pl);
/* Apply access checks immediately */
cid = DEREF_id (ctype_name (cs));
immediate_access (cid, id);
}
return;
}
/*
* MAKE A FRIENDLY CLASS
*
* This routine makes the class cid into a friend of the class cs. The
* effect of this is to add cs to cid's chums list and cid to cs's pals
* list.
*/
void
friend_class(CLASS_TYPE cs, IDENTIFIER cid, int expl)
{
if (!IS_NULL_ctype (cs)) {
ERROR err;
TYPE t = DEREF_type (id_class_name_etc_defn (cid));
while (IS_type_templ (t)) {
t = DEREF_type (type_templ_defn (t));
}
if (IS_type_compound (t)) {
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
if (eq_ctype (cs, ct)) {
/* Any class is a friend of itself */
if (expl) {
err = ERR_class_friend_dup_class (ct, cs);
report (crt_loc, err);
}
} else {
IDENTIFIER sid;
LIST (IDENTIFIER) pl;
/* Make cs a chum of ct */
LIST (CLASS_TYPE) fr = DEREF_list (ctype_chums (ct));
LIST (CLASS_TYPE) fs = fr;
while (!IS_NULL_list (fs)) {
CLASS_TYPE cr = DEREF_ctype (HEAD_list (fs));
if (eq_ctype (cr, cs)) {
/* ct is already a friend of cs */
if (expl) {
err = ERR_class_friend_dup_class (ct, cs);
report (crt_loc, err);
}
return;
}
fs = TAIL_list (fs);
}
CONS_ctype (cs, fr, fr);
COPY_list (ctype_chums (ct), fr);
/* Make ct a pal of cs */
pl = DEREF_list (ctype_pals (cs));
CONS_id (cid, pl, pl);
COPY_list (ctype_pals (cs), pl);
/* Apply access checks immediately */
sid = DEREF_id (ctype_name (cs));
immediate_access (sid, cid);
}
}
}
return;
}
/*
* LISTS OF PENDING ACCESS CHECKS
*
* Access control checking cannot be performed immediately because, for
* example, it is not known until the end of a declaration whether that
* declaration represents a friend function. The list crt_access_list
* is used to store any pending access checks.
*/
ACCESS_LIST crt_access_list = {
NULL_list (IDENTIFIER), NULL_list (GRAPH),
NULL_list (int), 0, 0
};
/*
* FIND ACCESS LEVEL
*
* This routine finds the access level for the members of the class
* namespace ns by the identifier pid (or a base class conversion from
* ns if base is true). It returns the highest access level greater
* than acc which can be accessed. It also returns a secondary access
* giving the access to base class members, plus markers for whether
* the access is via the actual class, a derived class or a friend.
*/
static DECL_SPEC
find_access(IDENTIFIER *pid, NAMESPACE ns, DECL_SPEC acc, int base)
{
NAMESPACE cns;
CLASS_TYPE ct;
TYPE t = NULL_type;
IDENTIFIER id = *pid;
/* Find the namespace corresponding to id */
DECL_SPEC ok = (dspec_public | dspec_public2);
if (IS_NULL_id (id)) return (ok);
if (IS_id_class_name (id)) {
cns = find_namespace (id);
} else {
cns = DEREF_nspace (id_parent (id));
}
if (IS_NULL_nspace (cns)) return (ok);
/* Map block identifiers to the corresponding function */
if (IS_nspace_block (cns)) {
id = DEREF_id (nspace_name (cns));
cns = DEREF_nspace (id_parent (id));
*pid = id;
}
/* Allow for equal namespaces */
if (base) {
ok = (dspec_private | dspec_public2);
} else {
ok = (dspec_private | dspec_protected2);
}
if (EQ_nspace (cns, ns)) {
ok |= dspec_defn;
return (ok);
}
ct = namespace_class (ns);
ct = expand_ctype (ct, 2, &t);
complete_class (ct, 1);
/* Check access for classes */
if (IS_nspace_ctype (cns)) {
LIST (CLASS_TYPE) fr;
CLASS_TYPE cs = namespace_class (cns);
if (eq_ctype (cs, ct)) {
/* Same class */
ok |= dspec_defn;
return (ok);
}
fr = DEREF_list (ctype_chums (cs));
while (!IS_NULL_list (fr)) {
CLASS_TYPE cr = DEREF_ctype (HEAD_list (fr));
if (eq_ctype (cr, ct)) {
/* Friend class */
ok |= (dspec_defn | dspec_friend);
return (ok);
}
fr = TAIL_list (fr);
}
}
/* Check for friend functions */
if (IS_id_function_etc (id)) {
LIST (CLASS_TYPE) fr;
fr = DEREF_list (id_function_etc_chums (id));
while (!IS_NULL_list (fr)) {
CLASS_TYPE cr = DEREF_ctype (HEAD_list (fr));
if (eq_ctype (cr, ct)) {
/* Friend function */
ok |= (dspec_defn | dspec_friend);
return (ok);
}
fr = TAIL_list (fr);
}
}
/* End here for private members */
if (acc == dspec_private || base) {
ok = (dspec_public | dspec_public2);
return (ok);
}
/* Check access for derived classes */
ok = (dspec_protected | dspec_protected2);
if (IS_nspace_ctype (cns)) {
LIST (CLASS_TYPE) fr;
CLASS_TYPE cs = namespace_class (cns);
GRAPH gr = find_base_class (cs, ct, 0);
if (!IS_NULL_graph (gr)) {
/* Derived class */
ok |= dspec_inherit;
return (ok);
}
fr = DEREF_list (ctype_chums (cs));
while (!IS_NULL_list (fr)) {
CLASS_TYPE cr = DEREF_ctype (HEAD_list (fr));
gr = find_base_class (cr, ct, 0);
if (!IS_NULL_graph (gr)) {
/* Friend class of derived class */
ok |= (dspec_inherit | dspec_friend);
return (ok);
}
fr = TAIL_list (fr);
}
}
/* Check for derived friend functions */
if (IS_id_function_etc (id)) {
LIST (CLASS_TYPE) fr;
fr = DEREF_list (id_function_etc_chums (id));
while (!IS_NULL_list (fr)) {
CLASS_TYPE cr = DEREF_ctype (HEAD_list (fr));
GRAPH gr = find_base_class (cr, ct, 0);
if (!IS_NULL_graph (gr)) {
/* Friend function of derived class */
ok |= (dspec_inherit | dspec_friend);
return (ok);
}
fr = TAIL_list (fr);
}
}
/* Default access */
ok = (dspec_public | dspec_public2);
return (ok);
}
/*
* COMPARE ACCESS LEVELS
*
* This routine checks whether the access level ok returned by find_access
* is sufficient to access a member of type tag with declaration specifiers
* ds. It returns true if the access is an error.
*/
static int
compare_access(DECL_SPEC ok, DECL_SPEC ds, unsigned tag, int mem)
{
int ret = 0;
DECL_SPEC acc = (ds & dspec_access);
DECL_SPEC level = (ok & dspec_access);
if (level < acc) {
/* Straightforward case */
ret = 1;
} else {
/* Deal with inheritance */
if (ds & dspec_inherit) {
DECL_SPEC acc2 = (ds & dspec_access2);
level = (ok & dspec_access2);
if (level < acc2) ret = 1;
}
}
if (!ret && !mem) {
if (tag == id_member_tag || tag == id_mem_func_tag) {
/* Check for access through derived class */
if (ok & dspec_inherit) ret = 1;
}
}
return (ret);
}
/*
* CAN AN INHERITED MEMBER BE ACCESSED?
*
* This routine checks whether the inherited class member pid can be
* accessed by the identifier id. If so it returns true. The direct
* cases, such as a member of a derived class accessing a member of a
* base class are handled by the main part of do_member_access, this
* routine deals with the indirect cases such as friends of classes
* intermediate between the base class and the derived class.
*/
static int
inherit_access(IDENTIFIER id, IDENTIFIER pid, int mem)
{
/* Find inheritance base class */
unsigned tag = TAG_id (pid);
IDENTIFIER bid = DEREF_id (id_alias (pid));
DECL_SPEC acc = DEREF_dspec (id_storage (bid));
NAMESPACE pns = DEREF_nspace (id_parent (pid));
NAMESPACE bns = DEREF_nspace (id_parent (bid));
CLASS_TYPE ct = namespace_class (pns);
CLASS_TYPE cs = namespace_class (bns);
GRAPH gr = find_base_class (ct, cs, 0);
/* Scan through all base classes of ct containing bid */
while (!IS_NULL_graph (gr)) {
GRAPH gs = gr;
while (!IS_NULL_graph (gs)) {
cs = DEREF_ctype (graph_head (gs));
if (!eq_ctype (cs, ct)) {
DECL_SPEC ds, ok;
ds = DEREF_dspec (graph_access (gr));
ds = join_access (acc, ds);
bns = DEREF_nspace (ctype_member (cs));
ok = find_access (&id, bns, ds, 2);
if (ok & dspec_defn) {
/* id is a member or friend of cs */
if (!compare_access (ok, ds, tag, mem)) {
/* Can access bid */
return (1);
}
}
}
gs = DEREF_graph (graph_up (gs));
}
gr = DEREF_graph (graph_equal (gr));
}
return (0);
}
/*
* CHECK A MEMBER ACCESS
*
* This routine checks the access of the class member pid by the
* identifier id. It prints an error and returns true if the access
* is illegal.
*/
static int
do_member_access(IDENTIFIER id, IDENTIFIER pid, int mem)
{
int ret = 0;
NAMESPACE pns = DEREF_nspace (id_parent (pid));
DECL_SPEC ds = DEREF_dspec (id_storage (pid));
DECL_SPEC acc = (ds & dspec_access);
DECL_SPEC ok = find_access (&id, pns, acc, 0);
if (compare_access (ok, ds, TAG_id (pid), mem)) {
if ((ds & dspec_inherit) && inherit_access (id, pid, mem)) {
/* Can access through inheritance */
/* EMPTY */
} else {
/* Report access error */
ERROR err;
if (IS_NULL_id (id)) {
err = ERR_class_access_spec_none (pid, acc);
} else {
err = ERR_class_access_spec_id (pid, acc, id);
}
report (crt_loc, err);
ret = 1;
}
}
return (ret);
}
/*
* CHECK A BASE CLASS ACCESS
*
* This routine checks the access of the base class gr by the
* identifier id. It prints an error and returns true if the access
* is illegal.
*/
static int
do_base_access(IDENTIFIER id, GRAPH gr)
{
int ret = 0;
GRAPH gt = DEREF_graph (graph_top (gr));
CLASS_TYPE ct = DEREF_ctype (graph_head (gt));
NAMESPACE pns = DEREF_nspace (ctype_member (ct));
DECL_SPEC ds = DEREF_dspec (graph_access (gr));
DECL_SPEC acc = (ds & dspec_access);
DECL_SPEC ok = find_access (&id, pns, acc, 1);
if (compare_access (ok, ds, null_tag, 0)) {
/* Report access error */
ERROR err;
CLASS_TYPE cs = DEREF_ctype (graph_head (gr));
if (IS_NULL_id (id)) {
err = ERR_class_access_base_none (cs, ct, acc);
} else {
err = ERR_class_access_base_id (cs, ct, acc, id);
}
err = concat_error (err, ERR_conv_ptr_access ());
report (crt_loc, err);
ret = 1;
}
return (ret);
}
/*
* CLEAR A LIST OF PENDING IDENTIFIER ACCESS CHECKS
*
* This routine clears the list of pending access checks given by p in
* the context given by the identifier id. It returns true if any
* results in an error.
*/
static int
clear_id_access(IDENTIFIER id, LIST (IDENTIFIER) p, LIST (int) r)
{
int ret = 0;
if (!IS_NULL_list (p)) {
int mem = DEREF_int (HEAD_list (r));
IDENTIFIER pid = DEREF_id (HEAD_list (p));
ret = clear_id_access (id, TAIL_list (p), TAIL_list (r));
if (!IS_NULL_id (pid) && do_member_access (id, pid, mem)) {
COPY_id (HEAD_list (p), NULL_id);
ret = 1;
}
}
return (ret);
}
/*
* CLEAR A LIST OF PENDING BASE CLASS ACCESS CHECKS
*
* This routine clears the list of pending base class access checks given
* by p in the context given by the identifier id. It returns true if
* any results in an error.
*/
static int
clear_base_access(IDENTIFIER id, LIST (GRAPH) p)
{
int ret = 0;
if (!IS_NULL_list (p)) {
GRAPH gr = DEREF_graph (HEAD_list (p));
ret = clear_base_access (id, TAIL_list (p));
if (!IS_NULL_graph (gr) && do_base_access (id, gr)) {
COPY_graph (HEAD_list (p), NULL_graph);
ret = 1;
}
}
return (ret);
}
/*
* CLEAR A LIST OF PENDING ACCESS CHECKS
*
* This routine clears the list of pending access checks given by acc in
* the context given by the identifier id. It returns true if any
* results in an error.
*/
int
clear_access(IDENTIFIER id, ACCESS_LIST *acc)
{
int ret = 0;
if (acc->pending) {
LIST (IDENTIFIER) p = acc->ids;
LIST (GRAPH) q = acc->bases;
LIST (int) r = acc->info;
if (!IS_NULL_list (p) && clear_id_access (id, p, r)) ret = 1;
if (!IS_NULL_list (q) && clear_base_access (id, q)) ret = 1;
}
return (ret);
}
/*
* CLEAR THE LIST OF CURRENT ACCESSES
*
* This routine clears all outstanding accesses in the scope given by id.
* It returns true if any results in an error.
*/
int
report_access(IDENTIFIER id)
{
ACCESS_LIST *acc = &crt_access_list;
int ret = clear_access (id, acc);
free_access (acc);
return (ret);
}
/*
* FREE AN ACCESS LIST
*
* This routine frees the list of accesses given by acc.
*/
void
free_access(ACCESS_LIST *acc)
{
LIST (IDENTIFIER) p = acc->ids;
LIST (GRAPH) q = acc->bases;
LIST (int) r = acc->info;
if (!IS_NULL_list (p)) {
DESTROY_list (p, SIZE_id);
acc->ids = NULL_list (IDENTIFIER);
}
if (!IS_NULL_list (q)) {
DESTROY_list (q, SIZE_graph);
acc->bases = NULL_list (GRAPH);
}
if (!IS_NULL_list (r)) {
DESTROY_list (r, SIZE_int);
acc->info = NULL_list (int);
}
acc->pending = 0;
acc->inherit = 0;
return;
}
/*
* SAVE AN ACCESS LIST
*
* This routine saves the current access list into acc and clears the
* list.
*/
void
save_access(ACCESS_LIST *acc)
{
ACCESS_LIST *crt = &crt_access_list;
acc->ids = crt->ids;
acc->bases = crt->bases;
acc->info = crt->info;
acc->pending = crt->pending;
acc->inherit = crt->inherit;
crt->ids = NULL_list (IDENTIFIER);
crt->bases = NULL_list (GRAPH);
crt->info = NULL_list (int);
crt->pending = 0;
crt->inherit = 0;
return;
}
/*
* RESTORE AN ACCESS LIST
*
* This routine clears the current access list in the scope given by
* id and resets the current access list the values stored in acc.
*/
int
restore_access(IDENTIFIER id, ACCESS_LIST *acc)
{
int ret = report_access (id);
ACCESS_LIST *crt = &crt_access_list;
crt->ids = acc->ids;
crt->bases = acc->bases;
crt->info = acc->info;
crt->pending = acc->pending;
crt->inherit = acc->inherit;
return (ret);
}
/*
* CHECK THE ACCESS TO AN IDENTIFIER
*
* This routine adds the identifier id with access acc to the list of
* pending access checks. acc will always be dspec_public, dspec_protected
* or dspec_private.
*/
void
check_access(IDENTIFIER id, DECL_SPEC acc)
{
if (acc == dspec_public) return;
if (do_access_checks) {
NAMESPACE ns = DEREF_nspace (id_parent (id));
if (IS_nspace_ctype (ns)) {
ACCESS_LIST *crt = &crt_access_list;
if (in_function_defn && !in_declaration) {
/* Calculate access immediately */
IGNORE do_member_access (crt_func_id, id, crt->inherit);
} else {
/* Add to pending list */
CONS_id (id, crt->ids, crt->ids);
CONS_int (crt->inherit, crt->info, crt->info);
crt->pending = 1;
}
} else {
DECL_SPEC ds = DEREF_dspec (id_storage (id));
if (ds & dspec_auto) {
/* Used to mark for-init variables */
report (crt_loc, ERR_stmt_for_init (id));
ds &= ~dspec_access;
COPY_dspec (id_storage (id), ds);
}
}
}
return;
}
/*
* CHECK THE ACCESS TO A BASE CLASS
*
* This routine adds the base class graph gr to the list of pending
* base access checks.
*/
void
check_base_access(GRAPH gr)
{
DECL_SPEC ds = DEREF_dspec (graph_access (gr));
DECL_SPEC acc = (ds & dspec_access);
DECL_SPEC acc2 = (ds & dspec_access2);
if (acc == dspec_public) return;
if (do_access_checks) {
/* Find best access to a virtual base */
GRAPH gs = DEREF_graph (graph_equal (gr));
while (!IS_NULL_graph (gs)) {
DECL_SPEC pds = DEREF_dspec (graph_access (gs));
DECL_SPEC pacc = (pds & dspec_access);
DECL_SPEC pacc2 = (pds & dspec_access2);
if (pacc == dspec_public) return;
if (pacc < acc || (pacc == acc && pacc2 < acc2)) {
acc = pacc;
acc2 = pacc2;
gr = gs;
}
gs = DEREF_graph (graph_equal (gs));
}
/* Check access control */
if (in_function_defn && !in_declaration) {
/* Calculate access immediately */
IGNORE do_base_access (crt_func_id, gr);
} else {
/* Add to pending list */
ACCESS_LIST *crt = &crt_access_list;
CONS_graph (gr, crt->bases, crt->bases);
crt->pending = 1;
}
}
return;
}
/*
* IMMEDIATELY CHECK THE ACCESS TO AN IDENTIFIER
*
* This routine applies an immediate access check to the identifier id
* by cid.
*/
void
immediate_access(IDENTIFIER cid, IDENTIFIER id)
{
DECL_SPEC acc = DEREF_dspec (id_storage (id));
acc &= dspec_access;
if (acc == dspec_none || acc == dspec_public) return;
if (do_access_checks) {
NAMESPACE ns = DEREF_nspace (id_parent (id));
if (IS_nspace_ctype (ns)) {
int mem = crt_access_list.inherit;
IGNORE do_member_access (cid, id, mem);
}
}
return;
}
syntax highlighted by Code2HTML, v. 0.9.1