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 "member_ops.h"
37
#include "nspace_ops.h"
38
#include "type_ops.h"
39
#include "error.h"
40
#include "catalog.h"
41
#include "access.h"
42
#include "chktype.h"
43
#include "class.h"
44
#include "declare.h"
45
#include "initialise.h"
46
#include "merge.h"
47
#include "namespace.h"
48
#include "redeclare.h"
49
#include "token.h"
50
 
51
 
52
/*
53
    NAME MERGING FLAG
54
 
55
    This flag is set to true to indicate that name merging is taking
56
    place.
57
*/
58
 
59
int force_merge = 0 ;
60
 
61
 
62
/*
63
    ARE TWO CLASSES LAYOUT COMPATIBLE?
64
 
65
    This routine checks whether the classes ct and cs are layout compatible,
66
    i.e. they have the same member types and accesses.
67
*/
68
 
69
int compatible_class
70
    PROTO_N ( ( ct, cs ) )
71
    PROTO_T ( CLASS_TYPE ct X CLASS_TYPE cs )
72
{
73
    GRAPH gt, gs ;
74
    MEMBER mt, ms ;
75
    BASE_TYPE kt, ks ;
76
    NAMESPACE nt, ns ;
77
    LIST ( GRAPH ) bt, bs ;
78
 
79
    /* Check for obvious equality */
80
    if ( eq_ctype ( ct, cs ) ) return ( 1 ) ;
81
 
82
    /* Check class keys */
83
    kt = find_class_key ( ct ) ;
84
    ks = find_class_key ( cs ) ;
85
    if ( !equal_key ( kt, ks ) ) return ( 0 ) ;
86
 
87
    /* Check base classes */
88
    gt = DEREF_graph ( ctype_base ( ct ) ) ;
89
    gs = DEREF_graph ( ctype_base ( cs ) ) ;
90
    bt = DEREF_list ( graph_tails ( gt ) ) ;
91
    bs = DEREF_list ( graph_tails ( gs ) ) ;
92
    while ( !IS_NULL_list ( bt ) && !IS_NULL_list ( bs ) ) {
93
	GRAPH ht = DEREF_graph ( HEAD_list ( bt ) ) ;
94
	GRAPH hs = DEREF_graph ( HEAD_list ( bs ) ) ;
95
	CLASS_TYPE pt = DEREF_ctype ( graph_head ( ht ) ) ;
96
	CLASS_TYPE ps = DEREF_ctype ( graph_head ( hs ) ) ;
97
	DECL_SPEC at = DEREF_dspec ( graph_access ( ht ) ) ;
98
	DECL_SPEC as = DEREF_dspec ( graph_access ( hs ) ) ;
99
	at &= ( dspec_access | dspec_virtual ) ;
100
	as &= ( dspec_access | dspec_virtual ) ;
101
	if ( at != as ) return ( 0 ) ;
102
	if ( !compatible_class ( pt, ps ) ) return ( 0 ) ;
103
	bs = TAIL_list ( bs ) ;
104
	bt = TAIL_list ( bt ) ;
105
    }
106
    if ( !EQ_list ( bt, bs ) ) return ( 0 ) ;
107
 
108
    /* Check class members */
109
    nt = DEREF_nspace ( ctype_member ( ct ) ) ;
110
    mt = DEREF_member ( nspace_ctype_first ( nt ) ) ;
111
    mt = next_data_member ( mt, 1 ) ;
112
    ns = DEREF_nspace ( ctype_member ( cs ) ) ;
113
    ms = DEREF_member ( nspace_ctype_first ( ns ) ) ;
114
    ms = next_data_member ( ms, 1 ) ;
115
    while ( !IS_NULL_member ( mt ) && !IS_NULL_member ( ms ) ) {
116
	IDENTIFIER it = DEREF_id ( member_id ( mt ) ) ;
117
	IDENTIFIER is = DEREF_id ( member_id ( ms ) ) ;
118
	TYPE t = DEREF_type ( id_member_type ( it ) ) ;
119
	TYPE s = DEREF_type ( id_member_type ( is ) ) ;
120
	DECL_SPEC at = DEREF_dspec ( id_storage ( it ) ) ;
121
	DECL_SPEC as = DEREF_dspec ( id_storage ( is ) ) ;
122
	at &= dspec_access ;
123
	as &= dspec_access ;
124
	if ( at != as ) return ( 0 ) ;
125
	if ( !eq_type ( t, s ) ) return ( 0 ) ;
126
	ms = DEREF_member ( member_next ( ms ) ) ;
127
	ms = next_data_member ( ms, 1 ) ;
128
	mt = DEREF_member ( member_next ( mt ) ) ;
129
	mt = next_data_member ( mt, 1 ) ;
130
    }
131
    if ( !EQ_member ( mt, ms ) ) return ( 0 ) ;
132
    return ( 1 ) ;
133
}
134
 
