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 "exp_ops.h"
34
#include "hashid_ops.h"
35
#include "id_ops.h"
36
#include "tok_ops.h"
37
#include "type_ops.h"
38
#include "error.h"
39
#include "catalog.h"
40
#include "option.h"
41
#include "allocate.h"
42
#include "basetype.h"
43
#include "cast.h"
44
#include "chktype.h"
45
#include "class.h"
46
#include "construct.h"
47
#include "convert.h"
48
#include "declare.h"
49
#include "derive.h"
50
#include "destroy.h"
51
#include "exception.h"
52
#include "expression.h"
53
#include "file.h"
54
#include "function.h"
55
#include "hash.h"
56
#include "identifier.h"
57
#include "initialise.h"
58
#include "label.h"
59
#include "namespace.h"
60
#include "predict.h"
61
#include "redeclare.h"
62
#include "statement.h"
63
#include "syntax.h"
64
#include "template.h"
65
#include "tokdef.h"
66
#include "typeid.h"
67
 
68
 
69
/*
70
    THE SET OF ALL TYPES
71
 
72
    The dummy list univ_type_set is used to represent the set of all
73
    types.  These sets of types are used to represent exception
74
    specifications for functions.  The list empty_type_set is used to
75
    give the exception specification for a function when none is given,
76
    by default it equals univ_type_set.
77
*/
78
 
79
LIST ( TYPE ) univ_type_set = NULL_list ( TYPE ) ;
80
LIST ( TYPE ) empty_type_set = NULL_list ( TYPE ) ;
81
 
82
 
83
/*
84
    INITIALISE THE SET OF ALL TYPES
85
 
86
    This routine initialises the set of all types to a dummy unique list.
87
*/
88
 
89
void init_exception
90
    PROTO_Z ()
91
{
92
    LIST ( TYPE ) p ;
93
    CONS_type ( type_any, NULL_list ( TYPE ), p ) ;
94
    p = uniq_type_set ( p ) ;
95
    COPY_list ( type_func_except ( type_func_void ), p ) ;
96
    COPY_list ( type_func_except ( type_temp_func ), p ) ;
97
    empty_type_set = p ;
98
    univ_type_set = p ;
99
    return ;
100
}
101
 
102
 
103
/*
104
    IS A TYPE IN A SET OF TYPES?
105
 
106
    This routine checks whether the type t is an element of the set of
107
    types listed as p.
108
*/
109
 
110
int in_type_set
111
    PROTO_N ( ( p, t ) )
112
    PROTO_T ( LIST ( TYPE ) p X TYPE t )
113
{
114
    if ( EQ_list ( p, univ_type_set ) ) return ( 1 ) ;
115
    expand_tokdef++ ;
116
    while ( !IS_NULL_list ( p ) ) {
117
	TYPE s = DEREF_type ( HEAD_list ( p ) ) ;
118
	if ( EQ_type ( t, s ) || eq_type_unqual ( t, s ) ) {
119
	    expand_tokdef-- ;
120
	    return ( 1 ) ;
121
	}
122
	p = TAIL_list ( p ) ;
123
    }
124
    expand_tokdef-- ;
125
    return ( 0 ) ;
126
}
127
 
128
 
129
/*
130
    IS A TYPE DERIVABLE FROM A SET OF TYPES?
131
 
132
    This routine checks whether an exception of type t will be caught by
133
    an element of the set of types listed as p.  It returns the catching
134
    type, or the null type if no match is found.
135
*/
136
 
137
static TYPE from_type_set
138
    PROTO_N ( ( p, t ) )
139
    PROTO_T ( LIST ( TYPE ) p X TYPE t )
140
{
141
    if ( EQ_list ( p, univ_type_set ) ) {
142
	/* The universal set catches everything */
143
	return ( t ) ;
144
    }
145
    expand_tokdef++ ;
146
    if ( IS_type_ref ( t ) ) t = DEREF_type ( type_ref_sub ( t ) ) ;
147
    while ( !IS_NULL_list ( p ) ) {
148
	TYPE r = DEREF_type ( HEAD_list ( p ) ) ;
149
	if ( !IS_NULL_type ( r ) ) {
150
	    TYPE s = r ;
151
	    unsigned rank ;
152
	    CONVERSION conv ;
153
	    if ( IS_type_ref ( s ) ) s = DEREF_type ( type_ref_sub ( s ) ) ;
154
	    if ( eq_type_unqual ( t, s ) ) {
155
		/* Exact match is allowed */
156
		expand_tokdef-- ;
157
		return ( r ) ;
158
	    }
159
	    conv.from = t ;
160
	    conv.to = s ;
161
	    rank = std_convert_seq ( &conv, NULL_exp, 0, 0 ) ;
162
	    switch ( rank ) {
163
		case CONV_EXACT :
164
		case CONV_QUAL :
165
		case CONV_BASE :
166
		case CONV_PTR_BASE :
167
		case CONV_PTR_VOID :
168
		case CONV_PTR_BOTTOM : {
169
		    /* These conversions are allowed */
170
		    expand_tokdef-- ;
171
		    return ( r ) ;
172
		}
173
	    }
174
	}
175
	p = TAIL_list ( p ) ;
176
    }
177
    expand_tokdef-- ;
178
    return ( NULL_type ) ;
179
}
180
 
181
 
182
/*
183
    ARE TWO TYPE SETS EQUAL?
184
 
185
    This routine checks whether the sets of types listed as p and q are
186
    equal.  It returns 2 if they are equal, 1 if p is a subset of q, and
187
 
188
    duplicate elements a fair amount can be deduced from the cardinalities
189
    of the sets, also the search is optimised if the types are given in
190
    the same order in each set.  If eq is true then only equality is
191
    checked for.
192
*/
193
 
