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