Subversion Repositories tendra.SVN

Rev

Rev 5 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
6 7u83 2
 * Copyright (c) 2002-2006 The TenDRA Project <http://www.tendra.org/>.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright notice,
11
 *    this list of conditions and the following disclaimer in the documentation
12
 *    and/or other materials provided with the distribution.
13
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific, prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
18
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * $Id$
30
 */
31
/*
2 7u83 32
    		 Crown Copyright (c) 1997
6 7u83 33
 
2 7u83 34
    This TenDRA(r) Computer Program is subject to Copyright
35
    owned by the United Kingdom Secretary of State for Defence
36
    acting through the Defence Evaluation and Research Agency
37
    (DERA).  It is made available to Recipients with a
38
    royalty-free licence for its use, reproduction, transfer
39
    to other parties and amendment for any purpose not excluding
40
    product development provided that any such use et cetera
41
    shall be deemed to be acceptance of the following conditions:-
6 7u83 42
 
2 7u83 43
        (1) Its Recipients shall ensure that this Notice is
44
        reproduced upon any copies or amended versions of it;
6 7u83 45
 
2 7u83 46
        (2) Any amended version of it shall be clearly marked to
47
        show both the nature of and the organisation responsible
48
        for the relevant amendment or amendments;
6 7u83 49
 
2 7u83 50
        (3) Its onward transfer from a recipient to another
51
        party shall be deemed to be that party's acceptance of
52
        these conditions;
6 7u83 53
 
2 7u83 54
        (4) DERA gives no warranty or assurance as to its
55
        quality or suitability for any purpose and DERA accepts
56
        no liability whatsoever in relation to any use to which
57
        it may be put.
58
*/
59
 
60
 
61
#include "config.h"
62
#include "c_types.h"
63
#include "ctype_ops.h"
64
#include "graph_ops.h"
65
#include "id_ops.h"
66
#include "nspace_ops.h"
67
#include "type_ops.h"
68
#include "error.h"
69
#include "catalog.h"
70
#include "access.h"
71
#include "chktype.h"
72
#include "class.h"
73
#include "derive.h"
74
#include "function.h"
75
#include "instance.h"
76
#include "namespace.h"
77
#include "predict.h"
78
#include "redeclare.h"
79
#include "token.h"
80
 
81
 
82
/*
83
    ACCESS CHECKING FLAGS
84
 
85
    The flag do_access_checks may be set to false to suppress access
86
    checking.
87
*/
88
 
6 7u83 89
int do_access_checks = 1;
2 7u83 90
 
91
 
92
/*
93
    CURRENT CLASS MEMBER ACCESS
94
 
95
    The variable crt_access is used to hold the current access specifier
96
    during a class definition.  prev_access is used to check for dubious
97
    base class access specifiers.
98
*/
99
 
6 7u83 100
DECL_SPEC crt_access = dspec_public;
101
DECL_SPEC prev_access = dspec_public;
2 7u83 102
 
103
 
104
/*
105
    FIND THE COMPOSITE OF TWO ACCESSES
106
 
107
    This routine finds the composite of the access specifiers a and b,
108
    i.e. if Y is a base class of X of access a, and Z is a base class of
109
    Y of access b, then the result is the access of Z as a sub-class of X.
110
    Due to the fact that:
111
 
112
	    dspec_public < dspec_protected < dspec_private
113
 
114
    the composite is just the maximum of the access components of a and b.
115
*/
116
 
6 7u83 117
DECL_SPEC
118
join_access(DECL_SPEC a, DECL_SPEC b)
2 7u83 119
{
6 7u83 120
	DECL_SPEC p = (a & dspec_access);
121
	DECL_SPEC q = (b & dspec_access);
122
	if (p >= q) {
123
		return (p);
124
	}
125
	return (q);
2 7u83 126
}
127
 
128
 
129
/*
130
    ADJUST THE ACCESS FOR AN IDENTIFIER
131
 
132
    This routine adjusts the access to the identifier id to the access
133
    level acc.  expl is true for explicit using and access declarations
134
    and false for simple redeclarations.
135
*/
136
 