135
 
136
/*
137
    ARE TWO TYPES TO BE MERGED?
138
 
139
    This routine checks whether the identifiers tid and sid are to be made
140
    equal by merge_id.  This essentially means that they should be the
141
    same.
142
*/
143
 
144
int merge_type
145
    PROTO_N ( ( tid, sid ) )
146
    PROTO_T ( IDENTIFIER tid X IDENTIFIER sid )
147
{
148
    while ( !EQ_id ( tid, sid ) ) {
149
	unsigned tt, ts ;
150
	HASHID tnm, snm ;
151
	NAMESPACE nt, ns ;
152
 
153
	/* Check identifiers */
154
	if ( IS_NULL_id ( tid ) ) return ( 0 ) ;
155
	if ( IS_NULL_id ( sid ) ) return ( 0 ) ;
156
	tt = TAG_id ( tid ) ;
157
	ts = TAG_id ( sid ) ;
158
	if ( tt != ts ) return ( 0 ) ;
159
 
160
	/* Check identifier names */
161
	tnm = DEREF_hashid ( id_name ( tid ) ) ;
162
	snm = DEREF_hashid ( id_name ( sid ) ) ;
163
	if ( !EQ_hashid ( tnm, snm ) ) return ( 0 ) ;
164
 
165
	/* Check identifier namespaces */
166
	nt = DEREF_nspace ( id_parent ( tid ) ) ;
167
	ns = DEREF_nspace ( id_parent ( sid ) ) ;
168
	if ( EQ_nspace ( nt, ns ) ) return ( 1 ) ;
169
	if ( IS_NULL_nspace ( nt ) ) return ( 0 ) ;
170
	if ( IS_NULL_nspace ( ns ) ) return ( 0 ) ;
171
	tt = TAG_nspace ( nt ) ;
172
	ts = TAG_nspace ( ns ) ;
173
	if ( tt != ts ) return ( 0 ) ;
174
	switch ( tt ) {
175
	    case nspace_global_tag : {
176
		return ( 1 ) ;
177
	    }
178
	    case nspace_ctype_tag :
179
	    case nspace_named_tag :
180
	    case nspace_unnamed_tag : {
181
		break ;
182
	    }
183
	    default : {
184
		return ( 0 ) ;
185
	    }
186
	}
187
	tid = DEREF_id ( nspace_name ( nt ) ) ;
188
	sid = DEREF_id ( nspace_name ( ns ) ) ;
189
    }
190
    return ( 1 ) ;
191
}
192
 
193
 
194
/*
195
    CHECK FOR CONSISTENT REDEFINITION
196
 
197
    This routine checks whether the definitions of the objects pid and
198
    qid and consistent.
199
*/
200
 
201
static int consistent_redef
202
    PROTO_N ( ( pid, qid ) )
203
    PROTO_T ( IDENTIFIER pid X IDENTIFIER qid )
