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