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