194
int eq_type_set
195
    PROTO_N ( ( p, q, eq ) )
196
    PROTO_T ( LIST ( TYPE ) p X LIST ( TYPE ) q X int eq )
197
{
198
    unsigned n, m ;
199
    LIST ( TYPE ) r ;
200
 
201
    /* Deal with the set of all types */
202
    if ( EQ_list ( p, q ) ) return ( 2 ) ;
203
    if ( EQ_list ( q, univ_type_set ) && !eq ) return ( 1 ) ;
204
    if ( EQ_list ( p, univ_type_set ) ) return ( 0 ) ;
205
 
206
    /* Check whether p is larger than q */
207
    n = LENGTH_list ( p ) ;
208
    m = LENGTH_list ( q ) ;
209
    if ( n > m ) return ( 0 ) ;
210
    if ( n < m && eq ) return ( 0 ) ;
211
 
212
    /* Check whether p is a subset of q */
213
    r = q ;
214
    while ( !IS_NULL_list ( p ) ) {
215
	TYPE t = DEREF_type ( HEAD_list ( p ) ) ;
216
	TYPE s = DEREF_type ( HEAD_list ( r ) ) ;
217
	if ( !EQ_type ( t, s ) && !eq_type_unqual ( t, s ) ) {
218
	    if ( !in_type_set ( q, t ) ) return ( 0 ) ;
219
	}
220
	r = TAIL_list ( r ) ;
221
	p = TAIL_list ( p ) ;
222
    }
223
 
224
    /* Check for equality using set sizes */
225
    if ( n < m ) return ( 1 ) ;
226
    return ( 2 ) ;
227
}
228
 
229
 
230
/*
231
    ADD AN ELEMENT TO A TYPE SET
232
 
233
    This routine adds the type t to the type set p if it is not already
234
    a member.
235
*/
236
 
237
LIST ( TYPE ) cons_type_set
238
    PROTO_N ( ( p, t ) )
239
    PROTO_T ( LIST ( TYPE ) p X TYPE t )
240
{
241
    if ( !IS_NULL_type ( t ) && !in_type_set ( p, t ) ) {
242
	CONS_type ( t, p, p ) ;
243
    }
244
    return ( p ) ;
245
}
246
 
247
 
248
/*
249
    FIND THE UNION OF TWO TYPE SETS
250
 
251
    This routine adds the elements of the type set q to the type set p.
252
*/
253
 
254
LIST ( TYPE ) union_type_set
255
    PROTO_N ( ( p, q ) )
256
    PROTO_T ( LIST ( TYPE ) p X LIST ( TYPE ) q )
257
{
258
    if ( !EQ_list ( p, univ_type_set ) ) {
259
	if ( EQ_list ( q, univ_type_set ) ) {
260
	    DESTROY_list ( p, SIZE_type ) ;
261
	    p = q ;
262
	} else {
263
	    while ( !IS_NULL_list ( q ) ) {
264
		TYPE t = DEREF_type ( HEAD_list ( q ) ) ;
265
		if ( !IS_NULL_type ( t ) ) {
266
		    if ( !in_type_set ( p, t ) ) CONS_type ( t, p, p ) ;
267
		}
268
		q = TAIL_list ( q ) ;
269
	    }
270
	}
271
    }
272
    return ( p ) ;
273
}
274
 
275
 
276
/*
277
    MAKE A UNIQUE COPY OF A TYPE SET
278
 
279
    This routine maintains a list of type sets.  If p equals an element of
280
    this list then the copy is returned and p is destroyed.  Otherwise p
281
    is added to the list.
282
*/
283
 
284
LIST ( TYPE ) uniq_type_set
285
    PROTO_N ( ( p ) )
286
    PROTO_T ( LIST ( TYPE ) p )
287
{
288
    static LIST ( LIST ( TYPE ) ) sets = NULL_list ( LIST ( TYPE ) ) ;
289
    LIST ( LIST ( TYPE ) ) s = sets ;
290
    while ( !IS_NULL_list ( s ) ) {
291
	LIST ( TYPE ) q = DEREF_list ( HEAD_list ( s ) ) ;
292
	if ( eq_type_set ( p, q, 1 ) == 2 ) {
293
	    DESTROY_list ( p, SIZE_type ) ;
294
	    return ( q ) ;
295
	}
296
	s = TAIL_list ( s ) ;
297
    }
298
    CONS_list ( p, sets, sets ) ;
299
    return ( p ) ;
300
}
301
 
302
 
303
/*
304
    COMPARE THE EXCEPTION SPECIFIERS OF TWO TYPES
305
 
306
    This routine compares the exception specifiers of the similar types
307
    s and t.  It returns 2 if they are equal, 1 if s is more constrained
308
    than t, and 0 otherwise.
309
*/
310
 
311
int eq_except
312
    PROTO_N ( ( s, t ) )
313
    PROTO_T ( TYPE s X TYPE t )