6 7u83 137
void
138
adjust_access(IDENTIFIER id, DECL_SPEC acc, int expl)
2 7u83 139
{
6 7u83 140
    DECL_SPEC ds = DEREF_dspec(id_storage(id));
141
    DECL_SPEC pacc = (ds & dspec_access);
142
    if (pacc && acc != pacc) {
143
	if (!expl) {
2 7u83 144
	    /* Access changed by redeclaration */
6 7u83 145
	    PTR(LOCATION)loc = id_loc(id);
146
	    report(crt_loc, ERR_class_access_spec_change(id, loc));
2 7u83 147
	}
6 7u83 148
	if (acc > pacc) {
149
	    if (expl) {
2 7u83 150
		/* Access reduced by using declaration */
6 7u83 151
		PTR(LOCATION)loc = id_loc(id);
152
		report(crt_loc, ERR_dcl_nspace_udecl_acc(id, loc));
2 7u83 153
	    }
6 7u83 154
	    acc = pacc;
2 7u83 155
	}
6 7u83 156
	ds = ((ds & ~dspec_access) | acc);
157
	COPY_dspec(id_storage(id), ds);
2 7u83 158
    }
6 7u83 159
    if (IS_id_function_etc(id) && expl) {
2 7u83 160
	/* Deal with overloaded functions */
6 7u83 161
	id = DEREF_id(id_function_etc_over(id));
162
	if (!IS_NULL_id(id))adjust_access(id, acc, expl);
2 7u83 163
    }
6 7u83 164
    return;
2 7u83 165
}
166
 
167
 
168
/*
169
    ACCESS DECLARATION FLAG
170
 
171
    This flag is set to true by access_decl.
172
*/
173
 
6 7u83 174
int have_access_decl = 0;
2 7u83 175
 
176
 
177
/*
178
    MAKE AN ACCESS DECLARATION
179
 
180
    This routine adjusts the access of the member id of the current class.
181
    This is equivalent to a using declaration for id.
182
*/
183
 
6 7u83 184
IDENTIFIER
185
access_decl(IDENTIFIER id)
2 7u83 186
{
6 7u83 187
	report(crt_loc, ERR_class_access_dcl_using(id));
188
	have_access_decl = 1;
189
	id = using_identifier(id);
190
	return (id);
2 7u83 191
}
192
 
193
 
194
/*
195
    MAKE A FRIENDLY FUNCTION
196
 
197
    This routine makes the function id into a friend of the class cs.
198
    The effect of this is to add cs to id's chums list and id to cs's
199
    pals list.
200
*/
201
 
6 7u83 202
void
203
friend_function(CLASS_TYPE cs, IDENTIFIER id, int expl)
2 7u83 204
{
6 7u83 205
    if (!IS_NULL_ctype(cs)) {
206
	IDENTIFIER cid;
207
	LIST(IDENTIFIER)pl;
208
	LIST(CLASS_TYPE)fr, fs;
2 7u83 209
 
210
	/* Make cs a pal of id */
6 7u83 211
	fr = DEREF_list(id_function_etc_chums(id));
212
	fs = fr;
213
	while (!IS_NULL_list(fs)) {
214
	    CLASS_TYPE ct = DEREF_ctype(HEAD_list(fs));
215
	    if (eq_ctype(ct, cs)) {
2 7u83 216
		/* id is already a friend of ns */
6 7u83 217
		if (expl) {
218
		    ERROR err = ERR_class_friend_dup_func(id, cs);
219
		    report(crt_loc, err);
2 7u83 220
		}
6 7u83 221
		return;
2 7u83 222
	    }
6 7u83 223
	    fs = TAIL_list(fs);
2 7u83 224
	}
6 7u83 225
	CONS_ctype(cs, fr, fr);
226
	COPY_list(id_function_etc_chums(id), fr);
2 7u83 227
 
228
	/* Make id a pal of cs */
6 7u83 229
	pl = DEREF_list(ctype_pals(cs));
230
	CONS_id(id, pl, pl);
231
	COPY_list(ctype_pals(cs), pl);
2 7u83 232
 
233
	/* Apply access checks immediately */
6 7u83 234
	cid = DEREF_id(ctype_name(cs));
235
	immediate_access(cid, id);
2 7u83 236
    }
6 7u83 237
    return;
2 7u83 238
}
239
 
240
 
241
/*
242
    MAKE A FRIENDLY CLASS
243
 
244
    This routine makes the class cid into a friend of the class cs.  The
245
    effect of this is to add cs to cid's chums list and cid to cs's pals
246
    list.
247
*/
248
 