204
{
205
    int ok = 1 ;
206
    switch ( TAG_id ( pid ) ) {
207
	case id_nspace_name_tag : {
208
	    /* Merge namespace definitions */
209
	    NAMESPACE pns = DEREF_nspace ( id_nspace_name_defn ( pid ) ) ;
210
	    NAMESPACE qns = DEREF_nspace ( id_nspace_name_defn ( qid ) ) ;
211
	    if ( IS_nspace_named ( pns ) ) {
212
		COPY_nspace ( id_nspace_name_defn ( pid ), qns ) ;
213
		merge_namespaces ( qns, pns ) ;
214
	    } else {
215
		merge_namespaces ( NULL_nspace, pns ) ;
216
	    }
217
	    break ;
218
	}
219
	case id_class_name_tag : {
220
	    BASE_TYPE bt, bs ;
221
	    CLASS_TYPE ct, cs ;
222
	    NAMESPACE pns, qns ;
223
	    TYPE t = DEREF_type ( id_class_name_defn ( pid ) ) ;
224
	    TYPE s = DEREF_type ( id_class_name_defn ( qid ) ) ;
225
	    while ( IS_type_templ ( t ) ) {
226
		t = DEREF_type ( type_templ_defn ( t ) ) ;
227
	    }
228
	    ct = DEREF_ctype ( type_compound_defn ( t ) ) ;
229
	    bt = find_class_key ( ct ) ;
230
	    pns = DEREF_nspace ( ctype_member ( ct ) ) ;
231
	    while ( IS_type_templ ( s ) ) {
232
		s = DEREF_type ( type_templ_defn ( s ) ) ;
233
	    }
234
	    cs = DEREF_ctype ( type_compound_defn ( s ) ) ;
235
	    bs = find_class_key ( cs ) ;
236
	    qns = DEREF_nspace ( ctype_member ( cs ) ) ;
237
	    COPY_nspace ( ctype_member ( ct ), qns ) ;
238
	    if ( !equal_key ( bt, bs ) ) {
239
		/* Inconsistent key */
240
		PTR ( LOCATION ) loc = id_loc ( qid ) ;
241
		ERROR err = ERR_dcl_type_elab_bad ( bt, bs, qid, loc ) ;
242
		report ( crt_loc, err ) ;
243
	    }
244
	    merge_namespaces ( qns, pns ) ;
245
	    break ;
246
	}
247
	case id_variable_tag :
248
	case id_stat_member_tag : {
249
	    ok = 0 ;
250
	    break ;
251
	}
252
    }
253
    return ( ok ) ;
254
}
255
 
256
 
257
/*
258
    EXPAND AN IDENTIFIER
259
 
260
    This routine expands the identifier id read from a spec input file.
261
    This is necessary because id may still contain pending identifiers.
262
*/
263
 
264
static void expand_id
265
    PROTO_N ( ( id ) )
266
    PROTO_T ( IDENTIFIER id )
267
{
268
    DEREF_loc ( id_loc ( id ), crt_loc ) ;
269
    decl_loc = crt_loc ;
270
    return ;
271
}
272
 
273
 
274
/*
275
    DECLARATION SPECIFIER MASK
276
 
277
    The macro dspec_mask is a mask which gives those declaration specifiers
278
    which should be the same for all declarations.
279
*/
280
 
281
#define dspec_mem_func\
282
    ( dspec_virtual | dspec_pure | dspec_explicit | dspec_implicit )
283
 
284
#define dspec_mask\
285
    ( dspec_storage | dspec_access | dspec_language | dspec_mem_func )
286
 
287
 
288
/*
289
    MERGE AN IDENTIFIER INTO A NAMESPACE
290
 
291
    This routine merges the identifier id read from a spec input file
292
    into the namespace ns.
293
*/
294
 
295
static void merge_id
296
    PROTO_N ( ( ns, id ) )
297
    PROTO_T ( NAMESPACE ns X IDENTIFIER id )