314
{
315
    unsigned ns, nt ;
316
    if ( EQ_type ( s, t ) ) return ( 2 ) ;
317
    if ( IS_NULL_type ( s ) ) return ( 0 ) ;
318
    if ( IS_NULL_type ( t ) ) return ( 0 ) ;
319
    ns = TAG_type ( s ) ;
320
    nt = TAG_type ( t ) ;
321
    if ( ns != nt ) return ( 2 ) ;
322
    ASSERT ( ORDER_type == 18 ) ;
323
    switch ( ns ) {
324
 
325
	case type_func_tag : {
326
	    /* Function types */
327
	    LIST ( TYPE ) es = DEREF_list ( type_func_except ( s ) ) ;
328
	    LIST ( TYPE ) et = DEREF_list ( type_func_except ( t ) ) ;
329
	    int eq = eq_type_set ( es, et, 0 ) ;
330
	    if ( eq ) {
331
		TYPE rs, rt ;
332
		LIST ( TYPE ) ps = DEREF_list ( type_func_ptypes ( s ) ) ;
333
		LIST ( TYPE ) pt = DEREF_list ( type_func_ptypes ( t ) ) ;
334
		while ( !IS_NULL_list ( ps ) && !IS_NULL_list ( pt ) ) {
335
		    rs = DEREF_type ( HEAD_list ( ps ) ) ;
336
		    rt = DEREF_type ( HEAD_list ( pt ) ) ;
337
		    if ( eq_except ( rs, rt ) != 2 ) return ( 0 ) ;
338
		    pt = TAIL_list ( pt ) ;
339
		    ps = TAIL_list ( ps ) ;
340
		}
341
		rs = DEREF_type ( type_func_ret ( s ) ) ;
342
		rt = DEREF_type ( type_func_ret ( t ) ) ;
343
		if ( eq_except ( rs, rt ) != 2 ) return ( 0 ) ;
344
	    }
345
	    return ( eq ) ;
346
	}
347
 
348
	case type_ptr_tag :
349
	case type_ref_tag : {
350
	    /* Pointer and reference types */
351
	    TYPE ps = DEREF_type ( type_ptr_etc_sub ( s ) ) ;
352
	    TYPE pt = DEREF_type ( type_ptr_etc_sub ( t ) ) ;
353
	    return ( eq_except ( ps, pt ) ) ;
354
	}
355
 
356
	case type_ptr_mem_tag : {
357
	    /* Pointer to member types */
358
	    TYPE ps = DEREF_type ( type_ptr_mem_sub ( s ) ) ;
359
	    TYPE pt = DEREF_type ( type_ptr_mem_sub ( t ) ) ;
360
	    return ( eq_except ( ps, pt ) ) ;
361
	}
362
 
363
	case type_array_tag : {
364
	    /* Array types */
365
	    TYPE ps = DEREF_type ( type_array_sub ( s ) ) ;
366
	    TYPE pt = DEREF_type ( type_array_sub ( t ) ) ;
367
	    return ( eq_except ( ps, pt ) ) ;
368
	}
369
 
370
	case type_templ_tag : {
371
	    /* Template types */
372
	    TOKEN as = DEREF_tok ( type_templ_sort ( s ) ) ;
373
	    TOKEN at = DEREF_tok ( type_templ_sort ( t ) ) ;
374
	    LIST ( IDENTIFIER ) qs = DEREF_list ( tok_templ_pids ( as ) ) ;
375
	    LIST ( IDENTIFIER ) qt = DEREF_list ( tok_templ_pids ( at ) ) ;
376
	    int eq = eq_templ_params ( qs, qt ) ;
377
	    if ( eq ) {
378
		TYPE ps = DEREF_type ( type_templ_defn ( s ) ) ;
379
		TYPE pt = DEREF_type ( type_templ_defn ( t ) ) ;
380
		eq = eq_except ( ps, pt ) ;
381
	    }
382
	    restore_templ_params ( qs ) ;
383
	    return ( eq ) ;
384
	}
385
    }
386
    return ( 2 ) ;
387
}
388
 
389
 
390
/*
391
    CREATE AN EXCEPTION TYPE
392
 
393
    This routine converts the exception type t to its primary form.
394
    Reference types are replaced by the referenced type and any top level
395
    type qualifiers are removed.  chk gives the context for the conversion,
396
    1 for a throw expression, 2 for a catch statement, 3 for an exception
397
    specifier and 0 otherwise.
398
*/
399
 
400
TYPE exception_type
401
    PROTO_N ( ( t, chk ) )
402
    PROTO_T ( TYPE t X int chk )
403
{
404
    if ( !IS_NULL_type ( t ) ) {
405
	unsigned tag = TAG_type ( t ) ;
406
	if ( tag == type_ref_tag ) {
407
	    t = DEREF_type ( type_ref_sub ( t ) ) ;
408
	    tag = TAG_type ( t ) ;
409
	}
410
	t = qualify_type ( t, cv_none, 0 ) ;
411
	if ( chk ) {
412
	    /* Check exception type */
413
	    TYPE s = t ;
414
	    if ( tag == type_ptr_tag ) {
415
		s = DEREF_type ( type_ptr_sub ( s ) ) ;
416
		tag = TAG_type ( s ) ;
417
	    }
418
	    if ( tag == type_compound_tag ) {
419
		ERROR err = check_incomplete ( s ) ;
420
		if ( !IS_NULL_err ( err ) ) {
421
		    /* Can't have an incomplete class */
422
		    ERROR err2 = NULL_err ;
423
		    switch ( chk ) {
424
			case 1 : err2 = ERR_except_throw_incompl () ; break ;
425
			case 2 : err2 = ERR_except_handle_incompl () ; break ;
426
			case 3 : err2 = ERR_except_spec_incompl () ; break ;
427
		    }
428
		    err = concat_error ( err, err2 ) ;
429
		    report ( crt_loc, err ) ;
430
		}
431
		if ( chk == 1 ) {
432
		    /* Can't throw a type with an ambiguous base */
433
		    CLASS_TYPE cs = DEREF_ctype ( type_compound_defn ( s ) ) ;
434
		    err = class_info ( cs, cinfo_ambiguous, 1 ) ;
435
		    if ( !IS_NULL_err ( err ) ) {
436
			ERROR err2 = ERR_except_throw_ambig () ;
437
			err = concat_error ( err, err2 ) ;
438
			report ( crt_loc, err ) ;
439
		    }
440
		}
441
	    }
442
	}
443
    }
444
    return ( t ) ;
445
}
446
 
447
 
