Mercurial > hg > CbC > CbC_gcc
comparison gcc/cp/except.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 /* Handle exceptional things in C++. | |
2 Copyright (C) 1989-2017 Free Software Foundation, Inc. | |
3 Contributed by Michael Tiemann <tiemann@cygnus.com> | |
4 Rewritten by Mike Stump <mrs@cygnus.com>, based upon an | |
5 initial re-implementation courtesy Tad Hunt. | |
6 | |
7 This file is part of GCC. | |
8 | |
9 GCC is free software; you can redistribute it and/or modify | |
10 it under the terms of the GNU General Public License as published by | |
11 the Free Software Foundation; either version 3, or (at your option) | |
12 any later version. | |
13 | |
14 GCC is distributed in the hope that it will be useful, | |
15 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 GNU General Public License for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
20 along with GCC; see the file COPYING3. If not see | |
21 <http://www.gnu.org/licenses/>. */ | |
22 | |
23 | |
24 #include "config.h" | |
25 #include "system.h" | |
26 #include "coretypes.h" | |
27 #include "cp-tree.h" | |
28 #include "stringpool.h" | |
29 #include "trans-mem.h" | |
30 #include "attribs.h" | |
31 #include "tree-iterator.h" | |
32 | |
33 static void push_eh_cleanup (tree); | |
34 static tree prepare_eh_type (tree); | |
35 static tree do_begin_catch (void); | |
36 static int dtor_nothrow (tree); | |
37 static tree do_end_catch (tree); | |
38 static void initialize_handler_parm (tree, tree); | |
39 static tree do_allocate_exception (tree); | |
40 static tree wrap_cleanups_r (tree *, int *, void *); | |
41 static int complete_ptr_ref_or_void_ptr_p (tree, tree); | |
42 static bool is_admissible_throw_operand_or_catch_parameter (tree, bool); | |
43 static int can_convert_eh (tree, tree); | |
44 | |
45 /* Sets up all the global eh stuff that needs to be initialized at the | |
46 start of compilation. */ | |
47 | |
48 void | |
49 init_exception_processing (void) | |
50 { | |
51 tree tmp; | |
52 | |
53 /* void std::terminate (); */ | |
54 push_namespace (std_identifier); | |
55 tmp = build_function_type_list (void_type_node, NULL_TREE); | |
56 terminate_fn = build_cp_library_fn_ptr ("terminate", tmp, | |
57 ECF_NOTHROW | ECF_NORETURN | |
58 | ECF_COLD); | |
59 gcc_checking_assert (TREE_THIS_VOLATILE (terminate_fn) | |
60 && TREE_NOTHROW (terminate_fn)); | |
61 pop_namespace (); | |
62 | |
63 /* void __cxa_call_unexpected(void *); */ | |
64 tmp = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); | |
65 call_unexpected_fn | |
66 = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp); | |
67 } | |
68 | |
69 /* Returns an expression to be executed if an unhandled exception is | |
70 propagated out of a cleanup region. */ | |
71 | |
72 tree | |
73 cp_protect_cleanup_actions (void) | |
74 { | |
75 /* [except.terminate] | |
76 | |
77 When the destruction of an object during stack unwinding exits | |
78 using an exception ... void terminate(); is called. */ | |
79 return terminate_fn; | |
80 } | |
81 | |
82 static tree | |
83 prepare_eh_type (tree type) | |
84 { | |
85 if (type == NULL_TREE) | |
86 return type; | |
87 if (type == error_mark_node) | |
88 return error_mark_node; | |
89 | |
90 /* peel back references, so they match. */ | |
91 type = non_reference (type); | |
92 | |
93 /* Peel off cv qualifiers. */ | |
94 type = TYPE_MAIN_VARIANT (type); | |
95 | |
96 /* Functions and arrays decay to pointers. */ | |
97 type = type_decays_to (type); | |
98 | |
99 return type; | |
100 } | |
101 | |
102 /* Return the type info for TYPE as used by EH machinery. */ | |
103 tree | |
104 eh_type_info (tree type) | |
105 { | |
106 if (type == NULL_TREE || type == error_mark_node) | |
107 return type; | |
108 | |
109 return get_tinfo_decl (type); | |
110 } | |
111 | |
112 /* Build the address of a typeinfo decl for use in the runtime | |
113 matching field of the exception model. */ | |
114 | |
115 tree | |
116 build_eh_type_type (tree type) | |
117 { | |
118 tree exp = eh_type_info (type); | |
119 | |
120 if (!exp) | |
121 return NULL; | |
122 | |
123 mark_used (exp); | |
124 | |
125 return convert (ptr_type_node, build_address (exp)); | |
126 } | |
127 | |
128 tree | |
129 build_exc_ptr (void) | |
130 { | |
131 return build_call_n (builtin_decl_explicit (BUILT_IN_EH_POINTER), | |
132 1, integer_zero_node); | |
133 } | |
134 | |
135 /* Find or declare a function NAME, returning RTYPE, taking a single | |
136 parameter PTYPE, with an empty exception specification. ECF are the | |
137 library fn flags. If TM_ECF is non-zero, also find or create a | |
138 transaction variant and record it as a replacement, when flag_tm is | |
139 in effect. | |
140 | |
141 Note that the C++ ABI document does not have a throw-specifier on | |
142 the routines declared below via this function. The declarations | |
143 are consistent with the actual implementations in libsupc++. */ | |
144 | |
145 static tree | |
146 declare_library_fn (const char *name, tree rtype, tree ptype, | |
147 int ecf, int tm_ecf) | |
148 { | |
149 tree ident = get_identifier (name); | |
150 tree res = get_global_binding (ident); | |
151 if (!res) | |
152 { | |
153 tree type = build_function_type_list (rtype, ptype, NULL_TREE); | |
154 tree except = ecf & ECF_NOTHROW ? empty_except_spec : NULL_TREE; | |
155 res = push_library_fn (ident, type, except, ecf); | |
156 if (tm_ecf && flag_tm) | |
157 { | |
158 char *tm_name = concat ("_ITM_", name + 2, NULL_TREE); | |
159 tree tm_ident = get_identifier (tm_name); | |
160 free (tm_name); | |
161 tree tm_fn = get_global_binding (tm_ident); | |
162 if (!tm_fn) | |
163 tm_fn = push_library_fn (tm_ident, type, except, ecf | tm_ecf); | |
164 record_tm_replacement (res, tm_fn); | |
165 } | |
166 } | |
167 return res; | |
168 } | |
169 | |
170 /* Build up a call to __cxa_get_exception_ptr so that we can build a | |
171 copy constructor for the thrown object. */ | |
172 | |
173 static tree | |
174 do_get_exception_ptr (void) | |
175 { | |
176 if (!get_exception_ptr_fn) | |
177 /* Declare void* __cxa_get_exception_ptr (void *) throw(). */ | |
178 get_exception_ptr_fn | |
179 = declare_library_fn ("__cxa_get_exception_ptr", | |
180 ptr_type_node, ptr_type_node, | |
181 ECF_NOTHROW | ECF_PURE | ECF_LEAF | ECF_TM_PURE, | |
182 0); | |
183 | |
184 return cp_build_function_call_nary (get_exception_ptr_fn, | |
185 tf_warning_or_error, | |
186 build_exc_ptr (), NULL_TREE); | |
187 } | |
188 | |
189 /* Build up a call to __cxa_begin_catch, to tell the runtime that the | |
190 exception has been handled. */ | |
191 | |
192 static tree | |
193 do_begin_catch (void) | |
194 { | |
195 if (!begin_catch_fn) | |
196 /* Declare void* __cxa_begin_catch (void *) throw(). */ | |
197 begin_catch_fn | |
198 = declare_library_fn ("__cxa_begin_catch", | |
199 ptr_type_node, ptr_type_node, ECF_NOTHROW, | |
200 ECF_TM_PURE); | |
201 | |
202 return cp_build_function_call_nary (begin_catch_fn, tf_warning_or_error, | |
203 build_exc_ptr (), NULL_TREE); | |
204 } | |
205 | |
206 /* Returns nonzero if cleaning up an exception of type TYPE (which can be | |
207 NULL_TREE for a ... handler) will not throw an exception. */ | |
208 | |
209 static int | |
210 dtor_nothrow (tree type) | |
211 { | |
212 if (type == NULL_TREE || type == error_mark_node) | |
213 return 0; | |
214 | |
215 if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type)) | |
216 return 1; | |
217 | |
218 if (CLASSTYPE_LAZY_DESTRUCTOR (type)) | |
219 lazily_declare_fn (sfk_destructor, type); | |
220 | |
221 return TREE_NOTHROW (CLASSTYPE_DESTRUCTOR (type)); | |
222 } | |
223 | |
224 /* Build up a call to __cxa_end_catch, to destroy the exception object | |
225 for the current catch block if no others are currently using it. */ | |
226 | |
227 static tree | |
228 do_end_catch (tree type) | |
229 { | |
230 if (!end_catch_fn) | |
231 /* Declare void __cxa_end_catch (). | |
232 This can throw if the destructor for the exception throws. */ | |
233 end_catch_fn | |
234 = declare_library_fn ("__cxa_end_catch", void_type_node, | |
235 NULL_TREE, 0, ECF_TM_PURE); | |
236 | |
237 tree cleanup = cp_build_function_call_vec (end_catch_fn, | |
238 NULL, tf_warning_or_error); | |
239 TREE_NOTHROW (cleanup) = dtor_nothrow (type); | |
240 | |
241 return cleanup; | |
242 } | |
243 | |
244 /* This routine creates the cleanup for the current exception. */ | |
245 | |
246 static void | |
247 push_eh_cleanup (tree type) | |
248 { | |
249 finish_decl_cleanup (NULL_TREE, do_end_catch (type)); | |
250 } | |
251 | |
252 /* Wrap EXPR in a MUST_NOT_THROW_EXPR expressing that EXPR must | |
253 not throw any exceptions if COND is true. A condition of | |
254 NULL_TREE is treated as 'true'. */ | |
255 | |
256 tree | |
257 build_must_not_throw_expr (tree body, tree cond) | |
258 { | |
259 tree type = body ? TREE_TYPE (body) : void_type_node; | |
260 | |
261 if (!flag_exceptions) | |
262 return body; | |
263 | |
264 if (!cond) | |
265 /* OK, unconditional. */; | |
266 else | |
267 { | |
268 tree conv = NULL_TREE; | |
269 if (!type_dependent_expression_p (cond)) | |
270 conv = perform_implicit_conversion_flags (boolean_type_node, cond, | |
271 tf_warning_or_error, | |
272 LOOKUP_NORMAL); | |
273 if (tree inst = instantiate_non_dependent_or_null (conv)) | |
274 cond = cxx_constant_value (inst); | |
275 else | |
276 require_constant_expression (cond); | |
277 if (integer_zerop (cond)) | |
278 return body; | |
279 else if (integer_onep (cond)) | |
280 cond = NULL_TREE; | |
281 } | |
282 | |
283 return build2 (MUST_NOT_THROW_EXPR, type, body, cond); | |
284 } | |
285 | |
286 | |
287 /* Initialize the catch parameter DECL. */ | |
288 | |
289 static void | |
290 initialize_handler_parm (tree decl, tree exp) | |
291 { | |
292 tree init; | |
293 tree init_type; | |
294 | |
295 /* Make sure we mark the catch param as used, otherwise we'll get a | |
296 warning about an unused ((anonymous)). */ | |
297 TREE_USED (decl) = 1; | |
298 DECL_READ_P (decl) = 1; | |
299 | |
300 /* Figure out the type that the initializer is. Pointers are returned | |
301 adjusted by value from __cxa_begin_catch. Others are returned by | |
302 reference. */ | |
303 init_type = TREE_TYPE (decl); | |
304 if (!POINTER_TYPE_P (init_type)) | |
305 init_type = build_reference_type (init_type); | |
306 | |
307 /* Since pointers are passed by value, initialize a reference to | |
308 pointer catch parm with the address of the temporary. */ | |
309 if (TREE_CODE (init_type) == REFERENCE_TYPE | |
310 && TYPE_PTR_P (TREE_TYPE (init_type))) | |
311 exp = cp_build_addr_expr (exp, tf_warning_or_error); | |
312 | |
313 exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0, | |
314 tf_warning_or_error); | |
315 | |
316 init = convert_from_reference (exp); | |
317 | |
318 /* If the constructor for the catch parm exits via an exception, we | |
319 must call terminate. See eh23.C. */ | |
320 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) | |
321 { | |
322 /* Generate the copy constructor call directly so we can wrap it. | |
323 See also expand_default_init. */ | |
324 init = ocp_convert (TREE_TYPE (decl), init, | |
325 CONV_IMPLICIT|CONV_FORCE_TEMP, 0, | |
326 tf_warning_or_error); | |
327 /* Force cleanups now to avoid nesting problems with the | |
328 MUST_NOT_THROW_EXPR. */ | |
329 init = fold_build_cleanup_point_expr (TREE_TYPE (init), init); | |
330 init = build_must_not_throw_expr (init, NULL_TREE); | |
331 } | |
332 | |
333 decl = pushdecl (decl); | |
334 | |
335 start_decl_1 (decl, true); | |
336 cp_finish_decl (decl, init, /*init_const_expr_p=*/false, NULL_TREE, | |
337 LOOKUP_ONLYCONVERTING|DIRECT_BIND); | |
338 } | |
339 | |
340 | |
341 /* Routine to see if exception handling is turned on. | |
342 DO_WARN is nonzero if we want to inform the user that exception | |
343 handling is turned off. | |
344 | |
345 This is used to ensure that -fexceptions has been specified if the | |
346 compiler tries to use any exception-specific functions. */ | |
347 | |
348 static inline int | |
349 doing_eh (void) | |
350 { | |
351 if (! flag_exceptions) | |
352 { | |
353 static int warned = 0; | |
354 if (! warned) | |
355 { | |
356 error ("exception handling disabled, use -fexceptions to enable"); | |
357 warned = 1; | |
358 } | |
359 return 0; | |
360 } | |
361 return 1; | |
362 } | |
363 | |
364 /* Call this to start a catch block. DECL is the catch parameter. */ | |
365 | |
366 tree | |
367 expand_start_catch_block (tree decl) | |
368 { | |
369 tree exp; | |
370 tree type, init; | |
371 | |
372 if (! doing_eh ()) | |
373 return NULL_TREE; | |
374 | |
375 if (decl) | |
376 { | |
377 if (!is_admissible_throw_operand_or_catch_parameter (decl, false)) | |
378 decl = error_mark_node; | |
379 | |
380 type = prepare_eh_type (TREE_TYPE (decl)); | |
381 mark_used (eh_type_info (type)); | |
382 } | |
383 else | |
384 type = NULL_TREE; | |
385 | |
386 /* Call __cxa_end_catch at the end of processing the exception. */ | |
387 push_eh_cleanup (type); | |
388 | |
389 init = do_begin_catch (); | |
390 | |
391 /* If there's no decl at all, then all we need to do is make sure | |
392 to tell the runtime that we've begun handling the exception. */ | |
393 if (decl == NULL || decl == error_mark_node || init == error_mark_node) | |
394 finish_expr_stmt (init); | |
395 | |
396 /* If the C++ object needs constructing, we need to do that before | |
397 calling __cxa_begin_catch, so that std::uncaught_exception gets | |
398 the right value during the copy constructor. */ | |
399 else if (flag_use_cxa_get_exception_ptr | |
400 && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) | |
401 { | |
402 exp = do_get_exception_ptr (); | |
403 initialize_handler_parm (decl, exp); | |
404 finish_expr_stmt (init); | |
405 } | |
406 | |
407 /* Otherwise the type uses a bitwise copy, and we don't have to worry | |
408 about the value of std::uncaught_exception and therefore can do the | |
409 copy with the return value of __cxa_end_catch instead. */ | |
410 else | |
411 { | |
412 tree init_type = type; | |
413 | |
414 /* Pointers are passed by values, everything else by reference. */ | |
415 if (!TYPE_PTR_P (type)) | |
416 init_type = build_pointer_type (type); | |
417 if (init_type != TREE_TYPE (init)) | |
418 init = build1 (NOP_EXPR, init_type, init); | |
419 exp = create_temporary_var (init_type); | |
420 cp_finish_decl (exp, init, /*init_const_expr=*/false, | |
421 NULL_TREE, LOOKUP_ONLYCONVERTING); | |
422 DECL_REGISTER (exp) = 1; | |
423 initialize_handler_parm (decl, exp); | |
424 } | |
425 | |
426 return type; | |
427 } | |
428 | |
429 | |
430 /* Call this to end a catch block. Its responsible for emitting the | |
431 code to handle jumping back to the correct place, and for emitting | |
432 the label to jump to if this catch block didn't match. */ | |
433 | |
434 void | |
435 expand_end_catch_block (void) | |
436 { | |
437 if (! doing_eh ()) | |
438 return; | |
439 | |
440 /* The exception being handled is rethrown if control reaches the end of | |
441 a handler of the function-try-block of a constructor or destructor. */ | |
442 if (in_function_try_handler | |
443 && (DECL_CONSTRUCTOR_P (current_function_decl) | |
444 || DECL_DESTRUCTOR_P (current_function_decl))) | |
445 { | |
446 tree rethrow = build_throw (NULL_TREE); | |
447 TREE_NO_WARNING (rethrow) = true; | |
448 finish_expr_stmt (rethrow); | |
449 } | |
450 } | |
451 | |
452 tree | |
453 begin_eh_spec_block (void) | |
454 { | |
455 tree r; | |
456 location_t spec_location = DECL_SOURCE_LOCATION (current_function_decl); | |
457 | |
458 /* A noexcept specification (or throw() with -fnothrow-opt) is a | |
459 MUST_NOT_THROW_EXPR. */ | |
460 if (TYPE_NOEXCEPT_P (TREE_TYPE (current_function_decl))) | |
461 { | |
462 r = build_stmt (spec_location, MUST_NOT_THROW_EXPR, | |
463 NULL_TREE, NULL_TREE); | |
464 TREE_SIDE_EFFECTS (r) = 1; | |
465 } | |
466 else | |
467 r = build_stmt (spec_location, EH_SPEC_BLOCK, NULL_TREE, NULL_TREE); | |
468 add_stmt (r); | |
469 TREE_OPERAND (r, 0) = push_stmt_list (); | |
470 return r; | |
471 } | |
472 | |
473 void | |
474 finish_eh_spec_block (tree raw_raises, tree eh_spec_block) | |
475 { | |
476 tree raises; | |
477 | |
478 TREE_OPERAND (eh_spec_block, 0) | |
479 = pop_stmt_list (TREE_OPERAND (eh_spec_block, 0)); | |
480 | |
481 if (TREE_CODE (eh_spec_block) == MUST_NOT_THROW_EXPR) | |
482 return; | |
483 | |
484 /* Strip cv quals, etc, from the specification types. */ | |
485 for (raises = NULL_TREE; | |
486 raw_raises && TREE_VALUE (raw_raises); | |
487 raw_raises = TREE_CHAIN (raw_raises)) | |
488 { | |
489 tree type = prepare_eh_type (TREE_VALUE (raw_raises)); | |
490 tree tinfo = eh_type_info (type); | |
491 | |
492 mark_used (tinfo); | |
493 raises = tree_cons (NULL_TREE, type, raises); | |
494 } | |
495 | |
496 EH_SPEC_RAISES (eh_spec_block) = raises; | |
497 } | |
498 | |
499 /* Return a pointer to a buffer for an exception object of type TYPE. */ | |
500 | |
501 static tree | |
502 do_allocate_exception (tree type) | |
503 { | |
504 if (!allocate_exception_fn) | |
505 /* Declare void *__cxa_allocate_exception(size_t) throw(). */ | |
506 allocate_exception_fn | |
507 = declare_library_fn ("__cxa_allocate_exception", | |
508 ptr_type_node, size_type_node, | |
509 ECF_NOTHROW | ECF_MALLOC, ECF_TM_PURE); | |
510 | |
511 return cp_build_function_call_nary (allocate_exception_fn, | |
512 tf_warning_or_error, | |
513 size_in_bytes (type), NULL_TREE); | |
514 } | |
515 | |
516 /* Call __cxa_free_exception from a cleanup. This is never invoked | |
517 directly, but see the comment for stabilize_throw_expr. */ | |
518 | |
519 static tree | |
520 do_free_exception (tree ptr) | |
521 { | |
522 if (!free_exception_fn) | |
523 /* Declare void __cxa_free_exception (void *) throw(). */ | |
524 free_exception_fn | |
525 = declare_library_fn ("__cxa_free_exception", | |
526 void_type_node, ptr_type_node, | |
527 ECF_NOTHROW | ECF_LEAF, ECF_TM_PURE); | |
528 | |
529 return cp_build_function_call_nary (free_exception_fn, | |
530 tf_warning_or_error, ptr, NULL_TREE); | |
531 } | |
532 | |
533 /* Wrap all cleanups for TARGET_EXPRs in MUST_NOT_THROW_EXPR. | |
534 Called from build_throw via walk_tree_without_duplicates. */ | |
535 | |
536 static tree | |
537 wrap_cleanups_r (tree *tp, int *walk_subtrees, void * /*data*/) | |
538 { | |
539 tree exp = *tp; | |
540 tree cleanup; | |
541 | |
542 /* Don't walk into types. */ | |
543 if (TYPE_P (exp)) | |
544 { | |
545 *walk_subtrees = 0; | |
546 return NULL_TREE; | |
547 } | |
548 if (TREE_CODE (exp) != TARGET_EXPR) | |
549 return NULL_TREE; | |
550 | |
551 cleanup = TARGET_EXPR_CLEANUP (exp); | |
552 if (cleanup) | |
553 { | |
554 cleanup = build2 (MUST_NOT_THROW_EXPR, void_type_node, cleanup, | |
555 NULL_TREE); | |
556 TARGET_EXPR_CLEANUP (exp) = cleanup; | |
557 } | |
558 | |
559 /* Keep iterating. */ | |
560 return NULL_TREE; | |
561 } | |
562 | |
563 /* Build a throw expression. */ | |
564 | |
565 tree | |
566 build_throw (tree exp) | |
567 { | |
568 if (exp == error_mark_node) | |
569 return exp; | |
570 | |
571 if (processing_template_decl) | |
572 { | |
573 if (cfun) | |
574 current_function_returns_abnormally = 1; | |
575 exp = build_min (THROW_EXPR, void_type_node, exp); | |
576 SET_EXPR_LOCATION (exp, input_location); | |
577 return exp; | |
578 } | |
579 | |
580 if (exp == null_node) | |
581 warning (0, "throwing NULL, which has integral, not pointer type"); | |
582 | |
583 if (exp != NULL_TREE) | |
584 { | |
585 if (!is_admissible_throw_operand_or_catch_parameter (exp, true)) | |
586 return error_mark_node; | |
587 } | |
588 | |
589 if (! doing_eh ()) | |
590 return error_mark_node; | |
591 | |
592 if (exp) | |
593 { | |
594 tree throw_type; | |
595 tree temp_type; | |
596 tree cleanup; | |
597 tree object, ptr; | |
598 tree tmp; | |
599 tree allocate_expr; | |
600 | |
601 /* The CLEANUP_TYPE is the internal type of a destructor. */ | |
602 if (!cleanup_type) | |
603 { | |
604 tmp = build_function_type_list (void_type_node, | |
605 ptr_type_node, NULL_TREE); | |
606 cleanup_type = build_pointer_type (tmp); | |
607 } | |
608 | |
609 if (!throw_fn) | |
610 { | |
611 tree name = get_identifier ("__cxa_throw"); | |
612 throw_fn = get_global_binding (name); | |
613 if (!throw_fn) | |
614 { | |
615 /* Declare void __cxa_throw (void*, void*, void (*)(void*)). */ | |
616 /* ??? Second argument is supposed to be "std::type_info*". */ | |
617 tmp = build_function_type_list (void_type_node, | |
618 ptr_type_node, ptr_type_node, | |
619 cleanup_type, NULL_TREE); | |
620 throw_fn = push_throw_library_fn (name, tmp); | |
621 | |
622 if (flag_tm) | |
623 { | |
624 tree itm_name = get_identifier ("_ITM_cxa_throw"); | |
625 tree itm_fn = get_global_binding (itm_name); | |
626 if (!itm_fn) | |
627 itm_fn = push_throw_library_fn (itm_name, tmp); | |
628 apply_tm_attr (itm_fn, get_identifier ("transaction_pure")); | |
629 record_tm_replacement (throw_fn, itm_fn); | |
630 } | |
631 } | |
632 } | |
633 | |
634 /* [except.throw] | |
635 | |
636 A throw-expression initializes a temporary object, the type | |
637 of which is determined by removing any top-level | |
638 cv-qualifiers from the static type of the operand of throw | |
639 and adjusting the type from "array of T" or "function return | |
640 T" to "pointer to T" or "pointer to function returning T" | |
641 respectively. */ | |
642 temp_type = is_bitfield_expr_with_lowered_type (exp); | |
643 if (!temp_type) | |
644 temp_type = cv_unqualified (type_decays_to (TREE_TYPE (exp))); | |
645 | |
646 /* OK, this is kind of wacky. The standard says that we call | |
647 terminate when the exception handling mechanism, after | |
648 completing evaluation of the expression to be thrown but | |
649 before the exception is caught (_except.throw_), calls a | |
650 user function that exits via an uncaught exception. | |
651 | |
652 So we have to protect the actual initialization of the | |
653 exception object with terminate(), but evaluate the | |
654 expression first. Since there could be temps in the | |
655 expression, we need to handle that, too. We also expand | |
656 the call to __cxa_allocate_exception first (which doesn't | |
657 matter, since it can't throw). */ | |
658 | |
659 /* Allocate the space for the exception. */ | |
660 allocate_expr = do_allocate_exception (temp_type); | |
661 allocate_expr = get_target_expr (allocate_expr); | |
662 ptr = TARGET_EXPR_SLOT (allocate_expr); | |
663 TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr); | |
664 CLEANUP_EH_ONLY (allocate_expr) = 1; | |
665 | |
666 object = build_nop (build_pointer_type (temp_type), ptr); | |
667 object = cp_build_indirect_ref (object, RO_NULL, tf_warning_or_error); | |
668 | |
669 /* And initialize the exception object. */ | |
670 if (CLASS_TYPE_P (temp_type)) | |
671 { | |
672 int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING; | |
673 vec<tree, va_gc> *exp_vec; | |
674 bool converted = false; | |
675 | |
676 /* Under C++0x [12.8/16 class.copy], a thrown lvalue is sometimes | |
677 treated as an rvalue for the purposes of overload resolution | |
678 to favor move constructors over copy constructors. */ | |
679 if (/* Must be a local, automatic variable. */ | |
680 VAR_P (exp) | |
681 && DECL_CONTEXT (exp) == current_function_decl | |
682 && ! TREE_STATIC (exp) | |
683 /* The variable must not have the `volatile' qualifier. */ | |
684 && !(cp_type_quals (TREE_TYPE (exp)) & TYPE_QUAL_VOLATILE)) | |
685 { | |
686 tree moved = move (exp); | |
687 exp_vec = make_tree_vector_single (moved); | |
688 moved = (build_special_member_call | |
689 (object, complete_ctor_identifier, &exp_vec, | |
690 TREE_TYPE (object), flags|LOOKUP_PREFER_RVALUE, | |
691 tf_none)); | |
692 release_tree_vector (exp_vec); | |
693 if (moved != error_mark_node) | |
694 { | |
695 exp = moved; | |
696 converted = true; | |
697 } | |
698 } | |
699 | |
700 /* Call the copy constructor. */ | |
701 if (!converted) | |
702 { | |
703 exp_vec = make_tree_vector_single (exp); | |
704 exp = (build_special_member_call | |
705 (object, complete_ctor_identifier, &exp_vec, | |
706 TREE_TYPE (object), flags, tf_warning_or_error)); | |
707 release_tree_vector (exp_vec); | |
708 } | |
709 | |
710 if (exp == error_mark_node) | |
711 { | |
712 error (" in thrown expression"); | |
713 return error_mark_node; | |
714 } | |
715 } | |
716 else | |
717 { | |
718 tmp = decay_conversion (exp, tf_warning_or_error); | |
719 if (tmp == error_mark_node) | |
720 return error_mark_node; | |
721 exp = build2 (INIT_EXPR, temp_type, object, tmp); | |
722 } | |
723 | |
724 /* Mark any cleanups from the initialization as MUST_NOT_THROW, since | |
725 they are run after the exception object is initialized. */ | |
726 cp_walk_tree_without_duplicates (&exp, wrap_cleanups_r, 0); | |
727 | |
728 /* Prepend the allocation. */ | |
729 exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); | |
730 | |
731 /* Force all the cleanups to be evaluated here so that we don't have | |
732 to do them during unwinding. */ | |
733 exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp); | |
734 | |
735 throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); | |
736 | |
737 cleanup = NULL_TREE; | |
738 if (type_build_dtor_call (TREE_TYPE (object))) | |
739 { | |
740 tree dtor_fn = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), | |
741 complete_dtor_identifier, 0); | |
742 dtor_fn = BASELINK_FUNCTIONS (dtor_fn); | |
743 mark_used (dtor_fn); | |
744 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object))) | |
745 { | |
746 cxx_mark_addressable (dtor_fn); | |
747 /* Pretend it's a normal function. */ | |
748 cleanup = build1 (ADDR_EXPR, cleanup_type, dtor_fn); | |
749 } | |
750 } | |
751 if (cleanup == NULL_TREE) | |
752 cleanup = build_int_cst (cleanup_type, 0); | |
753 | |
754 /* ??? Indicate that this function call throws throw_type. */ | |
755 tmp = cp_build_function_call_nary (throw_fn, tf_warning_or_error, | |
756 ptr, throw_type, cleanup, NULL_TREE); | |
757 | |
758 /* Tack on the initialization stuff. */ | |
759 exp = build2 (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp); | |
760 } | |
761 else | |
762 { | |
763 /* Rethrow current exception. */ | |
764 if (!rethrow_fn) | |
765 { | |
766 tree name = get_identifier ("__cxa_rethrow"); | |
767 rethrow_fn = get_global_binding (name); | |
768 if (!rethrow_fn) | |
769 /* Declare void __cxa_rethrow (void). */ | |
770 rethrow_fn = push_throw_library_fn | |
771 (name, build_function_type_list (void_type_node, NULL_TREE)); | |
772 | |
773 if (flag_tm) | |
774 apply_tm_attr (rethrow_fn, get_identifier ("transaction_pure")); | |
775 } | |
776 | |
777 /* ??? Indicate that this function call allows exceptions of the type | |
778 of the enclosing catch block (if known). */ | |
779 exp = cp_build_function_call_vec (rethrow_fn, NULL, tf_warning_or_error); | |
780 } | |
781 | |
782 exp = build1 (THROW_EXPR, void_type_node, exp); | |
783 SET_EXPR_LOCATION (exp, input_location); | |
784 | |
785 return exp; | |
786 } | |
787 | |
788 /* Make sure TYPE is complete, pointer to complete, reference to | |
789 complete, or pointer to cv void. Issue diagnostic on failure. | |
790 Return the zero on failure and nonzero on success. FROM can be | |
791 the expr or decl from whence TYPE came, if available. */ | |
792 | |
793 static int | |
794 complete_ptr_ref_or_void_ptr_p (tree type, tree from) | |
795 { | |
796 int is_ptr; | |
797 | |
798 /* Check complete. */ | |
799 type = complete_type_or_else (type, from); | |
800 if (!type) | |
801 return 0; | |
802 | |
803 /* Or a pointer or ref to one, or cv void *. */ | |
804 is_ptr = TYPE_PTR_P (type); | |
805 if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE) | |
806 { | |
807 tree core = TREE_TYPE (type); | |
808 | |
809 if (is_ptr && VOID_TYPE_P (core)) | |
810 /* OK */; | |
811 else if (!complete_type_or_else (core, from)) | |
812 return 0; | |
813 } | |
814 return 1; | |
815 } | |
816 | |
817 /* If IS_THROW is true return truth-value if T is an expression admissible | |
818 in throw-expression, i.e. if it is not of incomplete type or a pointer/ | |
819 reference to such a type or of an abstract class type. | |
820 If IS_THROW is false, likewise for a catch parameter, same requirements | |
821 for its type plus rvalue reference type is also not admissible. */ | |
822 | |
823 static bool | |
824 is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw) | |
825 { | |
826 tree expr = is_throw ? t : NULL_TREE; | |
827 tree type = TREE_TYPE (t); | |
828 | |
829 /* C++11 [except.handle] The exception-declaration shall not denote | |
830 an incomplete type, an abstract class type, or an rvalue reference | |
831 type. */ | |
832 | |
833 /* 15.1/4 [...] The type of the throw-expression shall not be an | |
834 incomplete type, or a pointer or a reference to an incomplete | |
835 type, other than void*, const void*, volatile void*, or | |
836 const volatile void*. Except for these restriction and the | |
837 restrictions on type matching mentioned in 15.3, the operand | |
838 of throw is treated exactly as a function argument in a call | |
839 (5.2.2) or the operand of a return statement. */ | |
840 if (!complete_ptr_ref_or_void_ptr_p (type, expr)) | |
841 return false; | |
842 | |
843 /* 10.4/3 An abstract class shall not be used as a parameter type, | |
844 as a function return type or as type of an explicit | |
845 conversion. */ | |
846 else if (abstract_virtuals_error (is_throw ? ACU_THROW : ACU_CATCH, type)) | |
847 return false; | |
848 else if (!is_throw | |
849 && TREE_CODE (type) == REFERENCE_TYPE | |
850 && TYPE_REF_IS_RVALUE (type)) | |
851 { | |
852 error ("cannot declare catch parameter to be of rvalue " | |
853 "reference type %qT", type); | |
854 return false; | |
855 } | |
856 else if (variably_modified_type_p (type, NULL_TREE)) | |
857 { | |
858 if (is_throw) | |
859 error ("cannot throw expression of type %qT because it involves " | |
860 "types of variable size", type); | |
861 else | |
862 error ("cannot catch type %qT because it involves types of " | |
863 "variable size", type); | |
864 return false; | |
865 } | |
866 | |
867 return true; | |
868 } | |
869 | |
870 /* Returns nonzero if FN is a declaration of a standard C library | |
871 function which is known not to throw. | |
872 | |
873 [lib.res.on.exception.handling]: None of the functions from the | |
874 Standard C library shall report an error by throwing an | |
875 exception, unless it calls a program-supplied function that | |
876 throws an exception. */ | |
877 | |
878 #include "cfns.h" | |
879 | |
880 int | |
881 nothrow_libfn_p (const_tree fn) | |
882 { | |
883 tree id; | |
884 | |
885 if (TREE_PUBLIC (fn) | |
886 && DECL_EXTERNAL (fn) | |
887 && DECL_NAMESPACE_SCOPE_P (fn) | |
888 && DECL_EXTERN_C_P (fn)) | |
889 /* OK */; | |
890 else | |
891 /* Can't be a C library function. */ | |
892 return 0; | |
893 | |
894 /* Being a C library function, DECL_ASSEMBLER_NAME == DECL_NAME | |
895 unless the system headers are playing rename tricks, and if | |
896 they are, we don't want to be confused by them. */ | |
897 id = DECL_NAME (fn); | |
898 const struct libc_name_struct *s | |
899 = libc_name::libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id)); | |
900 if (s == NULL) | |
901 return 0; | |
902 switch (s->c_ver) | |
903 { | |
904 case 89: return 1; | |
905 case 99: return !flag_iso || flag_isoc99; | |
906 case 11: return !flag_iso || flag_isoc11; | |
907 default: gcc_unreachable (); | |
908 } | |
909 } | |
910 | |
911 /* Returns nonzero if an exception of type FROM will be caught by a | |
912 handler for type TO, as per [except.handle]. */ | |
913 | |
914 static int | |
915 can_convert_eh (tree to, tree from) | |
916 { | |
917 to = non_reference (to); | |
918 from = non_reference (from); | |
919 | |
920 if (TYPE_PTR_P (to) && TYPE_PTR_P (from)) | |
921 { | |
922 to = TREE_TYPE (to); | |
923 from = TREE_TYPE (from); | |
924 | |
925 if (! at_least_as_qualified_p (to, from)) | |
926 return 0; | |
927 | |
928 if (VOID_TYPE_P (to)) | |
929 return 1; | |
930 | |
931 /* Else fall through. */ | |
932 } | |
933 | |
934 if (CLASS_TYPE_P (to) && CLASS_TYPE_P (from) | |
935 && publicly_uniquely_derived_p (to, from)) | |
936 return 1; | |
937 | |
938 return 0; | |
939 } | |
940 | |
941 /* Check whether any of the handlers in I are shadowed by another handler | |
942 accepting TYPE. Note that the shadowing may not be complete; even if | |
943 an exception of type B would be caught by a handler for A, there could | |
944 be a derived class C for which A is an ambiguous base but B is not, so | |
945 the handler for B would catch an exception of type C. */ | |
946 | |
947 static void | |
948 check_handlers_1 (tree master, tree_stmt_iterator i) | |
949 { | |
950 tree type = TREE_TYPE (master); | |
951 | |
952 for (; !tsi_end_p (i); tsi_next (&i)) | |
953 { | |
954 tree handler = tsi_stmt (i); | |
955 if (TREE_TYPE (handler) && can_convert_eh (type, TREE_TYPE (handler))) | |
956 { | |
957 warning_at (EXPR_LOCATION (handler), 0, | |
958 "exception of type %qT will be caught", | |
959 TREE_TYPE (handler)); | |
960 warning_at (EXPR_LOCATION (master), 0, | |
961 " by earlier handler for %qT", type); | |
962 break; | |
963 } | |
964 } | |
965 } | |
966 | |
967 /* Given a STATEMENT_LIST of HANDLERs, make sure that they're OK. */ | |
968 | |
969 void | |
970 check_handlers (tree handlers) | |
971 { | |
972 tree_stmt_iterator i; | |
973 | |
974 /* If we don't have a STATEMENT_LIST, then we've just got one | |
975 handler, and thus nothing to warn about. */ | |
976 if (TREE_CODE (handlers) != STATEMENT_LIST) | |
977 return; | |
978 | |
979 i = tsi_start (handlers); | |
980 if (!tsi_end_p (i)) | |
981 while (1) | |
982 { | |
983 tree handler = tsi_stmt (i); | |
984 tsi_next (&i); | |
985 | |
986 /* No more handlers; nothing to shadow. */ | |
987 if (tsi_end_p (i)) | |
988 break; | |
989 if (TREE_TYPE (handler) == NULL_TREE) | |
990 permerror (EXPR_LOCATION (handler), "%<...%>" | |
991 " handler must be the last handler for its try block"); | |
992 else | |
993 check_handlers_1 (handler, i); | |
994 } | |
995 } | |
996 | |
997 /* walk_tree helper for finish_noexcept_expr. Returns non-null if the | |
998 expression *TP causes the noexcept operator to evaluate to false. | |
999 | |
1000 5.3.7 [expr.noexcept]: The result of the noexcept operator is false if | |
1001 in a potentially-evaluated context the expression would contain | |
1002 * a potentially evaluated call to a function, member function, | |
1003 function pointer, or member function pointer that does not have a | |
1004 non-throwing exception-specification (15.4), | |
1005 * a potentially evaluated throw-expression (15.1), | |
1006 * a potentially evaluated dynamic_cast expression dynamic_cast<T>(v), | |
1007 where T is a reference type, that requires a run-time check (5.2.7), or | |
1008 * a potentially evaluated typeid expression (5.2.8) applied to a glvalue | |
1009 expression whose type is a polymorphic class type (10.3). */ | |
1010 | |
1011 static tree | |
1012 check_noexcept_r (tree *tp, int * /*walk_subtrees*/, void * /*data*/) | |
1013 { | |
1014 tree t = *tp; | |
1015 enum tree_code code = TREE_CODE (t); | |
1016 if ((code == CALL_EXPR && CALL_EXPR_FN (t)) | |
1017 || code == AGGR_INIT_EXPR) | |
1018 { | |
1019 /* We can only use the exception specification of the called function | |
1020 for determining the value of a noexcept expression; we can't use | |
1021 TREE_NOTHROW, as it might have a different value in another | |
1022 translation unit, creating ODR problems. | |
1023 | |
1024 We could use TREE_NOTHROW (t) for !TREE_PUBLIC fns, though... */ | |
1025 tree fn = cp_get_callee (t); | |
1026 tree type = TREE_TYPE (fn); | |
1027 gcc_assert (POINTER_TYPE_P (type)); | |
1028 type = TREE_TYPE (type); | |
1029 | |
1030 STRIP_NOPS (fn); | |
1031 if (TREE_CODE (fn) == ADDR_EXPR) | |
1032 fn = TREE_OPERAND (fn, 0); | |
1033 if (TREE_CODE (fn) == FUNCTION_DECL) | |
1034 { | |
1035 /* We do use TREE_NOTHROW for ABI internals like __dynamic_cast, | |
1036 and for C library functions known not to throw. */ | |
1037 if (DECL_EXTERN_C_P (fn) | |
1038 && (DECL_ARTIFICIAL (fn) | |
1039 || nothrow_libfn_p (fn))) | |
1040 return TREE_NOTHROW (fn) ? NULL_TREE : fn; | |
1041 /* A call to a constexpr function is noexcept if the call | |
1042 is a constant expression. */ | |
1043 if (DECL_DECLARED_CONSTEXPR_P (fn) | |
1044 && is_sub_constant_expr (t)) | |
1045 return NULL_TREE; | |
1046 } | |
1047 if (!TYPE_NOTHROW_P (type)) | |
1048 return fn; | |
1049 } | |
1050 | |
1051 return NULL_TREE; | |
1052 } | |
1053 | |
1054 /* If a function that causes a noexcept-expression to be false isn't | |
1055 defined yet, remember it and check it for TREE_NOTHROW again at EOF. */ | |
1056 | |
1057 struct GTY(()) pending_noexcept { | |
1058 tree fn; | |
1059 location_t loc; | |
1060 }; | |
1061 static GTY(()) vec<pending_noexcept, va_gc> *pending_noexcept_checks; | |
1062 | |
1063 /* FN is a FUNCTION_DECL that caused a noexcept-expr to be false. Warn if | |
1064 it can't throw. */ | |
1065 | |
1066 static void | |
1067 maybe_noexcept_warning (tree fn) | |
1068 { | |
1069 if (TREE_NOTHROW (fn)) | |
1070 { | |
1071 warning (OPT_Wnoexcept, "noexcept-expression evaluates to %<false%> " | |
1072 "because of a call to %qD", fn); | |
1073 warning_at (DECL_SOURCE_LOCATION (fn), OPT_Wnoexcept, | |
1074 "but %qD does not throw; perhaps " | |
1075 "it should be declared %<noexcept%>", fn); | |
1076 } | |
1077 } | |
1078 | |
1079 /* Check any functions that weren't defined earlier when they caused a | |
1080 noexcept expression to evaluate to false. */ | |
1081 | |
1082 void | |
1083 perform_deferred_noexcept_checks (void) | |
1084 { | |
1085 int i; | |
1086 pending_noexcept *p; | |
1087 location_t saved_loc = input_location; | |
1088 FOR_EACH_VEC_SAFE_ELT (pending_noexcept_checks, i, p) | |
1089 { | |
1090 input_location = p->loc; | |
1091 maybe_noexcept_warning (p->fn); | |
1092 } | |
1093 input_location = saved_loc; | |
1094 } | |
1095 | |
1096 /* Evaluate noexcept ( EXPR ). */ | |
1097 | |
1098 tree | |
1099 finish_noexcept_expr (tree expr, tsubst_flags_t complain) | |
1100 { | |
1101 if (expr == error_mark_node) | |
1102 return error_mark_node; | |
1103 | |
1104 if (processing_template_decl) | |
1105 return build_min (NOEXCEPT_EXPR, boolean_type_node, expr); | |
1106 | |
1107 return (expr_noexcept_p (expr, complain) | |
1108 ? boolean_true_node : boolean_false_node); | |
1109 } | |
1110 | |
1111 /* Returns whether EXPR is noexcept, possibly warning if allowed by | |
1112 COMPLAIN. */ | |
1113 | |
1114 bool | |
1115 expr_noexcept_p (tree expr, tsubst_flags_t complain) | |
1116 { | |
1117 tree fn; | |
1118 | |
1119 if (expr == error_mark_node) | |
1120 return false; | |
1121 | |
1122 fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0); | |
1123 if (fn) | |
1124 { | |
1125 if ((complain & tf_warning) && warn_noexcept | |
1126 && TREE_CODE (fn) == FUNCTION_DECL) | |
1127 { | |
1128 if (!DECL_INITIAL (fn)) | |
1129 { | |
1130 /* Not defined yet; check again at EOF. */ | |
1131 pending_noexcept p = {fn, input_location}; | |
1132 vec_safe_push (pending_noexcept_checks, p); | |
1133 } | |
1134 else | |
1135 maybe_noexcept_warning (fn); | |
1136 } | |
1137 return false; | |
1138 } | |
1139 else | |
1140 return true; | |
1141 } | |
1142 | |
1143 /* Return true iff SPEC is throw() or noexcept(true). */ | |
1144 | |
1145 bool | |
1146 nothrow_spec_p (const_tree spec) | |
1147 { | |
1148 gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec)); | |
1149 | |
1150 if (spec == empty_except_spec | |
1151 || spec == noexcept_true_spec) | |
1152 return true; | |
1153 | |
1154 gcc_assert (!spec | |
1155 || TREE_VALUE (spec) | |
1156 || spec == noexcept_false_spec | |
1157 || TREE_PURPOSE (spec) == error_mark_node | |
1158 || processing_template_decl); | |
1159 | |
1160 return false; | |
1161 } | |
1162 | |
1163 /* For FUNCTION_TYPE or METHOD_TYPE, true if NODE is noexcept. This is the | |
1164 case for things declared noexcept(true) and, with -fnothrow-opt, for | |
1165 throw() functions. */ | |
1166 | |
1167 bool | |
1168 type_noexcept_p (const_tree type) | |
1169 { | |
1170 tree spec = TYPE_RAISES_EXCEPTIONS (type); | |
1171 gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec)); | |
1172 if (flag_nothrow_opt) | |
1173 return nothrow_spec_p (spec); | |
1174 else | |
1175 return spec == noexcept_true_spec; | |
1176 } | |
1177 | |
1178 /* For FUNCTION_TYPE or METHOD_TYPE, true if NODE can throw any type, | |
1179 i.e. no exception-specification or noexcept(false). */ | |
1180 | |
1181 bool | |
1182 type_throw_all_p (const_tree type) | |
1183 { | |
1184 tree spec = TYPE_RAISES_EXCEPTIONS (type); | |
1185 gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec)); | |
1186 return spec == NULL_TREE || spec == noexcept_false_spec; | |
1187 } | |
1188 | |
1189 /* Create a representation of the noexcept-specification with | |
1190 constant-expression of EXPR. COMPLAIN is as for tsubst. */ | |
1191 | |
1192 tree | |
1193 build_noexcept_spec (tree expr, int complain) | |
1194 { | |
1195 /* This isn't part of the signature, so don't bother trying to evaluate | |
1196 it until instantiation. */ | |
1197 if (!processing_template_decl && TREE_CODE (expr) != DEFERRED_NOEXCEPT) | |
1198 { | |
1199 expr = perform_implicit_conversion_flags (boolean_type_node, expr, | |
1200 complain, | |
1201 LOOKUP_NORMAL); | |
1202 expr = cxx_constant_value (expr); | |
1203 } | |
1204 if (TREE_CODE (expr) == INTEGER_CST) | |
1205 { | |
1206 if (operand_equal_p (expr, boolean_true_node, 0)) | |
1207 return noexcept_true_spec; | |
1208 else | |
1209 { | |
1210 gcc_checking_assert (operand_equal_p (expr, boolean_false_node, 0)); | |
1211 return noexcept_false_spec; | |
1212 } | |
1213 } | |
1214 else if (expr == error_mark_node) | |
1215 return error_mark_node; | |
1216 else | |
1217 { | |
1218 gcc_assert (processing_template_decl | |
1219 || TREE_CODE (expr) == DEFERRED_NOEXCEPT); | |
1220 return build_tree_list (expr, NULL_TREE); | |
1221 } | |
1222 } | |
1223 | |
1224 /* Returns a TRY_CATCH_EXPR that will put TRY_LIST and CATCH_LIST in the | |
1225 TRY and CATCH locations. CATCH_LIST must be a STATEMENT_LIST */ | |
1226 | |
1227 tree | |
1228 create_try_catch_expr (tree try_expr, tree catch_list) | |
1229 { | |
1230 location_t loc = EXPR_LOCATION (try_expr); | |
1231 | |
1232 append_to_statement_list (do_begin_catch (), &catch_list); | |
1233 append_to_statement_list (build_throw (NULL_TREE), &catch_list); | |
1234 tree catch_tf_expr = build_stmt (loc, TRY_FINALLY_EXPR, catch_list, | |
1235 do_end_catch (NULL_TREE)); | |
1236 catch_list = build2 (CATCH_EXPR, void_type_node, NULL_TREE, | |
1237 catch_tf_expr); | |
1238 tree try_catch_expr = build_stmt (loc, TRY_CATCH_EXPR, try_expr, catch_list); | |
1239 return try_catch_expr; | |
1240 } | |
1241 | |
1242 #include "gt-cp-except.h" |