]>
Commit | Line | Data |
---|---|---|
8d08fdba | 1 | /* Handle exceptional things in C++. |
7adcbafe | 2 | Copyright (C) 1989-2022 Free Software Foundation, Inc. |
8d2733ca MS |
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. | |
8d08fdba | 6 | |
f5adbb8d | 7 | This file is part of GCC. |
8d08fdba | 8 | |
f5adbb8d | 9 | GCC is free software; you can redistribute it and/or modify |
8d08fdba | 10 | it under the terms of the GNU General Public License as published by |
e77f031d | 11 | the Free Software Foundation; either version 3, or (at your option) |
8d08fdba MS |
12 | any later version. |
13 | ||
f5adbb8d | 14 | GCC is distributed in the hope that it will be useful, |
8d08fdba MS |
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 | |
e77f031d NC |
20 | along with GCC; see the file COPYING3. If not see |
21 | <http://www.gnu.org/licenses/>. */ | |
8d08fdba MS |
22 | |
23 | ||
8d08fdba | 24 | #include "config.h" |
8d052bc7 | 25 | #include "system.h" |
4977bab6 | 26 | #include "coretypes.h" |
2adfab87 | 27 | #include "cp-tree.h" |
d8a2d370 DN |
28 | #include "stringpool.h" |
29 | #include "trans-mem.h" | |
30 | #include "attribs.h" | |
325c3691 | 31 | #include "tree-iterator.h" |
02a32ab4 | 32 | #include "target.h" |
8d08fdba | 33 | |
5cc3d3b8 GDR |
34 | static void push_eh_cleanup (tree); |
35 | static tree prepare_eh_type (tree); | |
5cc3d3b8 GDR |
36 | static tree do_begin_catch (void); |
37 | static int dtor_nothrow (tree); | |
38 | static tree do_end_catch (tree); | |
5cc3d3b8 GDR |
39 | static void initialize_handler_parm (tree, tree); |
40 | static tree do_allocate_exception (tree); | |
5cc3d3b8 GDR |
41 | static tree wrap_cleanups_r (tree *, int *, void *); |
42 | static int complete_ptr_ref_or_void_ptr_p (tree, tree); | |
f9eead1f | 43 | static bool is_admissible_throw_operand_or_catch_parameter (tree, bool); |
8d2733ca | 44 | |
52a11cbf | 45 | /* Sets up all the global eh stuff that needs to be initialized at the |
bbd0d54a | 46 | start of compilation. */ |
8d08fdba | 47 | |
8d08fdba | 48 | void |
5cc3d3b8 | 49 | init_exception_processing (void) |
8d08fdba | 50 | { |
52a11cbf RH |
51 | tree tmp; |
52 | ||
52a11cbf | 53 | /* void std::terminate (); */ |
5a7c4505 | 54 | push_nested_namespace (std_node); |
0244e6f7 | 55 | tmp = build_function_type_list (void_type_node, NULL_TREE); |
1a66d857 | 56 | terminate_fn = build_cp_library_fn_ptr ("terminate", tmp, |
cb59f689 JH |
57 | ECF_NOTHROW | ECF_NORETURN |
58 | | ECF_COLD); | |
59 | gcc_checking_assert (TREE_THIS_VOLATILE (terminate_fn) | |
60 | && TREE_NOTHROW (terminate_fn)); | |
5a7c4505 | 61 | pop_nested_namespace (std_node); |
8ccc31eb | 62 | |
52a11cbf | 63 | /* void __cxa_call_unexpected(void *); */ |
0244e6f7 | 64 | tmp = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); |
1a66d857 | 65 | call_unexpected_fn |
52a11cbf | 66 | = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp); |
6874c264 JM |
67 | } |
68 | ||
e6855a2d | 69 | /* Returns an expression to be executed if an unhandled exception is |
aba649ba | 70 | propagated out of a cleanup region. */ |
e6855a2d | 71 | |
3b06d379 | 72 | tree |
5cc3d3b8 | 73 | cp_protect_cleanup_actions (void) |
e6855a2d MM |
74 | { |
75 | /* [except.terminate] | |
76 | ||
77 | When the destruction of an object during stack unwinding exits | |
78 | using an exception ... void terminate(); is called. */ | |
1a66d857 | 79 | return terminate_fn; |
c8094d83 | 80 | } |
e6855a2d | 81 | |
6874c264 | 82 | static tree |
5cc3d3b8 | 83 | prepare_eh_type (tree type) |
8d08fdba | 84 | { |
52a11cbf RH |
85 | if (type == NULL_TREE) |
86 | return type; | |
f30432d7 MS |
87 | if (type == error_mark_node) |
88 | return error_mark_node; | |
8d2733ca | 89 | |
e92cc029 | 90 | /* peel back references, so they match. */ |
ee76b931 | 91 | type = non_reference (type); |
8d08fdba | 92 | |
e92cc029 | 93 | /* Peel off cv qualifiers. */ |
f30432d7 | 94 | type = TYPE_MAIN_VARIANT (type); |
8d2733ca | 95 | |
86ef5ebb JM |
96 | /* Functions and arrays decay to pointers. */ |
97 | type = type_decays_to (type); | |
98 | ||
52a11cbf | 99 | return type; |
8d08fdba | 100 | } |
8d08fdba | 101 | |
6cad4e17 JH |
102 | /* Return the type info for TYPE as used by EH machinery. */ |
103 | tree | |
104 | eh_type_info (tree type) | |
5816cb14 | 105 | { |
93ca4ba7 JM |
106 | if (type == NULL_TREE || type == error_mark_node) |
107 | return type; | |
5816cb14 | 108 | |
bfecd57c | 109 | return get_tinfo_decl (type); |
5816cb14 AM |
110 | } |
111 | ||
6cad4e17 JH |
112 | /* Build the address of a typeinfo decl for use in the runtime |
113 | matching field of the exception model. */ | |
114 | ||
f9417da1 | 115 | tree |
6cad4e17 JH |
116 | build_eh_type_type (tree type) |
117 | { | |
118 | tree exp = eh_type_info (type); | |
119 | ||
120 | if (!exp) | |
121 | return NULL; | |
122 | ||
f820b0cf JH |
123 | mark_used (exp); |
124 | ||
6de9cd9a | 125 | return convert (ptr_type_node, build_address (exp)); |
6cad4e17 JH |
126 | } |
127 | ||
52a11cbf | 128 | tree |
5cc3d3b8 | 129 | build_exc_ptr (void) |
52a11cbf | 130 | { |
e79983f4 | 131 | return build_call_n (builtin_decl_explicit (BUILT_IN_EH_POINTER), |
1d65f45c | 132 | 1, integer_zero_node); |
52a11cbf RH |
133 | } |
134 | ||
e88218fd NS |
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. */ | |
784417d1 | 140 | |
e88218fd NS |
141 | static tree |
142 | declare_library_fn_1 (const char *name, int ecf, | |
143 | tree rtype, int nargs, tree args[]) | |
784417d1 | 144 | { |
e88218fd NS |
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; | |
784417d1 JJ |
156 | } |
157 | ||
1a66d857 NS |
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. | |
448083e5 PC |
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 | |
1a66d857 NS |
169 | declare_library_fn (const char *name, tree rtype, tree ptype, |
170 | int ecf, int tm_ecf) | |
448083e5 | 171 | { |
e88218fd NS |
172 | tree res = declare_library_fn_1 (name, ecf, rtype, ptype ? 1 : 0, &ptype); |
173 | if (res == error_mark_node) | |
174 | return res; | |
784417d1 JJ |
175 | |
176 | if (tm_ecf && flag_tm) | |
177 | { | |
178 | char *tm_name = concat ("_ITM_", name + 2, NULL_TREE); | |
e88218fd NS |
179 | |
180 | tree tm_fn = declare_library_fn_1 (tm_name, ecf | tm_ecf, rtype, | |
181 | ptype ? 1 : 0, &ptype); | |
784417d1 JJ |
182 | free (tm_name); |
183 | if (tm_fn != error_mark_node) | |
184 | record_tm_replacement (res, tm_fn); | |
1a66d857 | 185 | } |
e88218fd | 186 | |
1a66d857 | 187 | return res; |
448083e5 PC |
188 | } |
189 | ||
39609077 RH |
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 | |
194 | do_get_exception_ptr (void) | |
195 | { | |
1a66d857 NS |
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, | |
450f4293 | 206 | build_exc_ptr (), NULL_TREE); |
39609077 RH |
207 | } |
208 | ||
52a11cbf RH |
209 | /* Build up a call to __cxa_begin_catch, to tell the runtime that the |
210 | exception has been handled. */ | |
93ca4ba7 | 211 | |
52a11cbf | 212 | static tree |
5cc3d3b8 | 213 | do_begin_catch (void) |
9c606f69 | 214 | { |
1a66d857 NS |
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, | |
450f4293 | 223 | build_exc_ptr (), NULL_TREE); |
9c606f69 AM |
224 | } |
225 | ||
93ca4ba7 JM |
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 | |
5cc3d3b8 | 230 | dtor_nothrow (tree type) |
93ca4ba7 | 231 | { |
9bb1a81b | 232 | if (type == NULL_TREE || type == error_mark_node) |
93ca4ba7 JM |
233 | return 0; |
234 | ||
9bb1a81b | 235 | if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type)) |
93ca4ba7 JM |
236 | return 1; |
237 | ||
9f4faeae MM |
238 | if (CLASSTYPE_LAZY_DESTRUCTOR (type)) |
239 | lazily_declare_fn (sfk_destructor, type); | |
240 | ||
b2cf76f3 | 241 | return TREE_NOTHROW (CLASSTYPE_DESTRUCTOR (type)); |
93ca4ba7 JM |
242 | } |
243 | ||
52a11cbf | 244 | /* Build up a call to __cxa_end_catch, to destroy the exception object |
93ca4ba7 | 245 | for the current catch block if no others are currently using it. */ |
6467930b | 246 | |
c7ae64f2 | 247 | static tree |
5cc3d3b8 | 248 | do_end_catch (tree type) |
72b7eeff | 249 | { |
1a66d857 NS |
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); | |
784417d1 JJ |
259 | if (cleanup != error_mark_node) |
260 | TREE_NOTHROW (cleanup) = dtor_nothrow (type); | |
52a11cbf | 261 | |
c0700ea5 | 262 | return cleanup; |
c7ae64f2 JM |
263 | } |
264 | ||
265 | /* This routine creates the cleanup for the current exception. */ | |
72b7eeff | 266 | |
c7ae64f2 | 267 | static void |
5cc3d3b8 | 268 | push_eh_cleanup (tree type) |
c7ae64f2 | 269 | { |
52a11cbf | 270 | finish_decl_cleanup (NULL_TREE, do_end_catch (type)); |
f4a23343 JM |
271 | } |
272 | ||
f2162c3d TR |
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 | |
278 | build_must_not_throw_expr (tree body, tree cond) | |
279 | { | |
280 | tree type = body ? TREE_TYPE (body) : void_type_node; | |
281 | ||
6df2ca09 TV |
282 | if (!flag_exceptions) |
283 | return body; | |
284 | ||
a0ab7ccd JM |
285 | if (!cond) |
286 | /* OK, unconditional. */; | |
287 | else | |
f2162c3d | 288 | { |
a0ab7ccd JM |
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); | |
f2162c3d TR |
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 | ||
b35d4555 | 308 | /* Initialize the catch parameter DECL. */ |
6467930b | 309 | |
c8094d83 | 310 | static void |
5cc3d3b8 | 311 | initialize_handler_parm (tree decl, tree exp) |
8d08fdba | 312 | { |
b35d4555 MM |
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; | |
03a904b5 | 319 | DECL_READ_P (decl) = 1; |
b35d4555 | 320 | |
52a11cbf | 321 | /* Figure out the type that the initializer is. Pointers are returned |
c8094d83 | 322 | adjusted by value from __cxa_begin_catch. Others are returned by |
52a11cbf | 323 | reference. */ |
b35d4555 | 324 | init_type = TREE_TYPE (decl); |
71a93b08 | 325 | if (!INDIRECT_TYPE_P (init_type)) |
b35d4555 MM |
326 | init_type = build_reference_type (init_type); |
327 | ||
b35d4555 | 328 | /* Since pointers are passed by value, initialize a reference to |
52a11cbf | 329 | pointer catch parm with the address of the temporary. */ |
9f613f06 | 330 | if (TYPE_REF_P (init_type) |
c93586fa | 331 | && TYPE_PTR_P (TREE_TYPE (init_type))) |
93c0e0bb | 332 | exp = cp_build_addr_expr (exp, tf_warning_or_error); |
b35d4555 | 333 | |
4b978f96 PC |
334 | exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0, |
335 | tf_warning_or_error); | |
b35d4555 MM |
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))) | |
faf5394a | 342 | { |
b35d4555 MM |
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, | |
4b978f96 PC |
346 | CONV_IMPLICIT|CONV_FORCE_TEMP, 0, |
347 | tf_warning_or_error); | |
ba6c89a9 JM |
348 | /* Force cleanups now to avoid nesting problems with the |
349 | MUST_NOT_THROW_EXPR. */ | |
c1bb7f86 | 350 | init = fold_build_cleanup_point_expr (TREE_TYPE (init), init); |
f2162c3d | 351 | init = build_must_not_throw_expr (init, NULL_TREE); |
faf5394a MS |
352 | } |
353 | ||
b35d4555 | 354 | decl = pushdecl (decl); |
8d2733ca | 355 | |
e92fb501 | 356 | start_decl_1 (decl, true); |
d174af6c | 357 | cp_finish_decl (decl, init, /*init_const_expr_p=*/false, NULL_TREE, |
b35d4555 | 358 | LOOKUP_ONLYCONVERTING|DIRECT_BIND); |
5816cb14 AM |
359 | } |
360 | ||
3b06d379 SB |
361 | \f |
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 | |
370 | doing_eh (void) | |
371 | { | |
372 | if (! flag_exceptions) | |
373 | { | |
374 | static int warned = 0; | |
375 | if (! warned) | |
376 | { | |
a3f9f006 | 377 | error ("exception handling disabled, use %<-fexceptions%> to enable"); |
3b06d379 SB |
378 | warned = 1; |
379 | } | |
380 | return 0; | |
381 | } | |
382 | return 1; | |
383 | } | |
384 | ||
b35d4555 | 385 | /* Call this to start a catch block. DECL is the catch parameter. */ |
5816cb14 | 386 | |
b35d4555 | 387 | tree |
5cc3d3b8 | 388 | expand_start_catch_block (tree decl) |
5816cb14 | 389 | { |
39609077 | 390 | tree exp; |
4227d4a1 | 391 | tree type, init; |
5816cb14 | 392 | |
3b06d379 | 393 | if (! doing_eh ()) |
b35d4555 | 394 | return NULL_TREE; |
5816cb14 | 395 | |
52a11cbf | 396 | if (decl) |
f9eead1f PC |
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)); | |
785b887e | 402 | mark_used (eh_type_info (type)); |
f9eead1f | 403 | } |
52a11cbf RH |
404 | else |
405 | type = NULL_TREE; | |
52a11cbf | 406 | |
39609077 RH |
407 | /* Call __cxa_end_catch at the end of processing the exception. */ |
408 | push_eh_cleanup (type); | |
409 | ||
4227d4a1 PC |
410 | init = do_begin_catch (); |
411 | ||
39609077 RH |
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. */ | |
4227d4a1 PC |
414 | if (decl == NULL || decl == error_mark_node || init == error_mark_node) |
415 | finish_expr_stmt (init); | |
39609077 RH |
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. */ | |
3db45ab5 | 420 | else if (flag_use_cxa_get_exception_ptr |
c7b5e395 | 421 | && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) |
39609077 RH |
422 | { |
423 | exp = do_get_exception_ptr (); | |
784417d1 JJ |
424 | if (exp != error_mark_node) |
425 | initialize_handler_parm (decl, exp); | |
4227d4a1 | 426 | finish_expr_stmt (init); |
39609077 RH |
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 | { | |
2de9107a R |
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); | |
3db45ab5 | 442 | cp_finish_decl (exp, init, /*init_const_expr=*/false, |
d174af6c | 443 | NULL_TREE, LOOKUP_ONLYCONVERTING); |
a2c6e7f2 | 444 | DECL_REGISTER (exp) = 1; |
39609077 | 445 | initialize_handler_parm (decl, exp); |
e97f22c9 | 446 | } |
5816cb14 | 447 | |
1a6025b4 | 448 | return type; |
5816cb14 AM |
449 | } |
450 | ||
f30432d7 | 451 | |
8d2733ca MS |
452 | /* Call this to end a catch block. Its responsible for emitting the |
453 | code to handle jumping back to the correct place, and for emitting | |
454 | the label to jump to if this catch block didn't match. */ | |
6467930b | 455 | |
824b9a4c | 456 | void |
5cc3d3b8 | 457 | expand_end_catch_block (void) |
8d08fdba | 458 | { |
3b06d379 | 459 | if (! doing_eh ()) |
f30432d7 | 460 | return; |
8d2733ca | 461 | |
0dde4175 JM |
462 | /* The exception being handled is rethrown if control reaches the end of |
463 | a handler of the function-try-block of a constructor or destructor. */ | |
464 | if (in_function_try_handler | |
465 | && (DECL_CONSTRUCTOR_P (current_function_decl) | |
466 | || DECL_DESTRUCTOR_P (current_function_decl))) | |
8243e2a9 | 467 | { |
d3769410 | 468 | tree rethrow = build_throw (input_location, NULL_TREE); |
65870e75 MS |
469 | /* Disable all warnings for the generated rethrow statement. */ |
470 | suppress_warning (rethrow); | |
8243e2a9 JM |
471 | finish_expr_stmt (rethrow); |
472 | } | |
8d2733ca | 473 | } |
8d08fdba | 474 | |
b35d4555 | 475 | tree |
5cc3d3b8 | 476 | begin_eh_spec_block (void) |
f30432d7 | 477 | { |
9feb3d6a | 478 | tree r; |
e70e0b60 SP |
479 | location_t spec_location = DECL_SOURCE_LOCATION (current_function_decl); |
480 | ||
9feb3d6a JM |
481 | /* A noexcept specification (or throw() with -fnothrow-opt) is a |
482 | MUST_NOT_THROW_EXPR. */ | |
483 | if (TYPE_NOEXCEPT_P (TREE_TYPE (current_function_decl))) | |
484 | { | |
f2162c3d TR |
485 | r = build_stmt (spec_location, MUST_NOT_THROW_EXPR, |
486 | NULL_TREE, NULL_TREE); | |
9feb3d6a JM |
487 | TREE_SIDE_EFFECTS (r) = 1; |
488 | } | |
489 | else | |
e70e0b60 | 490 | r = build_stmt (spec_location, EH_SPEC_BLOCK, NULL_TREE, NULL_TREE); |
52a11cbf | 491 | add_stmt (r); |
9feb3d6a | 492 | TREE_OPERAND (r, 0) = push_stmt_list (); |
52a11cbf | 493 | return r; |
f30432d7 MS |
494 | } |
495 | ||
b35d4555 | 496 | void |
5cc3d3b8 | 497 | finish_eh_spec_block (tree raw_raises, tree eh_spec_block) |
f30432d7 | 498 | { |
52a11cbf | 499 | tree raises; |
0c11ada6 | 500 | |
9feb3d6a JM |
501 | TREE_OPERAND (eh_spec_block, 0) |
502 | = pop_stmt_list (TREE_OPERAND (eh_spec_block, 0)); | |
503 | ||
504 | if (TREE_CODE (eh_spec_block) == MUST_NOT_THROW_EXPR) | |
505 | return; | |
6c20b7e9 | 506 | |
52a11cbf RH |
507 | /* Strip cv quals, etc, from the specification types. */ |
508 | for (raises = NULL_TREE; | |
509 | raw_raises && TREE_VALUE (raw_raises); | |
510 | raw_raises = TREE_CHAIN (raw_raises)) | |
6cad4e17 JH |
511 | { |
512 | tree type = prepare_eh_type (TREE_VALUE (raw_raises)); | |
513 | tree tinfo = eh_type_info (type); | |
514 | ||
515 | mark_used (tinfo); | |
516 | raises = tree_cons (NULL_TREE, type, raises); | |
517 | } | |
6c20b7e9 | 518 | |
52a11cbf | 519 | EH_SPEC_RAISES (eh_spec_block) = raises; |
f30432d7 MS |
520 | } |
521 | ||
52a11cbf | 522 | /* Return a pointer to a buffer for an exception object of type TYPE. */ |
6467930b | 523 | |
52a11cbf | 524 | static tree |
5cc3d3b8 | 525 | do_allocate_exception (tree type) |
8d08fdba | 526 | { |
1a66d857 NS |
527 | if (!allocate_exception_fn) |
528 | /* Declare void *__cxa_allocate_exception(size_t) throw(). */ | |
529 | allocate_exception_fn | |
530 | = declare_library_fn ("__cxa_allocate_exception", | |
531 | ptr_type_node, size_type_node, | |
c3cc0122 | 532 | ECF_NOTHROW | ECF_MALLOC | ECF_COLD, ECF_TM_PURE); |
1a66d857 NS |
533 | |
534 | return cp_build_function_call_nary (allocate_exception_fn, | |
535 | tf_warning_or_error, | |
450f4293 | 536 | size_in_bytes (type), NULL_TREE); |
8d08fdba MS |
537 | } |
538 | ||
2ac8a0f9 | 539 | /* Call __cxa_free_exception from a cleanup. This is never invoked |
6f30f1f1 | 540 | directly, but see the comment for stabilize_throw_expr. */ |
f4a23343 | 541 | |
c6160f8f | 542 | static tree |
5cc3d3b8 | 543 | do_free_exception (tree ptr) |
f4a23343 | 544 | { |
1a66d857 NS |
545 | if (!free_exception_fn) |
546 | /* Declare void __cxa_free_exception (void *) throw(). */ | |
547 | free_exception_fn | |
548 | = declare_library_fn ("__cxa_free_exception", | |
549 | void_type_node, ptr_type_node, | |
550 | ECF_NOTHROW | ECF_LEAF, ECF_TM_PURE); | |
551 | ||
552 | return cp_build_function_call_nary (free_exception_fn, | |
553 | tf_warning_or_error, ptr, NULL_TREE); | |
f4a23343 JM |
554 | } |
555 | ||
6f30f1f1 JM |
556 | /* Wrap all cleanups for TARGET_EXPRs in MUST_NOT_THROW_EXPR. |
557 | Called from build_throw via walk_tree_without_duplicates. */ | |
558 | ||
559 | static tree | |
12308bc6 | 560 | wrap_cleanups_r (tree *tp, int *walk_subtrees, void * /*data*/) |
6f30f1f1 JM |
561 | { |
562 | tree exp = *tp; | |
563 | tree cleanup; | |
564 | ||
565 | /* Don't walk into types. */ | |
566 | if (TYPE_P (exp)) | |
567 | { | |
568 | *walk_subtrees = 0; | |
569 | return NULL_TREE; | |
570 | } | |
571 | if (TREE_CODE (exp) != TARGET_EXPR) | |
572 | return NULL_TREE; | |
573 | ||
574 | cleanup = TARGET_EXPR_CLEANUP (exp); | |
575 | if (cleanup) | |
576 | { | |
f2162c3d TR |
577 | cleanup = build2 (MUST_NOT_THROW_EXPR, void_type_node, cleanup, |
578 | NULL_TREE); | |
6f30f1f1 JM |
579 | TARGET_EXPR_CLEANUP (exp) = cleanup; |
580 | } | |
581 | ||
582 | /* Keep iterating. */ | |
583 | return NULL_TREE; | |
584 | } | |
585 | ||
52a11cbf | 586 | /* Build a throw expression. */ |
6467930b | 587 | |
52a11cbf | 588 | tree |
d3769410 | 589 | build_throw (location_t loc, tree exp) |
8d08fdba | 590 | { |
52a11cbf RH |
591 | if (exp == error_mark_node) |
592 | return exp; | |
593 | ||
594 | if (processing_template_decl) | |
aff5c451 | 595 | { |
07515729 JJ |
596 | if (cfun) |
597 | current_function_returns_abnormally = 1; | |
73808ca6 | 598 | exp = build_min (THROW_EXPR, void_type_node, exp); |
d3769410 | 599 | SET_EXPR_LOCATION (exp, loc); |
73808ca6 | 600 | return exp; |
aff5c451 | 601 | } |
52a11cbf | 602 | |
9a004410 | 603 | if (exp && null_node_p (exp)) |
d3769410 PC |
604 | warning_at (loc, 0, |
605 | "throwing NULL, which has integral, not pointer type"); | |
c8094d83 | 606 | |
52a11cbf RH |
607 | if (exp != NULL_TREE) |
608 | { | |
f9eead1f | 609 | if (!is_admissible_throw_operand_or_catch_parameter (exp, true)) |
0cbd7506 | 610 | return error_mark_node; |
52a11cbf RH |
611 | } |
612 | ||
3b06d379 | 613 | if (! doing_eh ()) |
59ccf49d | 614 | return error_mark_node; |
8d08fdba | 615 | |
bfecd57c | 616 | if (exp) |
8d2733ca | 617 | { |
faae18ab | 618 | tree throw_type; |
41990f96 | 619 | tree temp_type; |
52a11cbf | 620 | tree cleanup; |
52a11cbf | 621 | tree object, ptr; |
b33a0480 | 622 | tree allocate_expr; |
52a11cbf | 623 | |
fbac6f3c MM |
624 | /* The CLEANUP_TYPE is the internal type of a destructor. */ |
625 | if (!cleanup_type) | |
626 | { | |
e88218fd NS |
627 | tree tmp = build_function_type_list (void_type_node, |
628 | ptr_type_node, NULL_TREE); | |
fbac6f3c MM |
629 | cleanup_type = build_pointer_type (tmp); |
630 | } | |
c8094d83 | 631 | |
4b4b2e58 | 632 | if (!throw_fn) |
52a11cbf | 633 | { |
e88218fd | 634 | tree args[3] = {ptr_type_node, ptr_type_node, cleanup_type}; |
4b4b2e58 | 635 | |
e88218fd NS |
636 | throw_fn = declare_library_fn_1 ("__cxa_throw", |
637 | ECF_NORETURN | ECF_COLD, | |
638 | void_type_node, 3, args); | |
784417d1 JJ |
639 | if (flag_tm && throw_fn != error_mark_node) |
640 | { | |
e88218fd NS |
641 | tree itm_fn = declare_library_fn_1 ("_ITM_cxa_throw", |
642 | ECF_NORETURN | ECF_COLD, | |
643 | void_type_node, 3, args); | |
784417d1 | 644 | if (itm_fn != error_mark_node) |
4b4b2e58 | 645 | { |
4b4b2e58 NS |
646 | apply_tm_attr (itm_fn, get_identifier ("transaction_pure")); |
647 | record_tm_replacement (throw_fn, itm_fn); | |
648 | } | |
0a35513e | 649 | } |
52a11cbf | 650 | } |
c8094d83 | 651 | |
3db45ab5 MS |
652 | /* [except.throw] |
653 | ||
654 | A throw-expression initializes a temporary object, the type | |
41990f96 MM |
655 | of which is determined by removing any top-level |
656 | cv-qualifiers from the static type of the operand of throw | |
657 | and adjusting the type from "array of T" or "function return | |
658 | T" to "pointer to T" or "pointer to function returning T" | |
659 | respectively. */ | |
660 | temp_type = is_bitfield_expr_with_lowered_type (exp); | |
661 | if (!temp_type) | |
ccaff498 | 662 | temp_type = cv_unqualified (type_decays_to (TREE_TYPE (exp))); |
a3b49ccd | 663 | |
52a11cbf RH |
664 | /* OK, this is kind of wacky. The standard says that we call |
665 | terminate when the exception handling mechanism, after | |
666 | completing evaluation of the expression to be thrown but | |
667 | before the exception is caught (_except.throw_), calls a | |
668 | user function that exits via an uncaught exception. | |
669 | ||
670 | So we have to protect the actual initialization of the | |
671 | exception object with terminate(), but evaluate the | |
672 | expression first. Since there could be temps in the | |
673 | expression, we need to handle that, too. We also expand | |
674 | the call to __cxa_allocate_exception first (which doesn't | |
675 | matter, since it can't throw). */ | |
676 | ||
52a11cbf | 677 | /* Allocate the space for the exception. */ |
41990f96 | 678 | allocate_expr = do_allocate_exception (temp_type); |
784417d1 JJ |
679 | if (allocate_expr == error_mark_node) |
680 | return error_mark_node; | |
6f30f1f1 JM |
681 | allocate_expr = get_target_expr (allocate_expr); |
682 | ptr = TARGET_EXPR_SLOT (allocate_expr); | |
b33a0480 JM |
683 | TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr); |
684 | CLEANUP_EH_ONLY (allocate_expr) = 1; | |
685 | ||
41990f96 | 686 | object = build_nop (build_pointer_type (temp_type), ptr); |
04757a2a | 687 | object = cp_build_fold_indirect_ref (object); |
faae18ab | 688 | |
6f30f1f1 | 689 | /* And initialize the exception object. */ |
36cbfdb0 | 690 | if (CLASS_TYPE_P (temp_type)) |
6f30f1f1 | 691 | { |
8af2fec4 | 692 | int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING; |
4ce8c5de | 693 | bool converted = false; |
d3769410 | 694 | location_t exp_loc = cp_expr_loc_or_loc (exp, loc); |
8af2fec4 RY |
695 | |
696 | /* Under C++0x [12.8/16 class.copy], a thrown lvalue is sometimes | |
697 | treated as an rvalue for the purposes of overload resolution | |
698 | to favor move constructors over copy constructors. */ | |
1722e201 | 699 | if (tree moved = treat_lvalue_as_rvalue_p (exp, /*return*/false)) |
4ce8c5de | 700 | { |
1722e201 | 701 | if (cxx_dialect < cxx20) |
4ce8c5de | 702 | { |
1722e201 JM |
703 | releasing_vec exp_vec (make_tree_vector_single (moved)); |
704 | moved = (build_special_member_call | |
705 | (object, complete_ctor_identifier, &exp_vec, | |
706 | TREE_TYPE (object), flags|LOOKUP_PREFER_RVALUE, | |
707 | tf_none)); | |
708 | if (moved != error_mark_node) | |
709 | { | |
710 | exp = moved; | |
711 | converted = true; | |
712 | } | |
4ce8c5de | 713 | } |
1722e201 JM |
714 | else |
715 | /* In C++20 we just treat the return value as an rvalue that | |
716 | can bind to lvalue refs. */ | |
717 | exp = moved; | |
4ce8c5de | 718 | } |
8af2fec4 | 719 | |
41990f96 | 720 | /* Call the copy constructor. */ |
4ce8c5de JM |
721 | if (!converted) |
722 | { | |
cd9cf97b | 723 | releasing_vec exp_vec (make_tree_vector_single (exp)); |
4ce8c5de JM |
724 | exp = (build_special_member_call |
725 | (object, complete_ctor_identifier, &exp_vec, | |
726 | TREE_TYPE (object), flags, tf_warning_or_error)); | |
4ce8c5de JM |
727 | } |
728 | ||
41990f96 MM |
729 | if (exp == error_mark_node) |
730 | { | |
d3769410 | 731 | inform (exp_loc, " in thrown expression"); |
41990f96 MM |
732 | return error_mark_node; |
733 | } | |
6f30f1f1 | 734 | } |
41990f96 | 735 | else |
10d3a72a | 736 | { |
e88218fd | 737 | tree tmp = decay_conversion (exp, tf_warning_or_error); |
10d3a72a PC |
738 | if (tmp == error_mark_node) |
739 | return error_mark_node; | |
740 | exp = build2 (INIT_EXPR, temp_type, object, tmp); | |
741 | } | |
f4a23343 | 742 | |
b33a0480 JM |
743 | /* Mark any cleanups from the initialization as MUST_NOT_THROW, since |
744 | they are run after the exception object is initialized. */ | |
745 | cp_walk_tree_without_duplicates (&exp, wrap_cleanups_r, 0); | |
6de9cd9a | 746 | |
6f30f1f1 | 747 | /* Prepend the allocation. */ |
f293ce4b | 748 | exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); |
b33a0480 JM |
749 | |
750 | /* Force all the cleanups to be evaluated here so that we don't have | |
751 | to do them during unwinding. */ | |
752 | exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp); | |
72b7eeff | 753 | |
52a11cbf | 754 | throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); |
f4a23343 | 755 | |
eca7fc57 JM |
756 | cleanup = NULL_TREE; |
757 | if (type_build_dtor_call (TREE_TYPE (object))) | |
52a11cbf | 758 | { |
4b4b2e58 | 759 | tree dtor_fn = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), |
098cf31a PP |
760 | complete_dtor_identifier, 0, |
761 | tf_warning_or_error); | |
4b4b2e58 NS |
762 | dtor_fn = BASELINK_FUNCTIONS (dtor_fn); |
763 | mark_used (dtor_fn); | |
eca7fc57 JM |
764 | if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object))) |
765 | { | |
4b4b2e58 | 766 | cxx_mark_addressable (dtor_fn); |
eca7fc57 | 767 | /* Pretend it's a normal function. */ |
4b4b2e58 | 768 | cleanup = build1 (ADDR_EXPR, cleanup_type, dtor_fn); |
eca7fc57 | 769 | } |
f30432d7 | 770 | } |
eca7fc57 | 771 | if (cleanup == NULL_TREE) |
7d60be94 | 772 | cleanup = build_int_cst (cleanup_type, 0); |
c8094d83 | 773 | |
52a11cbf | 774 | /* ??? Indicate that this function call throws throw_type. */ |
e88218fd NS |
775 | tree tmp = cp_build_function_call_nary (throw_fn, tf_warning_or_error, |
776 | ptr, throw_type, cleanup, | |
777 | NULL_TREE); | |
72b7eeff | 778 | |
6f30f1f1 | 779 | /* Tack on the initialization stuff. */ |
f293ce4b | 780 | exp = build2 (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp); |
8d2733ca MS |
781 | } |
782 | else | |
a3b49ccd | 783 | { |
52a11cbf | 784 | /* Rethrow current exception. */ |
4b4b2e58 | 785 | if (!rethrow_fn) |
52a11cbf | 786 | { |
e88218fd NS |
787 | rethrow_fn = declare_library_fn_1 ("__cxa_rethrow", |
788 | ECF_NORETURN | ECF_COLD, | |
789 | void_type_node, 0, NULL); | |
784417d1 | 790 | if (flag_tm && rethrow_fn != error_mark_node) |
4b4b2e58 NS |
791 | apply_tm_attr (rethrow_fn, get_identifier ("transaction_pure")); |
792 | } | |
0a35513e | 793 | |
6f30f1f1 | 794 | /* ??? Indicate that this function call allows exceptions of the type |
c8094d83 | 795 | of the enclosing catch block (if known). */ |
4b4b2e58 | 796 | exp = cp_build_function_call_vec (rethrow_fn, NULL, tf_warning_or_error); |
a3b49ccd | 797 | } |
8d2733ca | 798 | |
d3769410 | 799 | exp = build1_loc (loc, THROW_EXPR, void_type_node, exp); |
02020185 | 800 | |
52a11cbf | 801 | return exp; |
8d08fdba | 802 | } |
4cfbc546 NS |
803 | |
804 | /* Make sure TYPE is complete, pointer to complete, reference to | |
805 | complete, or pointer to cv void. Issue diagnostic on failure. | |
838dfd8a | 806 | Return the zero on failure and nonzero on success. FROM can be |
4cfbc546 NS |
807 | the expr or decl from whence TYPE came, if available. */ |
808 | ||
809 | static int | |
5cc3d3b8 | 810 | complete_ptr_ref_or_void_ptr_p (tree type, tree from) |
4cfbc546 NS |
811 | { |
812 | int is_ptr; | |
c8094d83 | 813 | |
4cfbc546 NS |
814 | /* Check complete. */ |
815 | type = complete_type_or_else (type, from); | |
816 | if (!type) | |
817 | return 0; | |
c8094d83 | 818 | |
4cfbc546 | 819 | /* Or a pointer or ref to one, or cv void *. */ |
50e10fa8 | 820 | is_ptr = TYPE_PTR_P (type); |
9f613f06 | 821 | if (is_ptr || TYPE_REF_P (type)) |
4cfbc546 NS |
822 | { |
823 | tree core = TREE_TYPE (type); | |
c8094d83 | 824 | |
b72801e2 | 825 | if (is_ptr && VOID_TYPE_P (core)) |
0cbd7506 | 826 | /* OK */; |
4cfbc546 | 827 | else if (!complete_type_or_else (core, from)) |
0cbd7506 | 828 | return 0; |
4cfbc546 NS |
829 | } |
830 | return 1; | |
831 | } | |
832 | ||
f9eead1f PC |
833 | /* If IS_THROW is true return truth-value if T is an expression admissible |
834 | in throw-expression, i.e. if it is not of incomplete type or a pointer/ | |
835 | reference to such a type or of an abstract class type. | |
836 | If IS_THROW is false, likewise for a catch parameter, same requirements | |
837 | for its type plus rvalue reference type is also not admissible. */ | |
d064d75a GDR |
838 | |
839 | static bool | |
f9eead1f | 840 | is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw) |
d064d75a | 841 | { |
f9eead1f PC |
842 | tree expr = is_throw ? t : NULL_TREE; |
843 | tree type = TREE_TYPE (t); | |
844 | ||
845 | /* C++11 [except.handle] The exception-declaration shall not denote | |
846 | an incomplete type, an abstract class type, or an rvalue reference | |
847 | type. */ | |
d064d75a GDR |
848 | |
849 | /* 15.1/4 [...] The type of the throw-expression shall not be an | |
0cbd7506 MS |
850 | incomplete type, or a pointer or a reference to an incomplete |
851 | type, other than void*, const void*, volatile void*, or | |
852 | const volatile void*. Except for these restriction and the | |
853 | restrictions on type matching mentioned in 15.3, the operand | |
854 | of throw is treated exactly as a function argument in a call | |
855 | (5.2.2) or the operand of a return statement. */ | |
d064d75a GDR |
856 | if (!complete_ptr_ref_or_void_ptr_p (type, expr)) |
857 | return false; | |
858 | ||
02a32ab4 RS |
859 | tree nonref_type = non_reference (type); |
860 | if (!verify_type_context (input_location, TCTX_EXCEPTIONS, nonref_type)) | |
861 | return false; | |
862 | ||
d064d75a | 863 | /* 10.4/3 An abstract class shall not be used as a parameter type, |
0cbd7506 MS |
864 | as a function return type or as type of an explicit |
865 | conversion. */ | |
2df663cc JM |
866 | else if (abstract_virtuals_error (is_throw ? ACU_THROW : ACU_CATCH, type)) |
867 | return false; | |
f9eead1f | 868 | else if (!is_throw |
9f613f06 | 869 | && TYPE_REF_P (type) |
f9eead1f PC |
870 | && TYPE_REF_IS_RVALUE (type)) |
871 | { | |
a9c697b8 | 872 | error ("cannot declare %<catch%> parameter to be of rvalue " |
f9eead1f | 873 | "reference type %qT", type); |
d064d75a GDR |
874 | return false; |
875 | } | |
785b887e JM |
876 | else if (variably_modified_type_p (type, NULL_TREE)) |
877 | { | |
878 | if (is_throw) | |
d3769410 PC |
879 | error_at (cp_expr_loc_or_input_loc (expr), |
880 | "cannot throw expression of type %qT because it involves " | |
881 | "types of variable size", type); | |
785b887e JM |
882 | else |
883 | error ("cannot catch type %qT because it involves types of " | |
884 | "variable size", type); | |
885 | return false; | |
886 | } | |
d064d75a GDR |
887 | |
888 | return true; | |
889 | } | |
890 | ||
1660cb3a JM |
891 | /* Returns nonzero if FN is a declaration of a standard C library |
892 | function which is known not to throw. | |
893 | ||
894 | [lib.res.on.exception.handling]: None of the functions from the | |
895 | Standard C library shall report an error by throwing an | |
896 | exception, unless it calls a program-supplied function that | |
897 | throws an exception. */ | |
898 | ||
899 | #include "cfns.h" | |
900 | ||
901 | int | |
58f9752a | 902 | nothrow_libfn_p (const_tree fn) |
1660cb3a JM |
903 | { |
904 | tree id; | |
905 | ||
906 | if (TREE_PUBLIC (fn) | |
907 | && DECL_EXTERNAL (fn) | |
92643fea | 908 | && DECL_NAMESPACE_SCOPE_P (fn) |
eb68cb58 | 909 | && DECL_EXTERN_C_P (fn)) |
1660cb3a JM |
910 | /* OK */; |
911 | else | |
912 | /* Can't be a C library function. */ | |
913 | return 0; | |
914 | ||
84b8b0e0 ZW |
915 | /* Being a C library function, DECL_ASSEMBLER_NAME == DECL_NAME |
916 | unless the system headers are playing rename tricks, and if | |
917 | they are, we don't want to be confused by them. */ | |
918 | id = DECL_NAME (fn); | |
6b56d5f5 JJ |
919 | const struct libc_name_struct *s |
920 | = libc_name::libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id)); | |
921 | if (s == NULL) | |
922 | return 0; | |
923 | switch (s->c_ver) | |
924 | { | |
925 | case 89: return 1; | |
926 | case 99: return !flag_iso || flag_isoc99; | |
927 | case 11: return !flag_iso || flag_isoc11; | |
928 | default: gcc_unreachable (); | |
929 | } | |
1660cb3a | 930 | } |
2bc9f1d1 JM |
931 | |
932 | /* Returns nonzero if an exception of type FROM will be caught by a | |
933 | handler for type TO, as per [except.handle]. */ | |
934 | ||
43d3b7bc | 935 | static bool |
5cc3d3b8 | 936 | can_convert_eh (tree to, tree from) |
2bc9f1d1 | 937 | { |
ee76b931 MM |
938 | to = non_reference (to); |
939 | from = non_reference (from); | |
2bc9f1d1 | 940 | |
43d3b7bc MP |
941 | if (same_type_ignoring_top_level_qualifiers_p (to, from)) |
942 | return true; | |
943 | ||
50e10fa8 | 944 | if (TYPE_PTR_P (to) && TYPE_PTR_P (from)) |
2bc9f1d1 JM |
945 | { |
946 | to = TREE_TYPE (to); | |
947 | from = TREE_TYPE (from); | |
948 | ||
949 | if (! at_least_as_qualified_p (to, from)) | |
43d3b7bc | 950 | return false; |
2bc9f1d1 | 951 | |
50e10fa8 | 952 | if (VOID_TYPE_P (to)) |
43d3b7bc | 953 | return true; |
2bc9f1d1 | 954 | |
f4f206f4 | 955 | /* Else fall through. */ |
2bc9f1d1 JM |
956 | } |
957 | ||
2d46ec83 | 958 | if (CLASS_TYPE_P (to) && CLASS_TYPE_P (from) |
22854930 | 959 | && publicly_uniquely_derived_p (to, from)) |
43d3b7bc | 960 | return true; |
2bc9f1d1 | 961 | |
43d3b7bc | 962 | return false; |
2bc9f1d1 JM |
963 | } |
964 | ||
325c3691 RH |
965 | /* Check whether any of the handlers in I are shadowed by another handler |
966 | accepting TYPE. Note that the shadowing may not be complete; even if | |
967 | an exception of type B would be caught by a handler for A, there could | |
968 | be a derived class C for which A is an ambiguous base but B is not, so | |
969 | the handler for B would catch an exception of type C. */ | |
2bc9f1d1 JM |
970 | |
971 | static void | |
325c3691 | 972 | check_handlers_1 (tree master, tree_stmt_iterator i) |
2bc9f1d1 JM |
973 | { |
974 | tree type = TREE_TYPE (master); | |
2bc9f1d1 | 975 | |
325c3691 RH |
976 | for (; !tsi_end_p (i); tsi_next (&i)) |
977 | { | |
978 | tree handler = tsi_stmt (i); | |
979 | if (TREE_TYPE (handler) && can_convert_eh (type, TREE_TYPE (handler))) | |
980 | { | |
44e1f63e | 981 | auto_diagnostic_group d; |
1d87302a MP |
982 | if (warning_at (EXPR_LOCATION (handler), OPT_Wexceptions, |
983 | "exception of type %qT will be caught by earlier " | |
984 | "handler", TREE_TYPE (handler))) | |
985 | inform (EXPR_LOCATION (master), "for type %qT", type); | |
325c3691 | 986 | break; |
0cbd7506 | 987 | } |
325c3691 | 988 | } |
2bc9f1d1 JM |
989 | } |
990 | ||
325c3691 | 991 | /* Given a STATEMENT_LIST of HANDLERs, make sure that they're OK. */ |
2bc9f1d1 JM |
992 | |
993 | void | |
5cc3d3b8 | 994 | check_handlers (tree handlers) |
2bc9f1d1 | 995 | { |
325c3691 RH |
996 | tree_stmt_iterator i; |
997 | ||
998 | /* If we don't have a STATEMENT_LIST, then we've just got one | |
999 | handler, and thus nothing to warn about. */ | |
1000 | if (TREE_CODE (handlers) != STATEMENT_LIST) | |
1001 | return; | |
1002 | ||
1003 | i = tsi_start (handlers); | |
1004 | if (!tsi_end_p (i)) | |
1005 | while (1) | |
1006 | { | |
0cbd7506 | 1007 | tree handler = tsi_stmt (i); |
325c3691 RH |
1008 | tsi_next (&i); |
1009 | ||
1010 | /* No more handlers; nothing to shadow. */ | |
1011 | if (tsi_end_p (i)) | |
1012 | break; | |
1013 | if (TREE_TYPE (handler) == NULL_TREE) | |
69bc6bff MLI |
1014 | permerror (EXPR_LOCATION (handler), "%<...%>" |
1015 | " handler must be the last handler for its try block"); | |
325c3691 RH |
1016 | else |
1017 | check_handlers_1 (handler, i); | |
1018 | } | |
2bc9f1d1 | 1019 | } |
0a766368 JM |
1020 | |
1021 | /* walk_tree helper for finish_noexcept_expr. Returns non-null if the | |
1022 | expression *TP causes the noexcept operator to evaluate to false. | |
1023 | ||
1024 | 5.3.7 [expr.noexcept]: The result of the noexcept operator is false if | |
1025 | in a potentially-evaluated context the expression would contain | |
1026 | * a potentially evaluated call to a function, member function, | |
1027 | function pointer, or member function pointer that does not have a | |
1028 | non-throwing exception-specification (15.4), | |
1029 | * a potentially evaluated throw-expression (15.1), | |
1030 | * a potentially evaluated dynamic_cast expression dynamic_cast<T>(v), | |
1031 | where T is a reference type, that requires a run-time check (5.2.7), or | |
1032 | * a potentially evaluated typeid expression (5.2.8) applied to a glvalue | |
1033 | expression whose type is a polymorphic class type (10.3). */ | |
1034 | ||
1035 | static tree | |
dee00bf6 | 1036 | check_noexcept_r (tree *tp, int *walk_subtrees, void *) |
0a766368 JM |
1037 | { |
1038 | tree t = *tp; | |
1039 | enum tree_code code = TREE_CODE (t); | |
dee00bf6 MP |
1040 | |
1041 | if (unevaluated_p (code)) | |
1042 | *walk_subtrees = false; | |
1043 | else if ((code == CALL_EXPR && CALL_EXPR_FN (t)) | |
1044 | || code == AGGR_INIT_EXPR) | |
0a766368 JM |
1045 | { |
1046 | /* We can only use the exception specification of the called function | |
1047 | for determining the value of a noexcept expression; we can't use | |
1048 | TREE_NOTHROW, as it might have a different value in another | |
1049 | translation unit, creating ODR problems. | |
1050 | ||
1051 | We could use TREE_NOTHROW (t) for !TREE_PUBLIC fns, though... */ | |
babaa9df | 1052 | tree fn = cp_get_callee (t); |
edabbec3 JM |
1053 | if (concept_check_p (fn)) |
1054 | return NULL_TREE; | |
5c563482 | 1055 | tree type = TREE_TYPE (fn); |
71a93b08 | 1056 | gcc_assert (INDIRECT_TYPE_P (type)); |
5c563482 | 1057 | type = TREE_TYPE (type); |
59f9c2ed JM |
1058 | |
1059 | STRIP_NOPS (fn); | |
0a766368 | 1060 | if (TREE_CODE (fn) == ADDR_EXPR) |
fa2200cb JM |
1061 | fn = TREE_OPERAND (fn, 0); |
1062 | if (TREE_CODE (fn) == FUNCTION_DECL) | |
0a766368 JM |
1063 | { |
1064 | /* We do use TREE_NOTHROW for ABI internals like __dynamic_cast, | |
1065 | and for C library functions known not to throw. */ | |
fa2200cb | 1066 | if (DECL_EXTERN_C_P (fn) |
59f9c2ed JM |
1067 | && (DECL_ARTIFICIAL (fn) |
1068 | || nothrow_libfn_p (fn))) | |
1069 | return TREE_NOTHROW (fn) ? NULL_TREE : fn; | |
c46f1a17 MP |
1070 | /* We used to treat a call to a constexpr function as noexcept if |
1071 | the call was a constant expression (CWG 1129). This has changed | |
1072 | in P0003 whereby noexcept has no special rule for constant | |
1073 | expressions anymore. Since the current behavior is important for | |
1074 | certain library functionality, we treat this as a DR, therefore | |
1075 | adjusting the behavior for C++11 and C++14. Previously, we had | |
1076 | to evaluate the noexcept-specifier's operand here, but that could | |
1077 | cause instantiations that would fail. */ | |
0a766368 | 1078 | } |
59f9c2ed JM |
1079 | if (!TYPE_NOTHROW_P (type)) |
1080 | return fn; | |
0a766368 JM |
1081 | } |
1082 | ||
1083 | return NULL_TREE; | |
1084 | } | |
1085 | ||
2c5df20f JM |
1086 | /* If a function that causes a noexcept-expression to be false isn't |
1087 | defined yet, remember it and check it for TREE_NOTHROW again at EOF. */ | |
1088 | ||
a79683d5 | 1089 | struct GTY(()) pending_noexcept { |
2c5df20f JM |
1090 | tree fn; |
1091 | location_t loc; | |
a79683d5 | 1092 | }; |
9771b263 | 1093 | static GTY(()) vec<pending_noexcept, va_gc> *pending_noexcept_checks; |
2c5df20f JM |
1094 | |
1095 | /* FN is a FUNCTION_DECL that caused a noexcept-expr to be false. Warn if | |
1f6c1c82 PP |
1096 | it can't throw. |
1097 | ||
1098 | TODO: Consider extending -Wnoexcept to do something like walk_subtrees in the | |
1099 | case of a defaulted function that obtained a noexcept(false) spec. */ | |
2c5df20f JM |
1100 | |
1101 | static void | |
1102 | maybe_noexcept_warning (tree fn) | |
1103 | { | |
5035cd66 JM |
1104 | if (TREE_NOTHROW (fn) |
1105 | && (!DECL_IN_SYSTEM_HEADER (fn) | |
1106 | || global_dc->dc_warn_system_headers)) | |
2c5df20f | 1107 | { |
3cf63c94 | 1108 | auto s = make_temp_override (global_dc->dc_warn_system_headers, true); |
5035cd66 JM |
1109 | auto_diagnostic_group d; |
1110 | if (warning (OPT_Wnoexcept, "noexcept-expression evaluates to %<false%> " | |
1111 | "because of a call to %qD", fn)) | |
1112 | inform (DECL_SOURCE_LOCATION (fn), | |
1113 | "but %qD does not throw; perhaps " | |
1114 | "it should be declared %<noexcept%>", fn); | |
2c5df20f JM |
1115 | } |
1116 | } | |
1117 | ||
1118 | /* Check any functions that weren't defined earlier when they caused a | |
1119 | noexcept expression to evaluate to false. */ | |
1120 | ||
1121 | void | |
1122 | perform_deferred_noexcept_checks (void) | |
1123 | { | |
1124 | int i; | |
1125 | pending_noexcept *p; | |
1126 | location_t saved_loc = input_location; | |
9771b263 | 1127 | FOR_EACH_VEC_SAFE_ELT (pending_noexcept_checks, i, p) |
2c5df20f JM |
1128 | { |
1129 | input_location = p->loc; | |
1130 | maybe_noexcept_warning (p->fn); | |
1131 | } | |
1132 | input_location = saved_loc; | |
1133 | } | |
1134 | ||
0a766368 JM |
1135 | /* Evaluate noexcept ( EXPR ). */ |
1136 | ||
1137 | tree | |
59f9c2ed | 1138 | finish_noexcept_expr (tree expr, tsubst_flags_t complain) |
0a766368 | 1139 | { |
d0bb79ac JM |
1140 | if (expr == error_mark_node) |
1141 | return error_mark_node; | |
1142 | ||
0a766368 JM |
1143 | if (processing_template_decl) |
1144 | return build_min (NOEXCEPT_EXPR, boolean_type_node, expr); | |
1145 | ||
6eaade31 JM |
1146 | return (expr_noexcept_p (expr, complain) |
1147 | ? boolean_true_node : boolean_false_node); | |
1148 | } | |
1149 | ||
1150 | /* Returns whether EXPR is noexcept, possibly warning if allowed by | |
1151 | COMPLAIN. */ | |
1152 | ||
1153 | bool | |
1154 | expr_noexcept_p (tree expr, tsubst_flags_t complain) | |
1155 | { | |
1156 | tree fn; | |
1157 | ||
1158 | if (expr == error_mark_node) | |
1159 | return false; | |
1160 | ||
59f9c2ed JM |
1161 | fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0); |
1162 | if (fn) | |
1163 | { | |
2c5df20f JM |
1164 | if ((complain & tf_warning) && warn_noexcept |
1165 | && TREE_CODE (fn) == FUNCTION_DECL) | |
59f9c2ed | 1166 | { |
2c5df20f JM |
1167 | if (!DECL_INITIAL (fn)) |
1168 | { | |
1169 | /* Not defined yet; check again at EOF. */ | |
f32682ca | 1170 | pending_noexcept p = {fn, input_location}; |
9771b263 | 1171 | vec_safe_push (pending_noexcept_checks, p); |
2c5df20f JM |
1172 | } |
1173 | else | |
1174 | maybe_noexcept_warning (fn); | |
59f9c2ed | 1175 | } |
6eaade31 | 1176 | return false; |
59f9c2ed | 1177 | } |
0a766368 | 1178 | else |
6eaade31 | 1179 | return true; |
0a766368 | 1180 | } |
3a55fb4c JM |
1181 | |
1182 | /* Return true iff SPEC is throw() or noexcept(true). */ | |
1183 | ||
1184 | bool | |
1185 | nothrow_spec_p (const_tree spec) | |
1186 | { | |
10261728 | 1187 | gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec)); |
96176bb3 NS |
1188 | |
1189 | if (spec == empty_except_spec | |
3a55fb4c JM |
1190 | || spec == noexcept_true_spec) |
1191 | return true; | |
96176bb3 NS |
1192 | |
1193 | gcc_assert (!spec | |
1194 | || TREE_VALUE (spec) | |
1195 | || spec == noexcept_false_spec | |
1196 | || TREE_PURPOSE (spec) == error_mark_node | |
78f7607d | 1197 | || UNPARSED_NOEXCEPT_SPEC_P (spec) |
96176bb3 NS |
1198 | || processing_template_decl); |
1199 | ||
3a55fb4c JM |
1200 | return false; |
1201 | } | |
1202 | ||
1203 | /* For FUNCTION_TYPE or METHOD_TYPE, true if NODE is noexcept. This is the | |
1204 | case for things declared noexcept(true) and, with -fnothrow-opt, for | |
1205 | throw() functions. */ | |
1206 | ||
1207 | bool | |
1208 | type_noexcept_p (const_tree type) | |
1209 | { | |
1210 | tree spec = TYPE_RAISES_EXCEPTIONS (type); | |
10261728 | 1211 | gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec)); |
3a55fb4c JM |
1212 | if (flag_nothrow_opt) |
1213 | return nothrow_spec_p (spec); | |
1214 | else | |
1215 | return spec == noexcept_true_spec; | |
1216 | } | |
1217 | ||
1218 | /* For FUNCTION_TYPE or METHOD_TYPE, true if NODE can throw any type, | |
1219 | i.e. no exception-specification or noexcept(false). */ | |
1220 | ||
1221 | bool | |
1222 | type_throw_all_p (const_tree type) | |
1223 | { | |
1224 | tree spec = TYPE_RAISES_EXCEPTIONS (type); | |
10261728 | 1225 | gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec)); |
3a55fb4c JM |
1226 | return spec == NULL_TREE || spec == noexcept_false_spec; |
1227 | } | |
1228 | ||
1229 | /* Create a representation of the noexcept-specification with | |
1230 | constant-expression of EXPR. COMPLAIN is as for tsubst. */ | |
1231 | ||
1232 | tree | |
779d8a5a | 1233 | build_noexcept_spec (tree expr, tsubst_flags_t complain) |
3a55fb4c | 1234 | { |
2cd5333d MP |
1235 | if (check_for_bare_parameter_packs (expr)) |
1236 | return error_mark_node; | |
38f3a877 | 1237 | if (TREE_CODE (expr) != DEFERRED_NOEXCEPT |
0d699def | 1238 | && !value_dependent_expression_p (expr)) |
fa2200cb | 1239 | { |
cc3bae3d | 1240 | expr = build_converted_constant_bool_expr (expr, complain); |
d417b4f5 | 1241 | expr = instantiate_non_dependent_expr_sfinae (expr, complain); |
0309d288 | 1242 | expr = cxx_constant_value (expr); |
fa2200cb | 1243 | } |
84fd832c JJ |
1244 | if (TREE_CODE (expr) == INTEGER_CST) |
1245 | { | |
1246 | if (operand_equal_p (expr, boolean_true_node, 0)) | |
1247 | return noexcept_true_spec; | |
1248 | else | |
1249 | { | |
1250 | gcc_checking_assert (operand_equal_p (expr, boolean_false_node, 0)); | |
1251 | return noexcept_false_spec; | |
1252 | } | |
1253 | } | |
d0bb79ac JM |
1254 | else if (expr == error_mark_node) |
1255 | return error_mark_node; | |
3a55fb4c JM |
1256 | else |
1257 | { | |
84fd832c | 1258 | gcc_assert (processing_template_decl |
10261728 | 1259 | || TREE_CODE (expr) == DEFERRED_NOEXCEPT); |
dd39c7d1 JM |
1260 | if (TREE_CODE (expr) != DEFERRED_NOEXCEPT) |
1261 | /* Avoid problems with a function type built with a dependent typedef | |
1262 | being reused in another scope (c++/84045). */ | |
1263 | expr = strip_typedefs_expr (expr); | |
3a55fb4c JM |
1264 | return build_tree_list (expr, NULL_TREE); |
1265 | } | |
1266 | } | |
b6c917ff | 1267 | |
bcfc2227 JM |
1268 | /* If the current function has a cleanup that might throw, and the return value |
1269 | has a non-trivial destructor, return a MODIFY_EXPR to set | |
1270 | current_retval_sentinel so that we know that the return value needs to be | |
1271 | destroyed on throw. Otherwise, returns NULL_TREE. */ | |
1272 | ||
1273 | tree | |
1274 | maybe_set_retval_sentinel () | |
1275 | { | |
1276 | if (processing_template_decl) | |
1277 | return NULL_TREE; | |
1278 | tree retval = DECL_RESULT (current_function_decl); | |
1279 | if (!TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (retval))) | |
1280 | return NULL_TREE; | |
1281 | if (!cp_function_chain->throwing_cleanup) | |
1282 | return NULL_TREE; | |
1283 | ||
1284 | if (!current_retval_sentinel) | |
1285 | { | |
1286 | /* Just create the temporary now, maybe_splice_retval_cleanup | |
1287 | will do the rest. */ | |
1288 | current_retval_sentinel = create_temporary_var (boolean_type_node); | |
1289 | DECL_INITIAL (current_retval_sentinel) = boolean_false_node; | |
1290 | pushdecl_outermost_localscope (current_retval_sentinel); | |
1291 | } | |
1292 | ||
1293 | return build2 (MODIFY_EXPR, boolean_type_node, | |
1294 | current_retval_sentinel, boolean_true_node); | |
1295 | } | |
1296 | ||
1297 | /* COMPOUND_STMT is the STATEMENT_LIST for the current function body. If | |
1298 | current_retval_sentinel was set in this function, wrap the body in a | |
1299 | CLEANUP_STMT to destroy the return value on throw. */ | |
1300 | ||
1301 | void | |
1302 | maybe_splice_retval_cleanup (tree compound_stmt) | |
1303 | { | |
1304 | /* If need_retval_cleanup set current_retval_sentinel, wrap the function body | |
1305 | in a CLEANUP_STMT to handle destroying the return value. */ | |
1306 | if (!DECL_CONSTRUCTOR_P (current_function_decl) | |
1307 | && !DECL_DESTRUCTOR_P (current_function_decl) | |
1308 | && current_retval_sentinel) | |
1309 | { | |
1310 | location_t loc = DECL_SOURCE_LOCATION (current_function_decl); | |
1311 | ||
1312 | /* Add a DECL_EXPR for current_retval_sentinel. */ | |
1313 | tree_stmt_iterator iter = tsi_start (compound_stmt); | |
1314 | tree retval = DECL_RESULT (current_function_decl); | |
1315 | tree decl_expr = build_stmt (loc, DECL_EXPR, current_retval_sentinel); | |
1316 | tsi_link_before (&iter, decl_expr, TSI_SAME_STMT); | |
1317 | ||
1318 | /* Skip past other decls, they can't contain a return. */ | |
1319 | while (TREE_CODE (tsi_stmt (iter)) == DECL_EXPR) | |
1320 | tsi_next (&iter); | |
1321 | gcc_assert (!tsi_end_p (iter)); | |
1322 | ||
1323 | /* Wrap the rest of the STATEMENT_LIST in a CLEANUP_STMT. */ | |
1324 | tree stmts = NULL_TREE; | |
1325 | while (!tsi_end_p (iter)) | |
1326 | { | |
1327 | append_to_statement_list_force (tsi_stmt (iter), &stmts); | |
1328 | tsi_delink (&iter); | |
1329 | } | |
1330 | tree dtor = build_cleanup (retval); | |
1331 | tree cond = build3 (COND_EXPR, void_type_node, current_retval_sentinel, | |
1332 | dtor, void_node); | |
1333 | tree cleanup = build_stmt (loc, CLEANUP_STMT, | |
1334 | stmts, cond, retval); | |
1335 | CLEANUP_EH_ONLY (cleanup) = true; | |
1336 | append_to_statement_list_force (cleanup, &compound_stmt); | |
1337 | } | |
1338 | } | |
1339 | ||
b6c917ff | 1340 | #include "gt-cp-except.h" |