6 7u83 249
void
250
friend_class(CLASS_TYPE cs, IDENTIFIER cid, int expl)
2 7u83 251
{
6 7u83 252
    if (!IS_NULL_ctype(cs)) {
253
	ERROR err;
254
	TYPE t = DEREF_type(id_class_name_etc_defn(cid));
255
	while (IS_type_templ(t)) {
256
	    t = DEREF_type(type_templ_defn(t));
2 7u83 257
	}
6 7u83 258
	if (IS_type_compound(t)) {
259
	    CLASS_TYPE ct = DEREF_ctype(type_compound_defn(t));
260
	    if (eq_ctype(cs, ct)) {
2 7u83 261
		/* Any class is a friend of itself */
6 7u83 262
		if (expl) {
263
		    err = ERR_class_friend_dup_class(ct, cs);
264
		    report(crt_loc, err);
2 7u83 265
		}
266
	    } else {
6 7u83 267
		IDENTIFIER sid;
268
		LIST(IDENTIFIER)pl;
2 7u83 269
 
270
		/* Make cs a chum of ct */
6 7u83 271
		LIST(CLASS_TYPE)fr = DEREF_list(ctype_chums(ct));
272
		LIST(CLASS_TYPE)fs = fr;
273
		while (!IS_NULL_list(fs)) {
274
		    CLASS_TYPE cr = DEREF_ctype(HEAD_list(fs));
275
		    if (eq_ctype(cr, cs)) {
2 7u83 276
			/* ct is already a friend of cs */
6 7u83 277
			if (expl) {
278
			    err = ERR_class_friend_dup_class(ct, cs);
279
			    report(crt_loc, err);
2 7u83 280
			}
6 7u83 281
			return;
2 7u83 282
		    }
6 7u83 283
		    fs = TAIL_list(fs);
2 7u83 284
		}
6 7u83 285
		CONS_ctype(cs, fr, fr);
286
		COPY_list(ctype_chums(ct), fr);
2 7u83 287
 
288
		/* Make ct a pal of cs */
6 7u83 289
		pl = DEREF_list(ctype_pals(cs));
290
		CONS_id(cid, pl, pl);
291
		COPY_list(ctype_pals(cs), pl);
2 7u83 292
 
293
		/* Apply access checks immediately */
6 7u83 294
		sid = DEREF_id(ctype_name(cs));
295
		immediate_access(sid, cid);
2 7u83 296
	    }
297
	}
298
    }
6 7u83 299
    return;
2 7u83 300
}
301
 
302
 
303
/*
304
    LISTS OF PENDING ACCESS CHECKS
305
 
306
    Access control checking cannot be performed immediately because, for
307
    example, it is not known until the end of a declaration whether that
308
    declaration represents a friend function.  The list crt_access_list
309
    is used to store any pending access checks.
310
*/
311
 
312
ACCESS_LIST crt_access_list = {
6 7u83 313
	NULL_list(IDENTIFIER), NULL_list(GRAPH),
314
	NULL_list(int), 0, 0
315
};
2 7u83 316
 
317
 
318
/*
319
    FIND ACCESS LEVEL
320
 
321
    This routine finds the access level for the members of the class
322
    namespace ns by the identifier pid (or a base class conversion from
323
    ns if base is true).  It returns the highest access level greater
324
    than acc which can be accessed.  It also returns a secondary access
325
    giving the access to base class members, plus markers for whether
326
    the access is via the actual class, a derived class or a friend.
327
*/
328
 