448
/*
449
    CHECK AN EXCEPTION SPECIFIER TYPE
450
 
451
    This routine checks the type t, which forms part of an exception
452
    specification for a function.  The argument n gives the number of types
453
    defined in t.
454
*/
455
 
456
TYPE check_except_type
457
    PROTO_N ( ( t, n ) )
458
    PROTO_T ( TYPE t X int n )
459
{
460
    if ( n ) report ( crt_loc, ERR_except_spec_typedef () ) ;
461
    IGNORE exception_type ( t, 3 ) ;
462
    return ( t ) ;
463
}
464
 
465
 
466
/*
467
    STACK OF CURRENTLY ACTIVE TRY BLOCKS
468
 
469
    The stack crt_try_block is used to hold all the currently active try
470
    blocks and exception handlers.  The flag in_func_handler is set to
471
    1 (or 2 for constructors and destructors) in the handler of a function
472
    try block.
473
*/
474
 
475
STACK ( EXP ) crt_try_blocks = NULL_stack ( EXP ) ;
476
static STACK ( STACK ( EXP ) ) past_try_blocks = NULL_stack ( STACK ( EXP ) ) ;
477
int in_func_handler = 0 ;
478
 
479
 
480
/*
481
    CHECK A THROWN TYPE
482
 
483
    This routine checks the type t thrown from an explicit throw expression
484
    (if expl is true) or a function call.  The null type is used to
485
    indicate an unknown type.  The routine returns true if the exception
486
    is caught by an enclosing handler.
487
*/
488
 
489
int check_throw
490
    PROTO_N ( ( t, expl ) )
491
    PROTO_T ( TYPE t X int expl )
492
{
493
    IDENTIFIER fn ;
494
    LIST ( EXP ) p = LIST_stack ( crt_try_blocks ) ;
495
    while ( !IS_NULL_list ( p ) ) {
496
	EXP e = DEREF_exp ( HEAD_list ( p ) ) ;
497
	if ( IS_exp_try_block ( e ) ) {
498
	    /* Add to list of thrown types */
499
	    LIST ( TYPE ) q ;
500
	    q = DEREF_list ( exp_try_block_ttypes ( e ) ) ;
501
	    if ( !EQ_list ( q, univ_type_set ) ) {
502
		LIST ( LOCATION ) ql ;
503
		ql = DEREF_list ( exp_try_block_tlocs ( e ) ) ;
504
		if ( IS_NULL_type ( t ) ) {
505
		    DESTROY_list ( q, SIZE_type ) ;
506
		    DESTROY_list ( ql, SIZE_loc ) ;
507
		    q = univ_type_set ;
508
		    ql = NULL_list ( LOCATION ) ;
509
		    CONS_loc ( crt_loc, ql, ql ) ;
510
		} else {
511
		    if ( !in_type_set ( q, t ) ) {
512
			CONS_type ( t, q, q ) ;
513
			CONS_loc ( crt_loc, ql, ql ) ;
514
		    }
515
		}
516
		COPY_list ( exp_try_block_ttypes ( e ), q ) ;
517
		COPY_list ( exp_try_block_tlocs ( e ), ql ) ;
518
	    }
519
	    return ( 1 ) ;
520
	}
521
	if ( IS_NULL_type ( t ) && expl && IS_exp_handler ( e ) ) {
522
	    /* Can deduce type of 'throw' inside a handler */
523
	    IDENTIFIER ex = DEREF_id ( exp_handler_except ( e ) ) ;
524
	    if ( !IS_NULL_id ( ex ) ) {
525
		t = DEREF_type ( id_variable_etc_type ( ex ) ) ;
526
		t = exception_type ( t, 0 ) ;
527
	    }
528
	}
529
	p = TAIL_list ( p ) ;
530
    }
531
 
532
    /* Exception not caught by any try block */
533
    fn = crt_func_id ;
534
    if ( IS_NULL_type ( t ) ) t = type_any ;
535
    if ( IS_NULL_id ( fn ) ) {
536
	report ( crt_loc, ERR_except_spec_throw ( t ) ) ;
537
    } else {
538
	report ( crt_loc, ERR_except_spec_call ( fn, t ) ) ;
539
    }
540
    return ( 0 ) ;
541
}
542
 
543
 
544
/*
545
    CHECK THE EXCEPTIONS THROWN IN A TRY BLOCK
546
 
547
    This routine checks the exceptions thrown in the try block e.  Any
548
    which are not caught by the handlers of e are passed to the enclosing
549
    block or reported if this is the outermost block.  The routine
550
    returns true if all the exceptions are handled by an enclosing block.
551
*/
552
 
553
int check_try_block
554
    PROTO_N ( ( e ) )
555
    PROTO_T ( EXP e )
