1 /* Handle exceptional things in C++.
2 Copyright (C) 1989-2022 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 #include "target.h"
33
34 static void push_eh_cleanup (tree);
35 static tree prepare_eh_type (tree);
36 static tree do_begin_catch (void);
37 static int dtor_nothrow (tree);
38 static tree do_end_catch (tree);
39 static void initialize_handler_parm (tree, tree);
40 static tree do_allocate_exception (tree);
41 static tree wrap_cleanups_r (tree *, int *, void *);
42 static int complete_ptr_ref_or_void_ptr_p (tree, tree);
43 static bool is_admissible_throw_operand_or_catch_parameter (tree, bool);
44
45 /* Sets up all the global eh stuff that needs to be initialized at the
46 start of compilation. */
47
48 void
init_exception_processing(void)49 init_exception_processing (void)
50 {
51 tree tmp;
52
53 /* void std::terminate (); */
54 push_nested_namespace (std_node);
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_nested_namespace (std_node);
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
cp_protect_cleanup_actions(void)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
prepare_eh_type(tree type)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
eh_type_info(tree type)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
build_eh_type_type(tree type)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
build_exc_ptr(void)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 /* Declare an exception ABI entry point called NAME.
136 ECF are the library flags, RTYPE the return type and ARGS[NARGS]
137 the parameter types. We return the DECL -- which might be one
138 found via the symbol table pushing, if the user already declared
139 it. If we pushed a new decl, the user will see it. */
140
141 static tree
declare_library_fn_1(const char * name,int ecf,tree rtype,int nargs,tree args[])142 declare_library_fn_1 (const char *name, int ecf,
143 tree rtype, int nargs, tree args[])
144 {
145 tree ident = get_identifier (name);
146 tree except = ecf & ECF_NOTHROW ? empty_except_spec : NULL_TREE;
147
148 /* Make a new decl. */
149 tree arg_list = void_list_node;
150 for (unsigned ix = nargs; ix--;)
151 arg_list = tree_cons (NULL_TREE, args[ix], arg_list);
152 tree fntype = build_function_type (rtype, arg_list);
153 tree res = push_library_fn (ident, fntype, except, ecf);
154
155 return res;
156 }
157
158 /* Find or declare a function NAME, returning RTYPE, taking a single
159 parameter PTYPE, with an empty exception specification. ECF are the
160 library fn flags. If TM_ECF is non-zero, also find or create a
161 transaction variant and record it as a replacement, when flag_tm is
162 in effect.
163
164 Note that the C++ ABI document does not have a throw-specifier on
165 the routines declared below via this function. The declarations
166 are consistent with the actual implementations in libsupc++. */
167
168 static tree
declare_library_fn(const char * name,tree rtype,tree ptype,int ecf,int tm_ecf)169 declare_library_fn (const char *name, tree rtype, tree ptype,
170 int ecf, int tm_ecf)
171 {
172 tree res = declare_library_fn_1 (name, ecf, rtype, ptype ? 1 : 0, &ptype);
173 if (res == error_mark_node)
174 return res;
175
176 if (tm_ecf && flag_tm)
177 {
178 char *tm_name = concat ("_ITM_", name + 2, NULL_TREE);
179
180 tree tm_fn = declare_library_fn_1 (tm_name, ecf | tm_ecf, rtype,
181 ptype ? 1 : 0, &ptype);
182 free (tm_name);
183 if (tm_fn != error_mark_node)
184 record_tm_replacement (res, tm_fn);
185 }
186
187 return res;
188 }
189
190 /* Build up a call to __cxa_get_exception_ptr so that we can build a
191 copy constructor for the thrown object. */
192
193 static tree
do_get_exception_ptr(void)194 do_get_exception_ptr (void)
195 {
196 if (!get_exception_ptr_fn)
197 /* Declare void* __cxa_get_exception_ptr (void *) throw(). */
198 get_exception_ptr_fn
199 = declare_library_fn ("__cxa_get_exception_ptr",
200 ptr_type_node, ptr_type_node,
201 ECF_NOTHROW | ECF_PURE | ECF_LEAF | ECF_TM_PURE,
202 0);
203
204 return cp_build_function_call_nary (get_exception_ptr_fn,
205 tf_warning_or_error,
206 build_exc_ptr (), NULL_TREE);
207 }
208
209 /* Build up a call to __cxa_begin_catch, to tell the runtime that the
210 exception has been handled. */
211
212 static tree
do_begin_catch(void)213 do_begin_catch (void)
214 {
215 if (!begin_catch_fn)
216 /* Declare void* __cxa_begin_catch (void *) throw(). */
217 begin_catch_fn
218 = declare_library_fn ("__cxa_begin_catch",
219 ptr_type_node, ptr_type_node, ECF_NOTHROW,
220 ECF_TM_PURE);
221
222 return cp_build_function_call_nary (begin_catch_fn, tf_warning_or_error,
223 build_exc_ptr (), NULL_TREE);
224 }
225
226 /* Returns nonzero if cleaning up an exception of type TYPE (which can be
227 NULL_TREE for a ... handler) will not throw an exception. */
228
229 static int
dtor_nothrow(tree type)230 dtor_nothrow (tree type)
231 {
232 if (type == NULL_TREE || type == error_mark_node)
233 return 0;
234
235 if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
236 return 1;
237
238 if (CLASSTYPE_LAZY_DESTRUCTOR (type))
239 lazily_declare_fn (sfk_destructor, type);
240
241 return TREE_NOTHROW (CLASSTYPE_DESTRUCTOR (type));
242 }
243
244 /* Build up a call to __cxa_end_catch, to destroy the exception object
245 for the current catch block if no others are currently using it. */
246
247 static tree
do_end_catch(tree type)248 do_end_catch (tree type)
249 {
250 if (!end_catch_fn)
251 /* Declare void __cxa_end_catch ().
252 This can throw if the destructor for the exception throws. */
253 end_catch_fn
254 = declare_library_fn ("__cxa_end_catch", void_type_node,
255 NULL_TREE, 0, ECF_TM_PURE);
256
257 tree cleanup = cp_build_function_call_vec (end_catch_fn,
258 NULL, tf_warning_or_error);
259 if (cleanup != error_mark_node)
260 TREE_NOTHROW (cleanup) = dtor_nothrow (type);
261
262 return cleanup;
263 }
264
265 /* This routine creates the cleanup for the current exception. */
266
267 static void
push_eh_cleanup(tree type)268 push_eh_cleanup (tree type)
269 {
270 finish_decl_cleanup (NULL_TREE, do_end_catch (type));
271 }
272
273 /* Wrap EXPR in a MUST_NOT_THROW_EXPR expressing that EXPR must
274 not throw any exceptions if COND is true. A condition of
275 NULL_TREE is treated as 'true'. */
276
277 tree
build_must_not_throw_expr(tree body,tree cond)278 build_must_not_throw_expr (tree body, tree cond)
279 {
280 tree type = body ? TREE_TYPE (body) : void_type_node;
281
282 if (!flag_exceptions)
283 return body;
284
285 if (!cond)
286 /* OK, unconditional. */;
287 else
288 {
289 tree conv = NULL_TREE;
290 if (!type_dependent_expression_p (cond))
291 conv = perform_implicit_conversion_flags (boolean_type_node, cond,
292 tf_warning_or_error,
293 LOOKUP_NORMAL);
294 if (tree inst = instantiate_non_dependent_or_null (conv))
295 cond = cxx_constant_value (inst);
296 else
297 require_constant_expression (cond);
298 if (integer_zerop (cond))
299 return body;
300 else if (integer_onep (cond))
301 cond = NULL_TREE;
302 }
303
304 return build2 (MUST_NOT_THROW_EXPR, type, body, cond);
305 }
306
307
308 /* Initialize the catch parameter DECL. */
309
310 static void
initialize_handler_parm(tree decl,tree exp)311 initialize_handler_parm (tree decl, tree exp)
312 {
313 tree init;
314 tree init_type;
315
316 /* Make sure we mark the catch param as used, otherwise we'll get a
317 warning about an unused ((anonymous)). */
318 TREE_USED (decl) = 1;
319 DECL_READ_P (decl) = 1;
320
321 /* Figure out the type that the initializer is. Pointers are returned
322 adjusted by value from __cxa_begin_catch. Others are returned by
323 reference. */
324 init_type = TREE_TYPE (decl);
325 if (!INDIRECT_TYPE_P (init_type))
326 init_type = build_reference_type (init_type);
327
328 /* Since pointers are passed by value, initialize a reference to
329 pointer catch parm with the address of the temporary. */
330 if (TYPE_REF_P (init_type)
331 && TYPE_PTR_P (TREE_TYPE (init_type)))
332 exp = cp_build_addr_expr (exp, tf_warning_or_error);
333
334 exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0,
335 tf_warning_or_error);
336
337 init = convert_from_reference (exp);
338
339 /* If the constructor for the catch parm exits via an exception, we
340 must call terminate. See eh23.C. */
341 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
342 {
343 /* Generate the copy constructor call directly so we can wrap it.
344 See also expand_default_init. */
345 init = ocp_convert (TREE_TYPE (decl), init,
346 CONV_IMPLICIT|CONV_FORCE_TEMP, 0,
347 tf_warning_or_error);
348 /* Force cleanups now to avoid nesting problems with the
349 MUST_NOT_THROW_EXPR. */
350 init = fold_build_cleanup_point_expr (TREE_TYPE (init), init);
351 init = build_must_not_throw_expr (init, NULL_TREE);
352 }
353
354 decl = pushdecl (decl);
355
356 start_decl_1 (decl, true);
357 cp_finish_decl (decl, init, /*init_const_expr_p=*/false, NULL_TREE,
358 LOOKUP_ONLYCONVERTING|DIRECT_BIND);
359 }
360
361
362 /* Routine to see if exception handling is turned on.
363 DO_WARN is nonzero if we want to inform the user that exception
364 handling is turned off.
365
366 This is used to ensure that -fexceptions has been specified if the
367 compiler tries to use any exception-specific functions. */
368
369 static inline int
doing_eh(void)370 doing_eh (void)
371 {
372 if (! flag_exceptions)
373 {
374 static int warned = 0;
375 if (! warned)
376 {
377 error ("exception handling disabled, use %<-fexceptions%> to enable");
378 warned = 1;
379 }
380 return 0;
381 }
382 return 1;
383 }
384
385 /* Call this to start a catch block. DECL is the catch parameter. */
386
387 tree
expand_start_catch_block(tree decl)388 expand_start_catch_block (tree decl)
389 {
390 tree exp;
391 tree type, init;
392
393 if (! doing_eh ())
394 return NULL_TREE;
395
396 if (decl)
397 {
398 if (!is_admissible_throw_operand_or_catch_parameter (decl, false))
399 decl = error_mark_node;
400
401 type = prepare_eh_type (TREE_TYPE (decl));
402 mark_used (eh_type_info (type));
403 }
404 else
405 type = NULL_TREE;
406
407 /* Call __cxa_end_catch at the end of processing the exception. */
408 push_eh_cleanup (type);
409
410 init = do_begin_catch ();
411
412 /* If there's no decl at all, then all we need to do is make sure
413 to tell the runtime that we've begun handling the exception. */
414 if (decl == NULL || decl == error_mark_node || init == error_mark_node)
415 finish_expr_stmt (init);
416
417 /* If the C++ object needs constructing, we need to do that before
418 calling __cxa_begin_catch, so that std::uncaught_exception gets
419 the right value during the copy constructor. */
420 else if (flag_use_cxa_get_exception_ptr
421 && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
422 {
423 exp = do_get_exception_ptr ();
424 if (exp != error_mark_node)
425 initialize_handler_parm (decl, exp);
426 finish_expr_stmt (init);
427 }
428
429 /* Otherwise the type uses a bitwise copy, and we don't have to worry
430 about the value of std::uncaught_exception and therefore can do the
431 copy with the return value of __cxa_end_catch instead. */
432 else
433 {
434 tree init_type = type;
435
436 /* Pointers are passed by values, everything else by reference. */
437 if (!TYPE_PTR_P (type))
438 init_type = build_pointer_type (type);
439 if (init_type != TREE_TYPE (init))
440 init = build1 (NOP_EXPR, init_type, init);
441 exp = create_temporary_var (init_type);
442 cp_finish_decl (exp, init, /*init_const_expr=*/false,
443 NULL_TREE, LOOKUP_ONLYCONVERTING);
444 DECL_REGISTER (exp) = 1;
445 initialize_handler_parm (decl, exp);
446 }
447
448 return type;
449 }
450
451 /* True if we are in a catch block within a catch block. Assumes that we are
452 in function scope. */
453
454 static bool
in_nested_catch(void)455 in_nested_catch (void)
456 {
457 int catches = 0;
458
459 /* Scan through the template parameter scopes. */
460 for (cp_binding_level *b = current_binding_level;
461 b->kind != sk_function_parms;
462 b = b->level_chain)
463 if (b->kind == sk_catch
464 && ++catches == 2)
465 return true;
466 return false;
467 }
468
469 /* Call this to end a catch block. Its responsible for emitting the
470 code to handle jumping back to the correct place, and for emitting
471 the label to jump to if this catch block didn't match. */
472
473 void
expand_end_catch_block(void)474 expand_end_catch_block (void)
475 {
476 if (! doing_eh ())
477 return;
478
479 /* The exception being handled is rethrown if control reaches the end of
480 a handler of the function-try-block of a constructor or destructor. */
481 if (in_function_try_handler
482 && (DECL_CONSTRUCTOR_P (current_function_decl)
483 || DECL_DESTRUCTOR_P (current_function_decl))
484 && !in_nested_catch ())
485 {
486 tree rethrow = build_throw (input_location, NULL_TREE);
487 /* Disable all warnings for the generated rethrow statement. */
488 suppress_warning (rethrow);
489 finish_expr_stmt (rethrow);
490 }
491 }
492
493 tree
begin_eh_spec_block(void)494 begin_eh_spec_block (void)
495 {
496 tree r;
497 location_t spec_location = DECL_SOURCE_LOCATION (current_function_decl);
498
499 /* A noexcept specification (or throw() with -fnothrow-opt) is a
500 MUST_NOT_THROW_EXPR. */
501 if (TYPE_NOEXCEPT_P (TREE_TYPE (current_function_decl)))
502 {
503 r = build_stmt (spec_location, MUST_NOT_THROW_EXPR,
504 NULL_TREE, NULL_TREE);
505 TREE_SIDE_EFFECTS (r) = 1;
506 }
507 else
508 r = build_stmt (spec_location, EH_SPEC_BLOCK, NULL_TREE, NULL_TREE);
509 add_stmt (r);
510 TREE_OPERAND (r, 0) = push_stmt_list ();
511 return r;
512 }
513
514 void
finish_eh_spec_block(tree raw_raises,tree eh_spec_block)515 finish_eh_spec_block (tree raw_raises, tree eh_spec_block)
516 {
517 tree raises;
518
519 TREE_OPERAND (eh_spec_block, 0)
520 = pop_stmt_list (TREE_OPERAND (eh_spec_block, 0));
521
522 if (TREE_CODE (eh_spec_block) == MUST_NOT_THROW_EXPR)
523 return;
524
525 /* Strip cv quals, etc, from the specification types. */
526 for (raises = NULL_TREE;
527 raw_raises && TREE_VALUE (raw_raises);
528 raw_raises = TREE_CHAIN (raw_raises))
529 {
530 tree type = prepare_eh_type (TREE_VALUE (raw_raises));
531 tree tinfo = eh_type_info (type);
532
533 mark_used (tinfo);
534 raises = tree_cons (NULL_TREE, type, raises);
535 }
536
537 EH_SPEC_RAISES (eh_spec_block) = raises;
538 }
539
540 /* Return a pointer to a buffer for an exception object of type TYPE. */
541
542 static tree
do_allocate_exception(tree type)543 do_allocate_exception (tree type)
544 {
545 if (!allocate_exception_fn)
546 /* Declare void *__cxa_allocate_exception(size_t) throw(). */
547 allocate_exception_fn
548 = declare_library_fn ("__cxa_allocate_exception",
549 ptr_type_node, size_type_node,
550 ECF_NOTHROW | ECF_MALLOC | ECF_COLD, ECF_TM_PURE);
551
552 return cp_build_function_call_nary (allocate_exception_fn,
553 tf_warning_or_error,
554 size_in_bytes (type), NULL_TREE);
555 }
556
557 /* Call __cxa_free_exception from a cleanup. This is never invoked
558 directly, but see the comment for stabilize_throw_expr. */
559
560 static tree
do_free_exception(tree ptr)561 do_free_exception (tree ptr)
562 {
563 if (!free_exception_fn)
564 /* Declare void __cxa_free_exception (void *) throw(). */
565 free_exception_fn
566 = declare_library_fn ("__cxa_free_exception",
567 void_type_node, ptr_type_node,
568 ECF_NOTHROW | ECF_LEAF, ECF_TM_PURE);
569
570 return cp_build_function_call_nary (free_exception_fn,
571 tf_warning_or_error, ptr, NULL_TREE);
572 }
573
574 /* Wrap all cleanups for TARGET_EXPRs in MUST_NOT_THROW_EXPR.
575 Called from build_throw via walk_tree_without_duplicates. */
576
577 static tree
wrap_cleanups_r(tree * tp,int * walk_subtrees,void *)578 wrap_cleanups_r (tree *tp, int *walk_subtrees, void * /*data*/)
579 {
580 tree exp = *tp;
581 tree cleanup;
582
583 /* Don't walk into types. */
584 if (TYPE_P (exp))
585 {
586 *walk_subtrees = 0;
587 return NULL_TREE;
588 }
589 if (TREE_CODE (exp) != TARGET_EXPR)
590 return NULL_TREE;
591
592 cleanup = TARGET_EXPR_CLEANUP (exp);
593 if (cleanup)
594 {
595 cleanup = build2 (MUST_NOT_THROW_EXPR, void_type_node, cleanup,
596 NULL_TREE);
597 TARGET_EXPR_CLEANUP (exp) = cleanup;
598 }
599
600 /* Keep iterating. */
601 return NULL_TREE;
602 }
603
604 /* Build a throw expression. */
605
606 tree
build_throw(location_t loc,tree exp)607 build_throw (location_t loc, tree exp)
608 {
609 if (exp == error_mark_node)
610 return exp;
611
612 if (processing_template_decl)
613 {
614 if (cfun)
615 current_function_returns_abnormally = 1;
616 exp = build_min (THROW_EXPR, void_type_node, exp);
617 SET_EXPR_LOCATION (exp, loc);
618 return exp;
619 }
620
621 if (exp && null_node_p (exp))
622 warning_at (loc, 0,
623 "throwing NULL, which has integral, not pointer type");
624
625 if (exp != NULL_TREE)
626 {
627 if (!is_admissible_throw_operand_or_catch_parameter (exp, true))
628 return error_mark_node;
629 }
630
631 if (! doing_eh ())
632 return error_mark_node;
633
634 if (exp)
635 {
636 tree throw_type;
637 tree temp_type;
638 tree cleanup;
639 tree object, ptr;
640 tree allocate_expr;
641
642 /* The CLEANUP_TYPE is the internal type of a destructor. */
643 if (!cleanup_type)
644 {
645 tree tmp = build_function_type_list (void_type_node,
646 ptr_type_node, NULL_TREE);
647 cleanup_type = build_pointer_type (tmp);
648 }
649
650 if (!throw_fn)
651 {
652 tree args[3] = {ptr_type_node, ptr_type_node, cleanup_type};
653
654 throw_fn = declare_library_fn_1 ("__cxa_throw",
655 ECF_NORETURN | ECF_COLD,
656 void_type_node, 3, args);
657 if (flag_tm && throw_fn != error_mark_node)
658 {
659 tree itm_fn = declare_library_fn_1 ("_ITM_cxa_throw",
660 ECF_NORETURN | ECF_COLD,
661 void_type_node, 3, args);
662 if (itm_fn != error_mark_node)
663 {
664 apply_tm_attr (itm_fn, get_identifier ("transaction_pure"));
665 record_tm_replacement (throw_fn, itm_fn);
666 }
667 }
668 }
669
670 /* [except.throw]
671
672 A throw-expression initializes a temporary object, the type
673 of which is determined by removing any top-level
674 cv-qualifiers from the static type of the operand of throw
675 and adjusting the type from "array of T" or "function return
676 T" to "pointer to T" or "pointer to function returning T"
677 respectively. */
678 temp_type = is_bitfield_expr_with_lowered_type (exp);
679 if (!temp_type)
680 temp_type = cv_unqualified (type_decays_to (TREE_TYPE (exp)));
681
682 /* OK, this is kind of wacky. The standard says that we call
683 terminate when the exception handling mechanism, after
684 completing evaluation of the expression to be thrown but
685 before the exception is caught (_except.throw_), calls a
686 user function that exits via an uncaught exception.
687
688 So we have to protect the actual initialization of the
689 exception object with terminate(), but evaluate the
690 expression first. Since there could be temps in the
691 expression, we need to handle that, too. We also expand
692 the call to __cxa_allocate_exception first (which doesn't
693 matter, since it can't throw). */
694
695 /* Allocate the space for the exception. */
696 allocate_expr = do_allocate_exception (temp_type);
697 if (allocate_expr == error_mark_node)
698 return error_mark_node;
699 allocate_expr = get_target_expr (allocate_expr);
700 ptr = TARGET_EXPR_SLOT (allocate_expr);
701 TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr);
702 CLEANUP_EH_ONLY (allocate_expr) = 1;
703
704 object = build_nop (build_pointer_type (temp_type), ptr);
705 object = cp_build_fold_indirect_ref (object);
706
707 /* And initialize the exception object. */
708 if (CLASS_TYPE_P (temp_type))
709 {
710 int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
711 bool converted = false;
712 location_t exp_loc = cp_expr_loc_or_loc (exp, loc);
713
714 /* Under C++0x [12.8/16 class.copy], a thrown lvalue is sometimes
715 treated as an rvalue for the purposes of overload resolution
716 to favor move constructors over copy constructors. */
717 if (tree moved = treat_lvalue_as_rvalue_p (exp, /*return*/false))
718 {
719 if (cxx_dialect < cxx20)
720 {
721 releasing_vec exp_vec (make_tree_vector_single (moved));
722 moved = (build_special_member_call
723 (object, complete_ctor_identifier, &exp_vec,
724 TREE_TYPE (object), flags|LOOKUP_PREFER_RVALUE,
725 tf_none));
726 if (moved != error_mark_node)
727 {
728 exp = moved;
729 converted = true;
730 }
731 }
732 else
733 /* In C++20 we just treat the return value as an rvalue that
734 can bind to lvalue refs. */
735 exp = moved;
736 }
737
738 /* Call the copy constructor. */
739 if (!converted)
740 {
741 releasing_vec exp_vec (make_tree_vector_single (exp));
742 exp = (build_special_member_call
743 (object, complete_ctor_identifier, &exp_vec,
744 TREE_TYPE (object), flags, tf_warning_or_error));
745 }
746
747 if (exp == error_mark_node)
748 {
749 inform (exp_loc, " in thrown expression");
750 return error_mark_node;
751 }
752 }
753 else
754 {
755 tree tmp = decay_conversion (exp, tf_warning_or_error);
756 if (tmp == error_mark_node)
757 return error_mark_node;
758 exp = build2 (INIT_EXPR, temp_type, object, tmp);
759 }
760
761 /* Mark any cleanups from the initialization as MUST_NOT_THROW, since
762 they are run after the exception object is initialized. */
763 cp_walk_tree_without_duplicates (&exp, wrap_cleanups_r, 0);
764
765 /* Prepend the allocation. */
766 exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp);
767
768 /* Force all the cleanups to be evaluated here so that we don't have
769 to do them during unwinding. */
770 exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp);
771
772 throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object)));
773
774 cleanup = NULL_TREE;
775 if (type_build_dtor_call (TREE_TYPE (object)))
776 {
777 tree dtor_fn = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
778 complete_dtor_identifier, 0,
779 tf_warning_or_error);
780 dtor_fn = BASELINK_FUNCTIONS (dtor_fn);
781 mark_used (dtor_fn);
782 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object)))
783 {
784 cxx_mark_addressable (dtor_fn);
785 /* Pretend it's a normal function. */
786 cleanup = build1 (ADDR_EXPR, cleanup_type, dtor_fn);
787 }
788 }
789 if (cleanup == NULL_TREE)
790 cleanup = build_int_cst (cleanup_type, 0);
791
792 /* ??? Indicate that this function call throws throw_type. */
793 tree tmp = cp_build_function_call_nary (throw_fn, tf_warning_or_error,
794 ptr, throw_type, cleanup,
795 NULL_TREE);
796
797 /* Tack on the initialization stuff. */
798 exp = build2 (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp);
799 }
800 else
801 {
802 /* Rethrow current exception. */
803 if (!rethrow_fn)
804 {
805 rethrow_fn = declare_library_fn_1 ("__cxa_rethrow",
806 ECF_NORETURN | ECF_COLD,
807 void_type_node, 0, NULL);
808 if (flag_tm && rethrow_fn != error_mark_node)
809 apply_tm_attr (rethrow_fn, get_identifier ("transaction_pure"));
810 }
811
812 /* ??? Indicate that this function call allows exceptions of the type
813 of the enclosing catch block (if known). */
814 exp = cp_build_function_call_vec (rethrow_fn, NULL, tf_warning_or_error);
815 }
816
817 exp = build1_loc (loc, THROW_EXPR, void_type_node, exp);
818
819 return exp;
820 }
821
822 /* Make sure TYPE is complete, pointer to complete, reference to
823 complete, or pointer to cv void. Issue diagnostic on failure.
824 Return the zero on failure and nonzero on success. FROM can be
825 the expr or decl from whence TYPE came, if available. */
826
827 static int
complete_ptr_ref_or_void_ptr_p(tree type,tree from)828 complete_ptr_ref_or_void_ptr_p (tree type, tree from)
829 {
830 int is_ptr;
831
832 /* Check complete. */
833 type = complete_type_or_else (type, from);
834 if (!type)
835 return 0;
836
837 /* Or a pointer or ref to one, or cv void *. */
838 is_ptr = TYPE_PTR_P (type);
839 if (is_ptr || TYPE_REF_P (type))
840 {
841 tree core = TREE_TYPE (type);
842
843 if (is_ptr && VOID_TYPE_P (core))
844 /* OK */;
845 else if (!complete_type_or_else (core, from))
846 return 0;
847 }
848 return 1;
849 }
850
851 /* If IS_THROW is true return truth-value if T is an expression admissible
852 in throw-expression, i.e. if it is not of incomplete type or a pointer/
853 reference to such a type or of an abstract class type.
854 If IS_THROW is false, likewise for a catch parameter, same requirements
855 for its type plus rvalue reference type is also not admissible. */
856
857 static bool
is_admissible_throw_operand_or_catch_parameter(tree t,bool is_throw)858 is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw)
859 {
860 tree expr = is_throw ? t : NULL_TREE;
861 tree type = TREE_TYPE (t);
862
863 /* C++11 [except.handle] The exception-declaration shall not denote
864 an incomplete type, an abstract class type, or an rvalue reference
865 type. */
866
867 /* 15.1/4 [...] The type of the throw-expression shall not be an
868 incomplete type, or a pointer or a reference to an incomplete
869 type, other than void*, const void*, volatile void*, or
870 const volatile void*. Except for these restriction and the
871 restrictions on type matching mentioned in 15.3, the operand
872 of throw is treated exactly as a function argument in a call
873 (5.2.2) or the operand of a return statement. */
874 if (!complete_ptr_ref_or_void_ptr_p (type, expr))
875 return false;
876
877 tree nonref_type = non_reference (type);
878 if (!verify_type_context (input_location, TCTX_EXCEPTIONS, nonref_type))
879 return false;
880
881 /* 10.4/3 An abstract class shall not be used as a parameter type,
882 as a function return type or as type of an explicit
883 conversion. */
884 else if (abstract_virtuals_error (is_throw ? ACU_THROW : ACU_CATCH, type))
885 return false;
886 else if (!is_throw
887 && TYPE_REF_P (type)
888 && TYPE_REF_IS_RVALUE (type))
889 {
890 error ("cannot declare %<catch%> parameter to be of rvalue "
891 "reference type %qT", type);
892 return false;
893 }
894 else if (variably_modified_type_p (type, NULL_TREE))
895 {
896 if (is_throw)
897 error_at (cp_expr_loc_or_input_loc (expr),
898 "cannot throw expression of type %qT because it involves "
899 "types of variable size", type);
900 else
901 error ("cannot catch type %qT because it involves types of "
902 "variable size", type);
903 return false;
904 }
905
906 return true;
907 }
908
909 /* Returns nonzero if FN is a declaration of a standard C library
910 function which is known not to throw.
911
912 [lib.res.on.exception.handling]: None of the functions from the
913 Standard C library shall report an error by throwing an
914 exception, unless it calls a program-supplied function that
915 throws an exception. */
916
917 #include "cfns.h"
918
919 int
nothrow_libfn_p(const_tree fn)920 nothrow_libfn_p (const_tree fn)
921 {
922 tree id;
923
924 if (TREE_PUBLIC (fn)
925 && DECL_EXTERNAL (fn)
926 && DECL_NAMESPACE_SCOPE_P (fn)
927 && DECL_EXTERN_C_P (fn))
928 /* OK */;
929 else
930 /* Can't be a C library function. */
931 return 0;
932
933 /* Being a C library function, DECL_ASSEMBLER_NAME == DECL_NAME
934 unless the system headers are playing rename tricks, and if
935 they are, we don't want to be confused by them. */
936 id = DECL_NAME (fn);
937 const struct libc_name_struct *s
938 = libc_name::libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
939 if (s == NULL)
940 return 0;
941 switch (s->c_ver)
942 {
943 case 89: return 1;
944 case 99: return !flag_iso || flag_isoc99;
945 case 11: return !flag_iso || flag_isoc11;
946 default: gcc_unreachable ();
947 }
948 }
949
950 /* Returns nonzero if an exception of type FROM will be caught by a
951 handler for type TO, as per [except.handle]. */
952
953 static bool
can_convert_eh(tree to,tree from)954 can_convert_eh (tree to, tree from)
955 {
956 to = non_reference (to);
957 from = non_reference (from);
958
959 if (same_type_ignoring_top_level_qualifiers_p (to, from))
960 return true;
961
962 if (TYPE_PTR_P (to) && TYPE_PTR_P (from))
963 {
964 to = TREE_TYPE (to);
965 from = TREE_TYPE (from);
966
967 if (! at_least_as_qualified_p (to, from))
968 return false;
969
970 if (VOID_TYPE_P (to))
971 return true;
972
973 /* Else fall through. */
974 }
975
976 if (CLASS_TYPE_P (to) && CLASS_TYPE_P (from)
977 && publicly_uniquely_derived_p (to, from))
978 return true;
979
980 return false;
981 }
982
983 /* Check whether any of the handlers in I are shadowed by another handler
984 accepting TYPE. Note that the shadowing may not be complete; even if
985 an exception of type B would be caught by a handler for A, there could
986 be a derived class C for which A is an ambiguous base but B is not, so
987 the handler for B would catch an exception of type C. */
988
989 static void
check_handlers_1(tree master,tree_stmt_iterator i)990 check_handlers_1 (tree master, tree_stmt_iterator i)
991 {
992 tree type = TREE_TYPE (master);
993
994 for (; !tsi_end_p (i); tsi_next (&i))
995 {
996 tree handler = tsi_stmt (i);
997 if (TREE_TYPE (handler) && can_convert_eh (type, TREE_TYPE (handler)))
998 {
999 auto_diagnostic_group d;
1000 if (warning_at (EXPR_LOCATION (handler), OPT_Wexceptions,
1001 "exception of type %qT will be caught by earlier "
1002 "handler", TREE_TYPE (handler)))
1003 inform (EXPR_LOCATION (master), "for type %qT", type);
1004 break;
1005 }
1006 }
1007 }
1008
1009 /* Given a STATEMENT_LIST of HANDLERs, make sure that they're OK. */
1010
1011 void
check_handlers(tree handlers)1012 check_handlers (tree handlers)
1013 {
1014 tree_stmt_iterator i;
1015
1016 /* If we don't have a STATEMENT_LIST, then we've just got one
1017 handler, and thus nothing to warn about. */
1018 if (TREE_CODE (handlers) != STATEMENT_LIST)
1019 return;
1020
1021 i = tsi_start (handlers);
1022 if (!tsi_end_p (i))
1023 while (1)
1024 {
1025 tree handler = tsi_stmt (i);
1026 tsi_next (&i);
1027
1028 /* No more handlers; nothing to shadow. */
1029 if (tsi_end_p (i))
1030 break;
1031 if (TREE_TYPE (handler) == NULL_TREE)
1032 permerror (EXPR_LOCATION (handler), "%<...%>"
1033 " handler must be the last handler for its try block");
1034 else
1035 check_handlers_1 (handler, i);
1036 }
1037 }
1038
1039 /* walk_tree helper for finish_noexcept_expr. Returns non-null if the
1040 expression *TP causes the noexcept operator to evaluate to false.
1041
1042 5.3.7 [expr.noexcept]: The result of the noexcept operator is false if
1043 in a potentially-evaluated context the expression would contain
1044 * a potentially evaluated call to a function, member function,
1045 function pointer, or member function pointer that does not have a
1046 non-throwing exception-specification (15.4),
1047 * a potentially evaluated throw-expression (15.1),
1048 * a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
1049 where T is a reference type, that requires a run-time check (5.2.7), or
1050 * a potentially evaluated typeid expression (5.2.8) applied to a glvalue
1051 expression whose type is a polymorphic class type (10.3). */
1052
1053 static tree
check_noexcept_r(tree * tp,int * walk_subtrees,void *)1054 check_noexcept_r (tree *tp, int *walk_subtrees, void *)
1055 {
1056 tree t = *tp;
1057 enum tree_code code = TREE_CODE (t);
1058
1059 if (unevaluated_p (code))
1060 *walk_subtrees = false;
1061 else if ((code == CALL_EXPR && CALL_EXPR_FN (t))
1062 || code == AGGR_INIT_EXPR)
1063 {
1064 /* We can only use the exception specification of the called function
1065 for determining the value of a noexcept expression; we can't use
1066 TREE_NOTHROW, as it might have a different value in another
1067 translation unit, creating ODR problems.
1068
1069 We could use TREE_NOTHROW (t) for !TREE_PUBLIC fns, though... */
1070 tree fn = cp_get_callee (t);
1071 if (concept_check_p (fn))
1072 return NULL_TREE;
1073 tree type = TREE_TYPE (fn);
1074 gcc_assert (INDIRECT_TYPE_P (type));
1075 type = TREE_TYPE (type);
1076
1077 STRIP_NOPS (fn);
1078 if (TREE_CODE (fn) == ADDR_EXPR)
1079 fn = TREE_OPERAND (fn, 0);
1080 if (TREE_CODE (fn) == FUNCTION_DECL)
1081 {
1082 /* We do use TREE_NOTHROW for ABI internals like __dynamic_cast,
1083 and for C library functions known not to throw. */
1084 if (DECL_EXTERN_C_P (fn)
1085 && (DECL_ARTIFICIAL (fn)
1086 || nothrow_libfn_p (fn)))
1087 return TREE_NOTHROW (fn) ? NULL_TREE : fn;
1088 /* We used to treat a call to a constexpr function as noexcept if
1089 the call was a constant expression (CWG 1129). This has changed
1090 in P0003 whereby noexcept has no special rule for constant
1091 expressions anymore. Since the current behavior is important for
1092 certain library functionality, we treat this as a DR, therefore
1093 adjusting the behavior for C++11 and C++14. Previously, we had
1094 to evaluate the noexcept-specifier's operand here, but that could
1095 cause instantiations that would fail. */
1096 }
1097 if (!TYPE_NOTHROW_P (type))
1098 return fn;
1099 }
1100
1101 return NULL_TREE;
1102 }
1103
1104 /* If a function that causes a noexcept-expression to be false isn't
1105 defined yet, remember it and check it for TREE_NOTHROW again at EOF. */
1106
1107 struct GTY(()) pending_noexcept {
1108 tree fn;
1109 location_t loc;
1110 };
1111 static GTY(()) vec<pending_noexcept, va_gc> *pending_noexcept_checks;
1112
1113 /* FN is a FUNCTION_DECL that caused a noexcept-expr to be false. Warn if
1114 it can't throw.
1115
1116 TODO: Consider extending -Wnoexcept to do something like walk_subtrees in the
1117 case of a defaulted function that obtained a noexcept(false) spec. */
1118
1119 static void
maybe_noexcept_warning(tree fn)1120 maybe_noexcept_warning (tree fn)
1121 {
1122 if (TREE_NOTHROW (fn)
1123 && (!DECL_IN_SYSTEM_HEADER (fn)
1124 || global_dc->dc_warn_system_headers))
1125 {
1126 auto s = make_temp_override (global_dc->dc_warn_system_headers, true);
1127 auto_diagnostic_group d;
1128 if (warning (OPT_Wnoexcept, "noexcept-expression evaluates to %<false%> "
1129 "because of a call to %qD", fn))
1130 inform (DECL_SOURCE_LOCATION (fn),
1131 "but %qD does not throw; perhaps "
1132 "it should be declared %<noexcept%>", fn);
1133 }
1134 }
1135
1136 /* Check any functions that weren't defined earlier when they caused a
1137 noexcept expression to evaluate to false. */
1138
1139 void
perform_deferred_noexcept_checks(void)1140 perform_deferred_noexcept_checks (void)
1141 {
1142 int i;
1143 pending_noexcept *p;
1144 location_t saved_loc = input_location;
1145 FOR_EACH_VEC_SAFE_ELT (pending_noexcept_checks, i, p)
1146 {
1147 input_location = p->loc;
1148 maybe_noexcept_warning (p->fn);
1149 }
1150 input_location = saved_loc;
1151 }
1152
1153 /* Evaluate noexcept ( EXPR ). */
1154
1155 tree
finish_noexcept_expr(tree expr,tsubst_flags_t complain)1156 finish_noexcept_expr (tree expr, tsubst_flags_t complain)
1157 {
1158 if (expr == error_mark_node)
1159 return error_mark_node;
1160
1161 if (processing_template_decl)
1162 return build_min (NOEXCEPT_EXPR, boolean_type_node, expr);
1163
1164 return (expr_noexcept_p (expr, complain)
1165 ? boolean_true_node : boolean_false_node);
1166 }
1167
1168 /* Returns whether EXPR is noexcept, possibly warning if allowed by
1169 COMPLAIN. */
1170
1171 bool
expr_noexcept_p(tree expr,tsubst_flags_t complain)1172 expr_noexcept_p (tree expr, tsubst_flags_t complain)
1173 {
1174 tree fn;
1175
1176 if (expr == error_mark_node)
1177 return false;
1178
1179 fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0);
1180 if (fn)
1181 {
1182 if ((complain & tf_warning) && warn_noexcept
1183 && TREE_CODE (fn) == FUNCTION_DECL)
1184 {
1185 if (!DECL_INITIAL (fn))
1186 {
1187 /* Not defined yet; check again at EOF. */
1188 pending_noexcept p = {fn, input_location};
1189 vec_safe_push (pending_noexcept_checks, p);
1190 }
1191 else
1192 maybe_noexcept_warning (fn);
1193 }
1194 return false;
1195 }
1196 else
1197 return true;
1198 }
1199
1200 /* Return true iff SPEC is throw() or noexcept(true). */
1201
1202 bool
nothrow_spec_p(const_tree spec)1203 nothrow_spec_p (const_tree spec)
1204 {
1205 gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec));
1206
1207 if (spec == empty_except_spec
1208 || spec == noexcept_true_spec)
1209 return true;
1210
1211 gcc_assert (!spec
1212 || TREE_VALUE (spec)
1213 || spec == noexcept_false_spec
1214 || TREE_PURPOSE (spec) == error_mark_node
1215 || UNPARSED_NOEXCEPT_SPEC_P (spec)
1216 || processing_template_decl);
1217
1218 return false;
1219 }
1220
1221 /* For FUNCTION_TYPE or METHOD_TYPE, true if NODE is noexcept. This is the
1222 case for things declared noexcept(true) and, with -fnothrow-opt, for
1223 throw() functions. */
1224
1225 bool
type_noexcept_p(const_tree type)1226 type_noexcept_p (const_tree type)
1227 {
1228 tree spec = TYPE_RAISES_EXCEPTIONS (type);
1229 gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec));
1230 if (flag_nothrow_opt)
1231 return nothrow_spec_p (spec);
1232 else
1233 return spec == noexcept_true_spec;
1234 }
1235
1236 /* For FUNCTION_TYPE or METHOD_TYPE, true if NODE can throw any type,
1237 i.e. no exception-specification or noexcept(false). */
1238
1239 bool
type_throw_all_p(const_tree type)1240 type_throw_all_p (const_tree type)
1241 {
1242 tree spec = TYPE_RAISES_EXCEPTIONS (type);
1243 gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec));
1244 return spec == NULL_TREE || spec == noexcept_false_spec;
1245 }
1246
1247 /* Create a representation of the noexcept-specification with
1248 constant-expression of EXPR. COMPLAIN is as for tsubst. */
1249
1250 tree
build_noexcept_spec(tree expr,tsubst_flags_t complain)1251 build_noexcept_spec (tree expr, tsubst_flags_t complain)
1252 {
1253 if (check_for_bare_parameter_packs (expr))
1254 return error_mark_node;
1255 if (TREE_CODE (expr) != DEFERRED_NOEXCEPT
1256 && !instantiation_dependent_expression_p (expr))
1257 {
1258 expr = build_converted_constant_bool_expr (expr, complain);
1259 expr = instantiate_non_dependent_expr_sfinae (expr, complain);
1260 expr = cxx_constant_value (expr);
1261 }
1262 if (TREE_CODE (expr) == INTEGER_CST)
1263 {
1264 if (operand_equal_p (expr, boolean_true_node, 0))
1265 return noexcept_true_spec;
1266 else
1267 {
1268 gcc_checking_assert (operand_equal_p (expr, boolean_false_node, 0));
1269 return noexcept_false_spec;
1270 }
1271 }
1272 else if (expr == error_mark_node)
1273 return error_mark_node;
1274 else
1275 {
1276 gcc_assert (processing_template_decl
1277 || TREE_CODE (expr) == DEFERRED_NOEXCEPT);
1278 if (TREE_CODE (expr) != DEFERRED_NOEXCEPT)
1279 /* Avoid problems with a function type built with a dependent typedef
1280 being reused in another scope (c++/84045). */
1281 expr = strip_typedefs_expr (expr);
1282 return build_tree_list (expr, NULL_TREE);
1283 }
1284 }
1285
1286 /* If the current function has a cleanup that might throw, and the return value
1287 has a non-trivial destructor, return a MODIFY_EXPR to set
1288 current_retval_sentinel so that we know that the return value needs to be
1289 destroyed on throw. Otherwise, returns NULL_TREE. */
1290
1291 tree
maybe_set_retval_sentinel()1292 maybe_set_retval_sentinel ()
1293 {
1294 if (processing_template_decl)
1295 return NULL_TREE;
1296 tree retval = DECL_RESULT (current_function_decl);
1297 if (!TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (retval)))
1298 return NULL_TREE;
1299 if (!cp_function_chain->throwing_cleanup)
1300 return NULL_TREE;
1301
1302 if (!current_retval_sentinel)
1303 {
1304 /* Just create the temporary now, maybe_splice_retval_cleanup
1305 will do the rest. */
1306 current_retval_sentinel = create_temporary_var (boolean_type_node);
1307 DECL_INITIAL (current_retval_sentinel) = boolean_false_node;
1308 pushdecl_outermost_localscope (current_retval_sentinel);
1309 }
1310
1311 return build2 (MODIFY_EXPR, boolean_type_node,
1312 current_retval_sentinel, boolean_true_node);
1313 }
1314
1315 /* COMPOUND_STMT is the STATEMENT_LIST for some block. If COMPOUND_STMT is the
1316 current function body or a try block, and current_retval_sentinel was set in
1317 this function, wrap the block in a CLEANUP_STMT to destroy the return value
1318 on throw. */
1319
1320 void
maybe_splice_retval_cleanup(tree compound_stmt,bool is_try)1321 maybe_splice_retval_cleanup (tree compound_stmt, bool is_try)
1322 {
1323 if (!current_function_decl || !cfun
1324 || DECL_CONSTRUCTOR_P (current_function_decl)
1325 || DECL_DESTRUCTOR_P (current_function_decl)
1326 || !current_retval_sentinel)
1327 return;
1328
1329 /* if we need a cleanup for the return value, add it in at the same level as
1330 pushdecl_outermost_localscope. And also in try blocks. */
1331 cp_binding_level *b = current_binding_level;
1332 const bool function_body = b->kind == sk_function_parms;
1333
1334 if (function_body || is_try)
1335 {
1336 location_t loc = DECL_SOURCE_LOCATION (current_function_decl);
1337 tree_stmt_iterator iter = tsi_start (compound_stmt);
1338 tree retval = DECL_RESULT (current_function_decl);
1339
1340 if (function_body)
1341 {
1342 /* Add a DECL_EXPR for current_retval_sentinel. */
1343 tree decl_expr = build_stmt (loc, DECL_EXPR, current_retval_sentinel);
1344 tsi_link_before (&iter, decl_expr, TSI_SAME_STMT);
1345 }
1346
1347 /* Skip past other decls, they can't contain a return. */
1348 while (!tsi_end_p (iter)
1349 && TREE_CODE (tsi_stmt (iter)) == DECL_EXPR)
1350 tsi_next (&iter);
1351
1352 if (tsi_end_p (iter))
1353 /* Nothing to wrap. */
1354 return;
1355
1356 /* Wrap the rest of the STATEMENT_LIST in a CLEANUP_STMT. */
1357 tree stmts = NULL_TREE;
1358 while (!tsi_end_p (iter))
1359 {
1360 append_to_statement_list_force (tsi_stmt (iter), &stmts);
1361 tsi_delink (&iter);
1362 }
1363 tree dtor = build_cleanup (retval);
1364 if (!function_body)
1365 {
1366 /* Clear the sentinel so we don't try to destroy the retval again on
1367 rethrow (c++/112301). */
1368 tree clear = build2 (MODIFY_EXPR, boolean_type_node,
1369 current_retval_sentinel, boolean_false_node);
1370 dtor = build2 (COMPOUND_EXPR, void_type_node, clear, dtor);
1371 }
1372 tree cond = build3 (COND_EXPR, void_type_node, current_retval_sentinel,
1373 dtor, void_node);
1374 tree cleanup = build_stmt (loc, CLEANUP_STMT,
1375 stmts, cond, retval);
1376 CLEANUP_EH_ONLY (cleanup) = true;
1377 append_to_statement_list_force (cleanup, &compound_stmt);
1378 }
1379 }
1380
1381 #include "gt-cp-except.h"
1382