6 7u83 329
static DECL_SPEC
330
find_access(IDENTIFIER *pid, NAMESPACE ns, DECL_SPEC acc, int base)
2 7u83 331
{
6 7u83 332
    NAMESPACE cns;
333
    CLASS_TYPE ct;
334
    TYPE t = NULL_type;
335
    IDENTIFIER id = *pid;
2 7u83 336
 
337
    /* Find the namespace corresponding to id */
6 7u83 338
    DECL_SPEC ok = (dspec_public | dspec_public2);
339
    if (IS_NULL_id(id)) {
340
	    return (ok);
341
    }
342
    if (IS_id_class_name(id)) {
343
	cns = find_namespace(id);
2 7u83 344
    } else {
6 7u83 345
	cns = DEREF_nspace(id_parent(id));
2 7u83 346
    }
6 7u83 347
    if (IS_NULL_nspace(cns)) {
348
	    return (ok);
349
    }
2 7u83 350
 
351
    /* Map block identifiers to the corresponding function */
6 7u83 352
    if (IS_nspace_block(cns)) {
353
	id = DEREF_id(nspace_name(cns));
354
	cns = DEREF_nspace(id_parent(id));
355
	*pid = id;
2 7u83 356
    }
357
 
358
    /* Allow for equal namespaces */
6 7u83 359
    if (base) {
360
	ok = (dspec_private | dspec_public2);
2 7u83 361
    } else {
6 7u83 362
	ok = (dspec_private | dspec_protected2);
2 7u83 363
    }
6 7u83 364
    if (EQ_nspace(cns, ns)) {
365
	ok |= dspec_defn;
366
	return (ok);
2 7u83 367
    }
6 7u83 368
    ct = namespace_class(ns);
369
    ct = expand_ctype(ct, 2, &t);
370
    complete_class(ct, 1);
2 7u83 371
 
372
    /* Check access for classes */
6 7u83 373
    if (IS_nspace_ctype(cns)) {
374
	LIST(CLASS_TYPE)fr;
375
	CLASS_TYPE cs = namespace_class(cns);
376
	if (eq_ctype(cs, ct)) {
2 7u83 377
	    /* Same class */
6 7u83 378
	    ok |= dspec_defn;
379
	    return (ok);
2 7u83 380
	}
6 7u83 381
	fr = DEREF_list(ctype_chums(cs));
382
	while (!IS_NULL_list(fr)) {
383
	    CLASS_TYPE cr = DEREF_ctype(HEAD_list(fr));
384
	    if (eq_ctype(cr, ct)) {
2 7u83 385
		/* Friend class */
6 7u83 386
		ok |= (dspec_defn | dspec_friend);
387
		return (ok);
2 7u83 388
	    }
6 7u83 389
	    fr = TAIL_list(fr);
2 7u83 390
	}
391
    }
392
 
393
    /* Check for friend functions */
6 7u83 394
    if (IS_id_function_etc(id)) {
395
	LIST(CLASS_TYPE)fr;
396
	fr = DEREF_list(id_function_etc_chums(id));
397
	while (!IS_NULL_list(fr)) {
398
	    CLASS_TYPE cr = DEREF_ctype(HEAD_list(fr));
399
	    if (eq_ctype(cr, ct)) {
2 7u83 400
		/* Friend function */
6 7u83 401
		ok |= (dspec_defn | dspec_friend);
402
		return (ok);
2 7u83 403
	    }
6 7u83 404
	    fr = TAIL_list(fr);
2 7u83 405
	}
406
    }
407
 
408
    /* End here for private members */
6 7u83 409
    if (acc == dspec_private || base) {
410
	ok = (dspec_public | dspec_public2);
411
	return (ok);
2 7u83 412
    }
413
 
414
    /* Check access for derived classes */
6 7u83 415
    ok = (dspec_protected | dspec_protected2);
416
    if (IS_nspace_ctype(cns)) {
417
	LIST(CLASS_TYPE)fr;
418
	CLASS_TYPE cs = namespace_class(cns);
419
	GRAPH gr = find_base_class(cs, ct, 0);
420
	if (!IS_NULL_graph(gr)) {
2 7u83 421
	    /* Derived class */
6 7u83 422
	    ok |= dspec_inherit;
423
	    return (ok);
2 7u83 424
	}
6 7u83 425
	fr = DEREF_list(ctype_chums(cs));
426
	while (!IS_NULL_list(fr)) {
427
	    CLASS_TYPE cr = DEREF_ctype(HEAD_list(fr));
428
	    gr = find_base_class(cr, ct, 0);
429
	    if (!IS_NULL_graph(gr)) {
2 7u83 430
		/* Friend class of derived class */
6 7u83 431
		ok |= (dspec_inherit | dspec_friend);
432
		return (ok);
2 7u83 433
	    }
6 7u83 434
	    fr = TAIL_list(fr);
2 7u83 435
	}
436
    }
437
 
438
    /* Check for derived friend functions */
6 7u83 439
    if (IS_id_function_etc(id)) {
440
	LIST(CLASS_TYPE)fr;
441
	fr = DEREF_list(id_function_etc_chums(id));
442
	while (!IS_NULL_list(fr)) {
443
	    CLASS_TYPE cr = DEREF_ctype(HEAD_list(fr));
444
	    GRAPH gr = find_base_class(cr, ct, 0);
445
	    if (!IS_NULL_graph(gr)) {
2 7u83 446
		/* Friend function of derived class */
6 7u83 447
		ok |= (dspec_inherit | dspec_friend);
448
		return (ok);
2 7u83 449
	    }
6 7u83 450
	    fr = TAIL_list(fr);
2 7u83 451
	}
452
    }
453
 
454
    /* Default access */
6 7u83 455
    ok = (dspec_public | dspec_public2);
456
    return (ok);
2 7u83 457
}
458
 