556
{
557
    int res = 1 ;
558
    if ( IS_exp_try_block ( e ) ) {
559
	LOCATION loc ;
560
	LIST ( LOCATION ) ql ;
561
	LIST ( TYPE ) p = DEREF_list ( exp_try_block_htypes ( e ) ) ;
562
	LIST ( TYPE ) q = DEREF_list ( exp_try_block_ttypes ( e ) ) ;
563
	EXP a = DEREF_exp ( exp_try_block_ellipsis ( e ) ) ;
564
	if ( EQ_list ( p, univ_type_set ) ) {
565
	    /* Have handlers for any type */
566
	    return ( 1 ) ;
567
	}
568
	if ( !IS_NULL_exp ( a ) && IS_exp_handler ( a ) ) {
569
	    /* Have a ... handler */
570
	    return ( 1 ) ;
571
	}
572
	bad_crt_loc++ ;
573
	loc = crt_loc ;
574
	ql = DEREF_list ( exp_try_block_tlocs ( e ) ) ;
575
	if ( EQ_list ( q, univ_type_set ) ) {
576
	    /* Can throw any type */
577
	    DEREF_loc ( HEAD_list ( ql ), crt_loc ) ;
578
	    res = check_throw ( NULL_type, 0 ) ;
579
	} else {
580
	    /* Can throw a finite set of types */
581
	    q = REVERSE_list ( q ) ;
582
	    ql = REVERSE_list ( ql ) ;
583
	    COPY_list ( exp_try_block_ttypes ( e ), q ) ;
584
	    COPY_list ( exp_try_block_tlocs ( e ), ql ) ;
585
	    while ( !IS_NULL_list ( q ) ) {
586
		TYPE t = DEREF_type ( HEAD_list ( q ) ) ;
587
		TYPE u = from_type_set ( p, t ) ;
588
		if ( IS_NULL_type ( u ) ) {
589
		    /* Throw uncaught type to enclosing block */
590
		    DEREF_loc ( HEAD_list ( ql ), crt_loc ) ;
591
		    if ( !check_throw ( t, 0 ) ) res = 0 ;
592
		}
593
		ql = TAIL_list ( ql ) ;
594
		q = TAIL_list ( q ) ;
595
	    }
596
	}
597
	crt_loc = loc ;
598
	bad_crt_loc-- ;
599
    }
600
    return ( res ) ;
601
}
602
 
603
 
604
/*
605
    CHECK THE EXCEPTIONS THROWN BY A FUNCTION CALL
606
 
607
    This routine checks the possible exceptions thrown by a call to a
608
    function of type fn.  When known the function name is given by fid.
609
    The routine returns true if the exception is handled by an enclosing
610
    try-block.
611
*/
612
 
613
int check_func_throw
614
    PROTO_N ( ( fn, fid ) )
615
    PROTO_T ( TYPE fn X IDENTIFIER fid )
616
{
617
    int res = 1 ;
618
    if ( IS_type_func ( fn ) ) {
619
	LIST ( TYPE ) p = DEREF_list ( type_func_except ( fn ) ) ;
620
	if ( IS_NULL_list ( p ) ) return ( 1 ) ;
621
	if ( EQ_list ( p, univ_type_set ) ) {
622
	    /* Can throw any type */
623
	    res = check_throw ( NULL_type, 0 ) ;
624
	} else {
625
	    /* Can throw a finite set of types */
626
	    while ( !IS_NULL_list ( p ) ) {
627
		TYPE t = DEREF_type ( HEAD_list ( p ) ) ;
628
		if ( !IS_NULL_type ( t ) ) {
629
		    if ( !check_throw ( t, 0 ) ) res = 0 ;
630
		}
631
		p = TAIL_list ( p ) ;
632
	    }
633
	}
634
    } else {
635
	res = check_throw ( NULL_type, 0 ) ;
636
    }
637
    UNUSED ( fid ) ;
638
    return ( res ) ;
639
}
640
 
641
 
642
/*
643
    START THE EXCEPTION CHECKS FOR A FUNCTION DEFINITION
644
 
645
    This routine starts the exception specification checks for a function
646
    which throws the types p.
647
*/
648
 
649
void start_try_check
650
    PROTO_N ( ( p ) )
651
    PROTO_T ( LIST ( TYPE ) p )
652
{
653
    EXP e ;
654
    MAKE_exp_try_block ( type_void, NULL_exp, 0, e ) ;
655
    COPY_list ( exp_try_block_htypes ( e ), p ) ;
656
    PUSH_stack ( crt_try_blocks, past_try_blocks ) ;
657
    crt_try_blocks = NULL_stack ( EXP ) ;
658
    PUSH_exp ( e, crt_try_blocks ) ;
659
    return ;
660
}
661
 
662
 
663
/*
664
    END THE EXCEPTION CHECKS FOR A FUNCTION DEFINITION
665
 
666
    This routine ends the exception specification checks for the function
667
    id with definition a.
668
*/
669
 
670
EXP end_try_check
671
    PROTO_N ( ( id, a ) )
672
    PROTO_T ( IDENTIFIER id X EXP a )
673
{
674
    EXP e ;
675
    POP_exp ( e, crt_try_blocks ) ;
676
    POP_stack ( crt_try_blocks, past_try_blocks ) ;
677
    if ( !IS_NULL_exp ( e ) && IS_exp_try_block ( e ) ) {
678
	IDENTIFIER fid = crt_func_id ;
679
	crt_func_id = id ;
680
	IGNORE check_try_block ( e ) ;
681
	if ( EQ_id ( fid, id ) ) {
682
	    LIST ( TYPE ) p = DEREF_list ( exp_try_block_ttypes ( e ) ) ;
683
	    if ( IS_NULL_list ( p ) && !in_template_decl ) {
684
		/* Function can't throw an exception */
685
		DECL_SPEC ds = DEREF_dspec ( id_storage ( id ) ) ;
686
		ds |= dspec_friend ;
687
		COPY_dspec ( id_storage ( id ), ds ) ;
688
	    }
689
	}
690
	COPY_list ( exp_try_block_htypes ( e ), NULL_list ( TYPE ) ) ;
691
	free_exp ( e, 1 ) ;
692
	crt_func_id = fid ;
693
    }
694
    return ( a ) ;
695
}
696
 
697
 
698
/*
699
    EXCEPTION HANDLING ROUTINES
700
 
701
    The exception handling routines are only included in the C++ producer.
702
*/
703
 
704
#if LANGUAGE_CPP
705
 
706
 
707
/*
708
    BEGIN THE CONSTRUCTION OF A TRY STATEMENT
709
 
710
    This routine begins the construction of the statement 'try { body }
711
    handlers'.  It is called immediately after the 'try'.  func is true
712
    for a function-try-block.
713
*/
714
 
715
EXP begin_try_stmt
716
    PROTO_N ( ( func ) )