298
{
299
    int type ;
300
    HASHID nm ;
301
    MEMBER mem ;
302
    IDENTIFIER pid ;
303
 
304
    /* Allow for overloaded functions */
305
    if ( IS_id_function_etc ( id ) ) {
306
	IDENTIFIER over = DEREF_id ( id_function_etc_over ( id ) ) ;
307
	if ( !IS_NULL_id ( over ) ) merge_id ( ns, over ) ;
308
    }
309
 
310
    /* Find previous declaration */
311
    expand_id ( id ) ;
312
    if ( IS_NULL_nspace ( ns ) ) return ;
313
    nm = DEREF_hashid ( id_name ( id ) ) ;
314
    mem = search_member ( ns, nm, 1 ) ;
315
    if ( is_tagged_type ( id ) ) {
316
	pid = type_member ( mem, 3 ) ;
317
	type = 1 ;
318
    } else {
319
	pid = DEREF_id ( member_id ( mem ) ) ;
320
	type = 0 ;
321
    }
322
 
323
    /* Check previous declaration */
324
    if ( !IS_NULL_id ( pid ) ) {
325
	unsigned tag = TAG_id ( id ) ;
326
	unsigned ptag = TAG_id ( pid ) ;
327
	if ( tag == id_stat_mem_func_tag ) tag = id_mem_func_tag ;
328
	if ( ptag == id_stat_mem_func_tag ) ptag = id_mem_func_tag ;
329
	if ( tag == ptag ) {
330
	    int ok = 1 ;
331
	    DECL_SPEC ds = DEREF_dspec ( id_storage ( id ) ) ;
332
	    DECL_SPEC pds = DEREF_dspec ( id_storage ( pid ) ) ;
333
	    PTR ( TYPE ) pt = NULL_ptr ( TYPE ) ;
334
	    PTR ( TYPE ) ps = NULL_ptr ( TYPE ) ;
335
	    switch ( tag ) {
336
		case id_class_name_tag :
337
		case id_enum_name_tag :
338
		case id_class_alias_tag :
339
		case id_enum_alias_tag :
340
		case id_type_alias_tag : {
341
		    pt = id_class_name_etc_defn ( id ) ;
342
		    ps = id_class_name_etc_defn ( pid ) ;
343
		    break ;
344
		}
345
		case id_variable_tag :
346
		case id_parameter_tag :
347
		case id_stat_member_tag : {
348
		    pt = id_variable_etc_type ( id ) ;
349
		    ps = id_variable_etc_type ( pid ) ;
350
		    break ;
351
		}
352
#if 0
353
		case id_function_tag :
354
		case id_mem_func_tag :
355
		case id_stat_mem_func_tag : {
356
		    /* NOT YET IMPLEMENTED - function overloading */
357
		    pt = id_function_etc_type ( id ) ;
358
		    ps = id_function_etc_type ( pid ) ;
359
		    break ;
360
		}
361
#endif
362
		case id_member_tag : {
363
		    pt = id_member_type ( id ) ;
364
		    ps = id_member_type ( pid ) ;
365
		    break ;
366
		}
367
		case id_enumerator_tag : {
368
		    pt = id_enumerator_etype ( id ) ;
369
		    ps = id_enumerator_etype ( pid ) ;
370
		    break ;
371
		}
372
	    }
373
 
374
	    /* Check type compatibility */
375
	    if ( !IS_NULL_ptr ( pt ) && !IS_NULL_ptr ( ps ) ) {
376
		ERROR err = NULL_err ;
377
		TYPE t = DEREF_type ( pt ) ;
378
		TYPE s = DEREF_type ( ps ) ;
379
		t = expand_type ( t, 1 ) ;
380
		s = expand_type ( s, 1 ) ;
381
		s = check_compatible ( s, t, 0, &err, 1 ) ;
382
		if ( !IS_NULL_err ( err ) ) {
383
		    /* Incompatible declaration */
384
		    PTR ( LOCATION ) ploc = id_loc ( pid ) ;
385
		    ERROR err2 = ERR_basic_link_decl_type ( pid, ploc ) ;
386
		    err = concat_error ( err, err2 ) ;
387
		    report ( crt_loc, err ) ;
388
		    ok = 0 ;
389
		} else {
390
		    COPY_type ( pt, t ) ;
391
		    COPY_type ( ps, s ) ;
392
		}
393
	    }
394
 
395
	    /* Check declaration specifiers */
396
	    if ( ok && ( ds & dspec_mask ) != ( pds & dspec_mask ) ) {
397
		PTR ( LOCATION ) ploc = id_loc ( pid ) ;
398
		DECL_SPEC st = ( ds & dspec_storage ) ;
399
		DECL_SPEC pst = ( pds & dspec_storage ) ;
400
		if ( st != pst ) {
401
		    /* Inconsistent linkage */
402
		    ERROR err ;
403
		    if ( pst & dspec_static ) {
404
			err = ERR_dcl_stc_internal ( pid, ploc ) ;
405
		    } else {
406
			err = ERR_dcl_stc_external ( pid, ploc ) ;
407
		    }
408
		    report ( crt_loc, err ) ;
409
		}
410
		st = ( ds & dspec_access ) ;
411
		pst = ( pds & dspec_access ) ;
412
		if ( st != pst ) {
413
		    /* Adjust access */
414
		    adjust_access ( pid, st, 0 ) ;
415
		}
416
		st = ( ds & dspec_language ) ;
417
		pst = ( pds & dspec_language ) ;
418
		if ( st != pst ) {
419
		    /* Inconsistent language */
420
		    string lang = linkage_string ( pst, cv_none ) ;
421
		    ERROR err = ERR_dcl_link_lang ( pid, lang, ploc ) ;
422
		    report ( crt_loc, err ) ;
423
		}
424
		st = ( ds & dspec_mem_func ) ;
425
		pst = ( pds & dspec_mem_func ) ;
426
		if ( st != pst ) {
427
		    /* NOT YET IMPLEMENTED */
428
		    /* EMPTY */
429
		}
430
	    }
431
 
432
	    /* Check for multiple definitions */
433
	    if ( pds & dspec_defn ) {
434
		if ( ds & dspec_defn ) {
435
		    if ( !consistent_redef ( id, pid ) && ok ) {
436
			PTR ( LOCATION ) ploc = id_loc ( pid ) ;
437
			report ( crt_loc, ERR_basic_odr_def ( pid, ploc ) ) ;
438
		    }
439
		} else {
440
		    id = pid ;
441
		}
442
	    }
443
 
444
	} else {
445
	    /* Redeclared as different type of object */
446
	    PTR ( LOCATION ) ploc = id_loc ( pid ) ;
447
	    report ( crt_loc, ERR_basic_odr_diff ( pid, ploc ) ) ;
448
	}
449
    }
450
 
451
    /* Set member */
452
    COPY_nspace ( id_parent ( id ), ns ) ;
453
    if ( type ) {
454
	set_type_member ( mem, id ) ;
455
    } else {
456
	set_member ( mem, id ) ;
457
    }
458
    return ;
459
}
460
 
