annotate gcc/cp/except.c @ 158:494b0b89df80 default tip

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