717
    PROTO_T ( int func )
718
{
719
    EXP e ;
720
    if ( func ) {
721
	/* Check function try blocks */
722
	IDENTIFIER fn = crt_func_id ;
723
	if ( !IS_NULL_id ( fn ) ) {
724
	    HASHID nm = DEREF_hashid ( id_name ( fn ) ) ;
725
	    unsigned tag = TAG_hashid ( nm ) ;
726
	    if ( tag == hashid_constr_tag || tag == hashid_destr_tag ) {
727
		/* Constructors and destructors are marked */
728
		func = 2 ;
729
	    }
730
	} else {
731
	    func = 0 ;
732
	}
733
    }
734
    MAKE_exp_try_block ( type_void, NULL_exp, func, e ) ;
735
    CONS_exp ( e, all_try_blocks, all_try_blocks ) ;
736
    PUSH_exp ( e, crt_try_blocks ) ;
737
    return ( e ) ;
738
}
739
 
740
 
741
/*
742
    INJECT FUNCTION PARAMETERS INTO A HANDLER
743
 
744
    It is not allowed to redeclare a function parameter in the body or
745
    the handler of a function-try-block.  This routine ensures this by
746
    injecting the function parameters into the current scope when prev
747
    is a function-try-block.
748
*/
749
 
750
void inject_try_stmt
751
    PROTO_N ( ( prev ) )
752
    PROTO_T ( EXP prev )
753
{
754
    int func = DEREF_int ( exp_try_block_func ( prev ) ) ;
755
    if ( func ) {
756
	IDENTIFIER id = crt_func_id ;
757
	if ( !IS_NULL_id ( id ) && IS_id_function_etc ( id ) ) {
758
	    LIST ( IDENTIFIER ) pids ;
759
	    NAMESPACE ns = crt_namespace ;
760
	    TYPE t = DEREF_type ( id_function_etc_type ( id ) ) ;
761
	    while ( IS_type_templ ( t ) ) {
762
		t = DEREF_type ( type_templ_defn ( t ) ) ;
763
	    }
764
	    pids = DEREF_list ( type_func_pids ( t ) ) ;
765
	    while ( !IS_NULL_list ( pids ) ) {
766
		IDENTIFIER pid = DEREF_id ( HEAD_list ( pids ) ) ;
767
		IGNORE redeclare_id ( ns, pid ) ;
768
		pids = TAIL_list ( pids ) ;
769
	    }
770
	}
771
    }
772
    return ;
773
}
774
 
775
 
776
/*
777
    CONTINUE THE CONSTRUCTION OF A TRY STATEMENT
778
 
779
    This routine continues the contruction of the try statement prev by
780
    filling in the given body statement.
781
*/
782
 
783
EXP cont_try_stmt
784
    PROTO_N ( ( prev, body ) )
785
    PROTO_T ( EXP prev X EXP body )
786
{
787
    EXP e ;
788
    int func = DEREF_int ( exp_try_block_func ( prev ) ) ;
789
    if ( func ) in_func_handler = func ;
790
    COPY_exp ( exp_try_block_body ( prev ), body ) ;
791
    set_parent_stmt ( body, prev ) ;
792
    POP_exp ( e, crt_try_blocks ) ;
793
    UNUSED ( e ) ;
794
    return ( prev ) ;
795
}
796
 
797
 
798
/*
799
    COMPLETE THE CONSTRUCTION OF A TRY STATEMENT
800
 
801
    This routine completes the contruction of the try statement prev.  It
802
    checks whether it contains at least one handler and determines the
803
    reachability of the following statement.
804
*/
805
 
806
EXP end_try_stmt
807
    PROTO_N ( ( prev, empty ) )
808
    PROTO_T ( EXP prev X int empty )
809
{
810
    EXP e ;
811
    TYPE t ;
812
    int all_bottom = 1 ;
813
    int func = DEREF_int ( exp_try_block_func ( prev ) ) ;
814
 
815
    /* Check handler list */
816
    EXP ell = DEREF_exp ( exp_try_block_ellipsis ( prev ) ) ;
817
    LIST ( EXP ) hs = DEREF_list ( exp_try_block_handlers ( prev ) ) ;
818
    LIST ( TYPE ) ps = DEREF_list ( exp_try_block_ttypes ( prev ) ) ;
819
    unsigned nh = LENGTH_list ( hs ) ;
820
    if ( IS_NULL_exp ( ell ) ) {
821
	/* Create default handler if necessary */
822
	if ( IS_NULL_list ( hs ) && !empty ) {
823
	    /* Check that there is at least one handler */
824
	    report ( crt_loc, ERR_except_handlers () ) ;
825
	}
826
	MAKE_exp_exception ( type_bottom, ell, NULL_exp, NULL_exp, 0, ell ) ;
827
	COPY_exp ( exp_try_block_ellipsis ( prev ), ell ) ;
828
    } else {
829
	nh++ ;
830
    }
831
    IGNORE check_value ( OPT_VAL_exception_handlers, ( ulong ) nh ) ;
832
 
833
    /* Do unreached code analysis */
834
    e = DEREF_exp ( exp_try_block_body ( prev ) ) ;
835
    t = DEREF_type ( exp_type ( e ) ) ;
836
    if ( IS_type_bottom ( t ) ) {
837
	/* Don't reach end of try block */
838
	t = DEREF_type ( exp_type ( ell ) ) ;
839
	if ( !IS_type_bottom ( t ) ) all_bottom = 0 ;
840
	while ( !IS_NULL_list ( hs ) && all_bottom ) {
841
	    /* Check the other handlers */
842
	    e = DEREF_exp ( HEAD_list ( hs ) ) ;
843
	    t = DEREF_type ( exp_type ( e ) ) ;
844
	    if ( !IS_type_bottom ( t ) ) all_bottom = 0 ;
845
	    hs = TAIL_list ( hs ) ;
846
	}
847
    } else {
848
	/* Reach end of try block */
849
	all_bottom = 0 ;
850
    }
851
    if ( all_bottom ) {
852
	COPY_type ( exp_type ( prev ), type_bottom ) ;
853
	unreached_code = 1 ;
854
	unreached_last = 0 ;
855
    } else {
856
	unreached_code = unreached_prev ;
857
    }
858
    if ( IS_NULL_list ( ps ) && !empty && !in_template_decl ) {
859
	report ( crt_loc, ERR_except_not () ) ;
860
    }
861
    if ( func ) in_func_handler = 0 ;
862
    IGNORE check_try_block ( prev ) ;
863
    return ( prev ) ;
864
}
865
 