459
 
460
/*
461
    COMPARE ACCESS LEVELS
462
 
463
    This routine checks whether the access level ok returned by find_access
464
    is sufficient to access a member of type tag with declaration specifiers
465
    ds.  It returns true if the access is an error.
466
*/
467
 
6 7u83 468
static int
469
compare_access(DECL_SPEC ok, DECL_SPEC ds, unsigned tag, int mem)
2 7u83 470
{
6 7u83 471
	int ret = 0;
472
	DECL_SPEC acc = (ds & dspec_access);
473
	DECL_SPEC level = (ok & dspec_access);
474
	if (level < acc) {
475
		/* Straightforward case */
476
		ret = 1;
477
	} else {
478
		/* Deal with inheritance */
479
		if (ds & dspec_inherit) {
480
			DECL_SPEC acc2 = (ds & dspec_access2);
481
			level = (ok & dspec_access2);
482
			if (level < acc2) {
483
				ret = 1;
484
			}
485
		}
2 7u83 486
	}
6 7u83 487
	if (!ret && !mem) {
488
		if (tag == id_member_tag || tag == id_mem_func_tag) {
489
			/* Check for access through derived class */
490
			if (ok & dspec_inherit) {
491
				ret = 1;
492
			}
493
		}
2 7u83 494
	}
6 7u83 495
	return (ret);
2 7u83 496
}
497
 
498
 
499
/*
500
    CAN AN INHERITED MEMBER BE ACCESSED?
501
 
502
    This routine checks whether the inherited class member pid can be
503
    accessed by the identifier id.  If so it returns true.  The direct
504
    cases, such as a member of a derived class accessing a member of a
505
    base class are handled by the main part of do_member_access, this
506
    routine deals with the indirect cases such as friends of classes
507
    intermediate between the base class and the derived class.
508
*/
509
 
6 7u83 510
static int
511
inherit_access(IDENTIFIER id, IDENTIFIER pid, int mem)
2 7u83 512
{
6 7u83 513
	/* Find inheritance base class */
514
	unsigned tag = TAG_id(pid);
515
	IDENTIFIER bid = DEREF_id(id_alias(pid));
516
	DECL_SPEC acc = DEREF_dspec(id_storage(bid));
517
	NAMESPACE pns = DEREF_nspace(id_parent(pid));
518
	NAMESPACE bns = DEREF_nspace(id_parent(bid));
519
	CLASS_TYPE ct = namespace_class(pns);
520
	CLASS_TYPE cs = namespace_class(bns);
521
	GRAPH gr = find_base_class(ct, cs, 0);
2 7u83 522
 
6 7u83 523
	/* Scan through all base classes of ct containing bid */
524
	while (!IS_NULL_graph(gr)) {
525
		GRAPH gs = gr;
526
		while (!IS_NULL_graph(gs)) {
527
			cs = DEREF_ctype(graph_head(gs));
528
			if (!eq_ctype(cs, ct)) {
529
				DECL_SPEC ds, ok;
530
				ds = DEREF_dspec(graph_access(gr));
531
				ds = join_access(acc, ds);
532
				bns = DEREF_nspace(ctype_member(cs));
533
				ok = find_access(&id, bns, ds, 2);
534
				if (ok & dspec_defn) {
535
					/* id is a member or friend of cs */
536
					if (!compare_access(ok, ds, tag, mem)) {
537
						/* Can access bid */
538
						return (1);
539
					}
540
				}
541
			}
542
			gs = DEREF_graph(graph_up(gs));
2 7u83 543
		}
6 7u83 544
		gr = DEREF_graph(graph_equal(gr));
2 7u83 545
	}
6 7u83 546
	return (0);
2 7u83 547
}
548
 
549
 
550
/*
551
    CHECK A MEMBER ACCESS
552
 
553
    This routine checks the access of the class member pid by the
554
    identifier id.  It prints an error and returns true if the access
555
    is illegal.
556
*/
557
 
