Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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