461
 
462
/*
463
    MERGE TWO NAMESPACES
464
 
465
    This routine merges the namespace ns with the additional members
466
    read from a spec input file given by pns.
467
*/
468
 
469
void merge_namespaces
470
    PROTO_N ( ( ns, pns ) )
471
    PROTO_T ( NAMESPACE ns X NAMESPACE pns )
472
{
473
    MEMBER mem = DEREF_member ( nspace_named_etc_first ( pns ) ) ;
474
    LIST ( IDENTIFIER ) ids = DEREF_list ( nspace_named_etc_extra ( pns ) ) ;
475
    force_merge++ ;
476
    while ( !IS_NULL_member ( mem ) ) {
477
	IDENTIFIER id = DEREF_id ( member_id ( mem ) ) ;
478
	IDENTIFIER alt = DEREF_id ( member_alt ( mem ) ) ;
479
	if ( !IS_NULL_id ( id ) ) {
480
	    merge_id ( ns, id ) ;
481
	}
482
	if ( !IS_NULL_id ( alt ) && !EQ_id ( id, alt ) ) {
483
	    merge_id ( ns, alt ) ;
484
	}
485
	mem = DEREF_member ( member_next ( mem ) ) ;
486
    }
487
    while ( !IS_NULL_list ( ids ) ) {
488
	IDENTIFIER id = DEREF_id ( HEAD_list ( ids ) ) ;
489
	expand_id ( id ) ;
490
	ids = TAIL_list ( ids ) ;
491
    }
492
    force_merge-- ;
493
    return ;
494
}