6 7u83 558
static int
559
do_member_access(IDENTIFIER id, IDENTIFIER pid, int mem)
2 7u83 560
{
6 7u83 561
	int ret = 0;
562
	NAMESPACE pns = DEREF_nspace(id_parent(pid));
563
	DECL_SPEC ds = DEREF_dspec(id_storage(pid));
564
	DECL_SPEC acc = (ds & dspec_access);
565
	DECL_SPEC ok = find_access(&id, pns, acc, 0);
566
	if (compare_access(ok, ds, TAG_id(pid), mem)) {
567
		if ((ds & dspec_inherit) && inherit_access(id, pid, mem)) {
568
			/* Can access through inheritance */
569
			/* EMPTY */
570
		} else {
571
			/* Report access error */
572
			ERROR err;
573
			if (IS_NULL_id(id)) {
574
				err = ERR_class_access_spec_none(pid, acc);
575
			} else {
576
				err = ERR_class_access_spec_id(pid, acc, id);
577
			}
578
			report(crt_loc, err);
579
			ret = 1;
580
		}
2 7u83 581
	}
6 7u83 582
	return (ret);
2 7u83 583
}
584
 
585
 
586
/*
587
    CHECK A BASE CLASS ACCESS
588
 
589
    This routine checks the access of the base class gr by the
590
    identifier id.  It prints an error and returns true if the access
591
    is illegal.
592
*/
593
 
6 7u83 594
static int
595
do_base_access(IDENTIFIER id, GRAPH gr)
2 7u83 596
{
6 7u83 597
	int ret = 0;
598
	GRAPH gt = DEREF_graph(graph_top(gr));
599
	CLASS_TYPE ct = DEREF_ctype(graph_head(gt));
600
	NAMESPACE pns = DEREF_nspace(ctype_member(ct));
601
	DECL_SPEC ds = DEREF_dspec(graph_access(gr));
602
	DECL_SPEC acc = (ds & dspec_access);
603
	DECL_SPEC ok = find_access(&id, pns, acc, 1);
604
	if (compare_access(ok, ds, null_tag, 0)) {
605
		/* Report access error */
606
		ERROR err;
607
		CLASS_TYPE cs = DEREF_ctype(graph_head(gr));
608
		if (IS_NULL_id(id)) {
609
			err = ERR_class_access_base_none(cs, ct, acc);
610
		} else {
611
			err = ERR_class_access_base_id(cs, ct, acc, id);
612
		}
613
		err = concat_error(err, ERR_conv_ptr_access());
614
		report(crt_loc, err);
615
		ret = 1;
2 7u83 616
	}
6 7u83 617
	return (ret);
2 7u83 618
}
619
 
620
 
621
/*
622
    CLEAR A LIST OF PENDING IDENTIFIER ACCESS CHECKS
623
 
624
    This routine clears the list of pending access checks given by p in
625
    the context given by the identifier id.  It returns true if any
626
    results in an error.
627
*/
628
 
6 7u83 629
static int
630
clear_id_access(IDENTIFIER id, LIST(IDENTIFIER)p, LIST(int)r)
2 7u83 631
{
6 7u83 632
	int ret = 0;
633
	if (!IS_NULL_list(p)) {
634
		int mem = DEREF_int(HEAD_list(r));
635
		IDENTIFIER pid = DEREF_id(HEAD_list(p));
636
		ret = clear_id_access(id, TAIL_list(p), TAIL_list(r));
637
		if (!IS_NULL_id(pid) && do_member_access(id, pid, mem)) {
638
			COPY_id(HEAD_list(p), NULL_id);
639
			ret = 1;
640
		}
2 7u83 641
	}
6 7u83 642
	return (ret);
2 7u83 643
}
644
 
645
 
646
/*
647
    CLEAR A LIST OF PENDING BASE CLASS ACCESS CHECKS
648
 
649
    This routine clears the list of pending base class access checks given
650
    by p in the context given by the identifier id.  It returns true if
651
    any results in an error.
652
*/
653
 
6 7u83 654
static int
655
clear_base_access(IDENTIFIER id, LIST(GRAPH)p)
2 7u83 656
{
6 7u83 657
	int ret = 0;
658
	if (!IS_NULL_list(p)) {
659
		GRAPH gr = DEREF_graph(HEAD_list(p));
660
		ret = clear_base_access(id, TAIL_list(p));
661
		if (!IS_NULL_graph(gr) && do_base_access(id, gr)) {
662
			COPY_graph(HEAD_list(p), NULL_graph);
663
			ret = 1;
664
		}
2 7u83 665
	}
6 7u83 666
	return (ret);
2 7u83 667
}
668
 
