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