866
 
867
/*
868
    MARK ALL VARIABLES ENCLOSING A TRY BLOCK
869
 
870
    This routine marks all the local variables of the function id which
871
    contain a try block within their scope.
872
*/
873
 
874
void end_try_blocks
875
    PROTO_N ( ( id ) )
876
    PROTO_T ( IDENTIFIER id )
877
{
878
    LIST ( EXP ) p = all_try_blocks ;
879
    if ( !IS_NULL_list ( p ) ) {
880
	if ( !IS_NULL_id ( id ) ) {
881
	    /* Mark function */
882
	    DECL_SPEC ds = DEREF_dspec ( id_storage ( id ) ) ;
883
	    ds |= dspec_mutable ;
884
	    COPY_dspec ( id_storage ( id ), ds ) ;
885
	}
886
	while ( !IS_NULL_list ( p ) ) {
887
	    EXP a = DEREF_exp ( HEAD_list ( p ) ) ;
888
	    while ( !IS_NULL_exp ( a ) ) {
889
		if ( IS_exp_decl_stmt ( a ) ) {
890
		    IDENTIFIER pid = DEREF_id ( exp_decl_stmt_id ( a ) ) ;
891
		    DECL_SPEC ds = DEREF_dspec ( id_storage ( pid ) ) ;
892
		    if ( ds & dspec_auto ) {
893
			/* Mark local variable */
894
			ds |= dspec_mutable ;
895
			COPY_dspec ( id_storage ( pid ), ds ) ;
896
		    }
897
		}
898
		a = get_parent_stmt ( a ) ;
899
	    }
900
	    p = TAIL_list ( p ) ;
901
	}
902
    }
903
    return ;
904
}
905
 
906
 
907
/*
908
    DECLARE AN EXCEPTION HANDLER
909
 
910
    This routine declares an exception handler named id with type t and
911
    declaration specifiers ds (which should always be empty).  n gives
912
    the number of types defined in t.
913
*/
914
 
915
IDENTIFIER make_except_decl
916
    PROTO_N ( ( ds, t, id, n ) )
917
    PROTO_T ( DECL_SPEC ds X TYPE t X IDENTIFIER id X int n )
918
{
919
    /* Declare id as a local variable */
920
    EXP e ;
921
    if ( crt_id_qualifier == qual_nested || crt_templ_qualifier ) {
922
	/* Other illegal identifiers are caught elsewhere */
923
	report ( crt_loc, ERR_dcl_meaning_id ( qual_nested, id ) ) ;
924
    }
925
    if ( n ) report ( crt_loc, ERR_except_handle_typedef () ) ;
926
    t = make_param_type ( t, CONTEXT_PARAMETER ) ;
927
    id = make_object_decl ( ds, t, id, 0 ) ;
928
 
929
    /* The initialising value is the current exception */
930
    if ( IS_type_ref ( t ) ) {
931
	t = DEREF_type ( type_ref_sub ( t ) ) ;
932
    }
933
    t = lvalue_type ( t ) ;
934
    MAKE_exp_thrown ( t, 0, e ) ;
935
    IGNORE init_object ( id, e ) ;
936
    return ( id ) ;
937
}
938
 
939
 
940
/*
941
    BEGIN THE CONSTRUCTION OF A CATCH STATEMENT
942
 
943
    This routine begins the construction of the handler 'catch ( ex )
944
    { body }' associated with the try block block.  It is called after the
945
    declaration of ex.  Note that ex can be the null identifier, indicating
946
    that the handler is '...'.
947
*/
948
 
949
EXP begin_catch_stmt
950
    PROTO_N ( ( block, ex ) )
951
    PROTO_T ( EXP block X IDENTIFIER ex )
952
{
953
    /* Construct the result */
954
    EXP e, d ;
955
    MAKE_exp_handler ( type_void, ex, NULL_exp, e ) ;
956
    COPY_exp ( exp_handler_parent ( e ), block ) ;
957
    unreached_code = 0 ;
958
    unreached_last = 0 ;
959
 
960
    /* Check for '...' handlers */
961
    d = DEREF_exp ( exp_try_block_ellipsis ( block ) ) ;
962
    if ( !IS_NULL_exp ( d ) ) {
963
	/* Already have a '...' handler */
964
	report ( crt_loc, ERR_except_handle_ellipsis () ) ;
965
	unreached_code = 1 ;
966
    } else if ( IS_NULL_id ( ex ) ) {
967
	/* Set the '...' handler if necessary */
968
	COPY_exp ( exp_try_block_ellipsis ( block ), e ) ;
969
    } else {
970
	/* Add to list of other handlers */
971
	TYPE t0 ;
972
	TYPE t, s ;
973
	LIST ( EXP ) p, q ;
974
	LIST ( TYPE ) u, v ;
975
 
976
	/* Check list of handler types */
977
	u = DEREF_list ( exp_try_block_htypes ( block ) ) ;
978
	t0 = DEREF_type ( id_variable_etc_type ( ex ) ) ;
979
	t = exception_type ( t0, 2 ) ;
980
	s = from_type_set ( u, t ) ;
981
	if ( !IS_NULL_type ( s ) ) {
982
	    report ( crt_loc, ERR_except_handle_unreach ( t0, s ) ) ;
983
	    unreached_code = 1 ;
984
	}
985
	CONS_type ( t, NULL_list ( TYPE ), v ) ;
986
	u = APPEND_list ( u, v ) ;
987
	COPY_list ( exp_try_block_htypes ( block ), u ) ;
988
 
989
	/* Add ex to list of handler expressions */
990
	p = DEREF_list ( exp_try_block_handlers ( block ) ) ;
991
	CONS_exp ( e, NULL_list ( EXP ), q ) ;
992
	p = APPEND_list ( p, q ) ;
993
	COPY_list ( exp_try_block_handlers ( block ), p ) ;
994
    }
995
    PUSH_exp ( e, crt_try_blocks ) ;
996
    return ( e ) ;
997
}
998
 