669
 
670
/*
671
    CLEAR A LIST OF PENDING ACCESS CHECKS
672
 
673
    This routine clears the list of pending access checks given by acc in
674
    the context given by the identifier id.  It returns true if any
675
    results in an error.
676
*/
677
 
6 7u83 678
int
679
clear_access(IDENTIFIER id, ACCESS_LIST *acc)
2 7u83 680
{
6 7u83 681
	int ret = 0;
682
	if (acc->pending) {
683
		LIST(IDENTIFIER)p = acc->ids;
684
		LIST(GRAPH)q = acc->bases;
685
		LIST(int)r = acc->info;
686
		if (!IS_NULL_list(p) && clear_id_access(id, p, r)) {
687
			ret = 1;
688
		}
689
		if (!IS_NULL_list(q) && clear_base_access(id, q)) {
690
			ret = 1;
691
		}
692
	}
693
	return (ret);
2 7u83 694
}
695
 
696
 
697
/*
698
    CLEAR THE LIST OF CURRENT ACCESSES
699
 
700
    This routine clears all outstanding accesses in the scope given by id.
701
    It returns true if any results in an error.
702
*/
703
 
6 7u83 704
int
705
report_access(IDENTIFIER id)
2 7u83 706
{
6 7u83 707
	ACCESS_LIST *acc = &crt_access_list;
708
	int ret = clear_access(id, acc);
709
	free_access(acc);
710
	return (ret);
2 7u83 711
}
712
 
713
 
714
/*
715
    FREE AN ACCESS LIST
716
 
717
    This routine frees the list of accesses given by acc.
718
*/
719
 
6 7u83 720
void
721
free_access(ACCESS_LIST *acc)
2 7u83 722
{
6 7u83 723
	LIST(IDENTIFIER)p = acc->ids;
724
	LIST(GRAPH)q = acc->bases;
725
	LIST(int)r = acc->info;
726
	if (!IS_NULL_list(p)) {
727
		DESTROY_list(p, SIZE_id);
728
		acc->ids = NULL_list(IDENTIFIER);
729
	}
730
	if (!IS_NULL_list(q)) {
731
		DESTROY_list(q, SIZE_graph);
732
		acc->bases = NULL_list(GRAPH);
733
	}
734
	if (!IS_NULL_list(r)) {
735
		DESTROY_list(r, SIZE_int);
736
		acc->info = NULL_list(int);
737
	}
738
	acc->pending = 0;
739
	acc->inherit = 0;
740
	return;
2 7u83 741
}
742
 
743
 
744
/*
745
    SAVE AN ACCESS LIST
746
 
747
    This routine saves the current access list into acc and clears the
748
    list.
749
*/
750
 
6 7u83 751
void
752
save_access(ACCESS_LIST *acc)
2 7u83 753
{
6 7u83 754
	ACCESS_LIST *crt = &crt_access_list;
755
	acc->ids = crt->ids;
756
	acc->bases = crt->bases;
757
	acc->info = crt->info;
758
	acc->pending = crt->pending;
759
	acc->inherit = crt->inherit;
760
	crt->ids = NULL_list(IDENTIFIER);
761
	crt->bases = NULL_list(GRAPH);
762
	crt->info = NULL_list(int);
763
	crt->pending = 0;
764
	crt->inherit = 0;
765
	return;
2 7u83 766
}
767
 
768
 
769
/*
770
    RESTORE AN ACCESS LIST
771
 
772
    This routine clears the current access list in the scope given by
773
    id and resets the current access list the values stored in acc.
774
*/
775
 
6 7u83 776
int
777
restore_access(IDENTIFIER id, ACCESS_LIST *acc)
2 7u83 778
{
6 7u83 779
	int ret = report_access(id);
780
	ACCESS_LIST *crt = &crt_access_list;
781
	crt->ids = acc->ids;
782
	crt->bases = acc->bases;
783
	crt->info = acc->info;
784
	crt->pending = acc->pending;
785
	crt->inherit = acc->inherit;
786
	return (ret);
2 7u83 787
}
788
 
789
 
790
/*
791
    CHECK THE ACCESS TO AN IDENTIFIER
792
 
793
    This routine adds the identifier id with access acc to the list of
794
    pending access checks.  acc will always be dspec_public, dspec_protected
795
    or dspec_private.
796
*/
797
 
6 7u83 798
void
799
check_access(IDENTIFIER id, DECL_SPEC acc)
2 7u83 800
{
6 7u83 801
	if (acc == dspec_public) {
802
		return;
2 7u83 803
	}
6 7u83 804
	if (do_access_checks) {
805
		NAMESPACE ns = DEREF_nspace(id_parent(id));
806
		if (IS_nspace_ctype(ns)) {
807
			ACCESS_LIST *crt = &crt_access_list;
808
			if (in_function_defn && !in_declaration) {
809
				/* Calculate access immediately */
810
				IGNORE do_member_access(crt_func_id, id,
811
							crt->inherit);
812
			} else {
813
				/* Add to pending list */
814
				CONS_id(id, crt->ids, crt->ids);
815
				CONS_int(crt->inherit, crt->info, crt->info);
816
				crt->pending = 1;
817
			}
818
		} else {
819
			DECL_SPEC ds = DEREF_dspec(id_storage(id));
820
			if (ds & dspec_auto) {
821
				/* Used to mark for-init variables */
822
				report(crt_loc, ERR_stmt_for_init(id));
823
				ds &= ~dspec_access;
824
				COPY_dspec(id_storage(id), ds);
825
			}
826
		}
827
	}
828
	return;
2 7u83 829
}
830
 
831
 
832
/*
833
    CHECK THE ACCESS TO A BASE CLASS
834
 
835
    This routine adds the base class graph gr to the list of pending
836
    base access checks.
837
*/
838
 
6 7u83 839
void
840
check_base_access(GRAPH gr)
2 7u83 841
{
6 7u83 842
	DECL_SPEC ds = DEREF_dspec(graph_access(gr));
843
	DECL_SPEC acc = (ds & dspec_access);
844
	DECL_SPEC acc2 = (ds & dspec_access2);
845
	if (acc == dspec_public) {
846
		return;
2 7u83 847
	}
848
 
6 7u83 849
	if (do_access_checks) {
850
		/* Find best access to a virtual base */
851
		GRAPH gs = DEREF_graph(graph_equal(gr));
852
		while (!IS_NULL_graph(gs)) {
853
			DECL_SPEC pds = DEREF_dspec(graph_access(gs));
854
			DECL_SPEC pacc = (pds & dspec_access);
855
			DECL_SPEC pacc2 = (pds & dspec_access2);
856
			if (pacc == dspec_public) {
857
				return;
858
			}
859
			if (pacc < acc || (pacc == acc && pacc2 < acc2)) {
860
				acc = pacc;
861
				acc2 = pacc2;
862
				gr = gs;
863
			}
864
			gs = DEREF_graph(graph_equal(gs));
865
		}
866
 
867
		/* Check access control */
868
		if (in_function_defn && !in_declaration) {
869
			/* Calculate access immediately */
870
			IGNORE do_base_access(crt_func_id, gr);
871
		} else {
872
			/* Add to pending list */
873
			ACCESS_LIST *crt = &crt_access_list;
874
			CONS_graph(gr, crt->bases, crt->bases);
875
			crt->pending = 1;
876
		}
2 7u83 877
	}
6 7u83 878
	return;
2 7u83 879
}
880
 
881
 
882
/*
883
    IMMEDIATELY CHECK THE ACCESS TO AN IDENTIFIER
884
 
885
    This routine applies an immediate access check to the identifier id
886
    by cid.
887
*/
888
 
6 7u83 889
void
890
immediate_access(IDENTIFIER cid, IDENTIFIER id)
2 7u83 891
{
6 7u83 892
	DECL_SPEC acc = DEREF_dspec(id_storage(id));
893
	acc &= dspec_access;
894
	if (acc == dspec_none || acc == dspec_public) {
895
		return;
2 7u83 896
	}
6 7u83 897
	if (do_access_checks) {
898
		NAMESPACE ns = DEREF_nspace(id_parent(id));
899
		if (IS_nspace_ctype(ns)) {
900
			int mem = crt_access_list.inherit;
901
			IGNORE do_member_access(cid, id, mem);
902
		}
903
	}
904
	return;
2 7u83 905
}