999
 
1000
/*
1001
    COMPLETE THE CONSTRUCTION OF A CATCH STATEMENT
1002
 
1003
    This routine completes the construction of the catch statement prev by
1004
    filling in the given body statement.
1005
*/
1006
 
1007
EXP end_catch_stmt
1008
    PROTO_N ( ( prev, body ) )
1009
    PROTO_T ( EXP prev X EXP body )
1010
{
1011
    EXP e ;
1012
    if ( unreached_code ) {
1013
	/* Mark unreached statements */
1014
	COPY_type ( exp_type ( prev ), type_bottom ) ;
1015
    } else {
1016
	/* Control reaches end of handler */
1017
	int func ;
1018
	e = DEREF_exp ( exp_handler_parent ( prev ) ) ;
1019
	func = DEREF_int ( exp_try_block_func ( e ) ) ;
1020
	if ( func == 2 ) {
1021
	    /* Re-throw current exception */
1022
	    e = make_throw_exp ( NULL_exp, 0 ) ;
1023
	    body = add_compound_stmt ( body, e ) ;
1024
	    COPY_type ( exp_type ( prev ), type_bottom ) ;
1025
	}
1026
    }
1027
    COPY_exp ( exp_handler_body ( prev ), body ) ;
1028
    set_parent_stmt ( body, prev ) ;
1029
    POP_exp ( e, crt_try_blocks ) ;
1030
    UNUSED ( e ) ;
1031
    return ( prev ) ;
1032
}
1033
 
1034
 
1035
/*
1036
    CONSTRUCT A THROW ARGUMENT FROM A TYPE
1037
 
1038
    The syntax 'throw t' for a type t is exactly equivalent to 'throw t ()'.
1039
    This routine constructs the argument 't ()'.  n gives the number of types
1040
    defined in t.
1041
*/
1042
 
1043
EXP make_throw_arg
1044
    PROTO_N ( ( t, n ) )
1045
    PROTO_T ( TYPE t X int n )
1046
{
1047
    EXP e ;
1048
    report ( crt_loc, ERR_except_throw_type () ) ;
1049
    if ( n ) report ( crt_loc, ERR_except_throw_typedef () ) ;
1050
    e = make_func_cast_exp ( t, NULL_list ( EXP ) ) ;
1051
    return ( e ) ;
1052
}
1053
 
1054
 
1055
/*
1056
    CONSTRUCT A THROW EXPRESSION
1057
 
1058
    This routine constructs the expressions 'throw a' and 'throw' (if a is
1059
    the null expression).  Note that a is assigned to a temporary variable
1060
    of its own type.
1061
*/
1062
 
1063
EXP make_throw_exp
1064
    PROTO_N ( ( a, expl ) )
1065
    PROTO_T ( EXP a X int expl )
1066
{
1067
    EXP e ;
1068
    EXP b = NULL_exp ;
1069
    EXP d = NULL_exp ;
1070
    if ( !IS_NULL_exp ( a ) ) {
1071
	/* Perform operand conversions on a */
1072
	TYPE t ;
1073
	ERROR err ;
1074
	a = convert_reference ( a, REF_NORMAL ) ;
1075
	t = DEREF_type ( exp_type ( a ) ) ;
1076
	if ( !IS_type_compound ( t ) ) {
1077
	    a = convert_lvalue ( a ) ;
1078
	    t = DEREF_type ( exp_type ( a ) ) ;
1079
	}
1080
	t = exception_type ( t, 1 ) ;
1081
	IGNORE check_throw ( t, 1 ) ;
1082
	b = sizeof_exp ( t ) ;
1083
	err = check_complete ( t ) ;
1084
	if ( IS_NULL_err ( err ) ) {
1085
	    /* Exception is assigned to temporary variable */
1086
	    a = init_assign ( t, cv_none, a, &err ) ;
1087
	    d = init_default ( t, &d, DEFAULT_DESTR, EXTRA_DESTR, &err ) ;
1088
	    if ( !IS_NULL_err ( err ) ) err = init_error ( err, 0 ) ;
1089
	}
1090
	if ( !IS_NULL_err ( err ) ) {
1091
	    /* Report type errors */
1092
	    err = concat_error ( err, ERR_except_throw_copy () ) ;
1093
	    report ( crt_loc, err ) ;
1094
	}
1095
	a = check_return_exp ( a, lex_throw ) ;
1096
    } else {
1097
	/* Check thrown type */
1098
	IGNORE check_throw ( NULL_type, 1 ) ;
1099
    }
1100
    MAKE_exp_exception ( type_bottom, a, b, d, expl, e ) ;
1101
    return ( e ) ;
1102
}
1103
 
1104
 
1105
#endif