]>
Commit | Line | Data |
---|---|---|
8d08fdba MS |
1 | /* Handle the hair of processing (but not expanding) inline functions. |
2 | Also manage function and variable name overloading. | |
17211ab5 | 3 | Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, |
71af2621 | 4 | 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. |
8d08fdba MS |
5 | Contributed by Michael Tiemann (tiemann@cygnus.com) |
6 | ||
f5adbb8d | 7 | This file is part of GCC. |
8d08fdba | 8 | |
f5adbb8d | 9 | GCC is free software; you can redistribute it and/or modify |
8d08fdba MS |
10 | it under the terms of the GNU General Public License as published by |
11 | the Free Software Foundation; either version 2, or (at your option) | |
12 | any later version. | |
13 | ||
f5adbb8d | 14 | GCC is distributed in the hope that it will be useful, |
8d08fdba MS |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
f5adbb8d | 20 | along with GCC; see the file COPYING. If not, write to |
e9fa0c7c RK |
21 | the Free Software Foundation, 59 Temple Place - Suite 330, |
22 | Boston, MA 02111-1307, USA. */ | |
8d08fdba MS |
23 | |
24 | ||
8d08fdba | 25 | /* Handle method declarations. */ |
8d08fdba | 26 | #include "config.h" |
e817b5e3 | 27 | #include "system.h" |
4977bab6 ZW |
28 | #include "coretypes.h" |
29 | #include "tm.h" | |
8d08fdba MS |
30 | #include "tree.h" |
31 | #include "cp-tree.h" | |
8926095f MS |
32 | #include "rtl.h" |
33 | #include "expr.h" | |
34 | #include "output.h" | |
8926095f | 35 | #include "flags.h" |
54f92bfb | 36 | #include "toplev.h" |
b1afd7f4 | 37 | #include "tm_p.h" |
483ab821 | 38 | #include "target.h" |
8d08fdba | 39 | |
669ec2b4 JM |
40 | /* Various flags to control the mangling process. */ |
41 | ||
42 | enum mangling_flags | |
43 | { | |
44 | /* No flags. */ | |
45 | mf_none = 0, | |
46 | /* The thing we are presently mangling is part of a template type, | |
47 | rather than a fully instantiated type. Therefore, we may see | |
48 | complex expressions where we would normally expect to see a | |
49 | simple integer constant. */ | |
50 | mf_maybe_uninstantiated = 1, | |
51 | /* When mangling a numeric value, use the form `_XX_' (instead of | |
52 | just `XX') if the value has more than one digit. */ | |
de94b46c | 53 | mf_use_underscores_around_value = 2 |
669ec2b4 JM |
54 | }; |
55 | ||
56 | typedef enum mangling_flags mangling_flags; | |
57 | ||
4977bab6 ZW |
58 | static tree thunk_adjust (tree, bool, HOST_WIDE_INT, tree); |
59 | static void do_build_assign_ref (tree); | |
60 | static void do_build_copy_constructor (tree); | |
61 | static tree synthesize_exception_spec (tree, tree (*) (tree, void *), void *); | |
62 | static tree locate_dtor (tree, void *); | |
63 | static tree locate_ctor (tree, void *); | |
64 | static tree locate_copy (tree, void *); | |
d46c570d | 65 | static tree make_alias_for_thunk (tree); |
669ec2b4 | 66 | |
669ec2b4 JM |
67 | /* Called once to initialize method.c. */ |
68 | ||
69 | void | |
4977bab6 | 70 | init_method (void) |
669ec2b4 | 71 | { |
1f84ec23 | 72 | init_mangle (); |
669ec2b4 | 73 | } |
8926095f | 74 | \f |
4977bab6 ZW |
75 | /* Return a this or result adjusting thunk to FUNCTION. THIS_ADJUSTING |
76 | indicates whether it is a this or result adjusting thunk. | |
77 | FIXED_OFFSET and VIRTUAL_OFFSET indicate how to do the adjustment | |
78 | (see thunk_adjust). VIRTUAL_OFFSET can be NULL, but FIXED_OFFSET | |
79 | never is. VIRTUAL_OFFSET is the /index/ into the vtable for this | |
80 | adjusting thunks, we scale it to a byte offset. For covariant | |
81 | thunks VIRTUAL_OFFSET is the virtual binfo. You must post process | |
82 | the returned thunk with finish_thunk. */ | |
1f6e1acc | 83 | |
8926095f | 84 | tree |
4977bab6 ZW |
85 | make_thunk (tree function, bool this_adjusting, |
86 | tree fixed_offset, tree virtual_offset) | |
8926095f | 87 | { |
31f8e4f3 | 88 | HOST_WIDE_INT d; |
4977bab6 ZW |
89 | tree thunk; |
90 | ||
bb5e8a7f | 91 | my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 20021025); |
9bcb9aae | 92 | /* We can have this thunks to covariant thunks, but not vice versa. */ |
4977bab6 | 93 | my_friendly_assert (!DECL_THIS_THUNK_P (function), 20021127); |
bb885938 NS |
94 | my_friendly_assert (!DECL_RESULT_THUNK_P (function) || this_adjusting, |
95 | 20031123); | |
4977bab6 ZW |
96 | |
97 | /* Scale the VIRTUAL_OFFSET to be in terms of bytes. */ | |
98 | if (this_adjusting && virtual_offset) | |
99 | virtual_offset | |
31f8e4f3 | 100 | = size_binop (MULT_EXPR, |
4977bab6 ZW |
101 | virtual_offset, |
102 | convert (ssizetype, | |
103 | TYPE_SIZE_UNIT (vtable_entry_type))); | |
104 | ||
105 | d = tree_low_cst (fixed_offset, 0); | |
106 | ||
107 | /* See if we already have the thunk in question. For this_adjusting | |
108 | thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it | |
9bcb9aae | 109 | will be a BINFO. */ |
bb5e8a7f | 110 | for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk)) |
e00853fd NS |
111 | if (DECL_THIS_THUNK_P (thunk) == this_adjusting |
112 | && THUNK_FIXED_OFFSET (thunk) == d | |
113 | && !virtual_offset == !THUNK_VIRTUAL_OFFSET (thunk) | |
114 | && (!virtual_offset | |
115 | || (this_adjusting | |
116 | ? tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk), | |
117 | virtual_offset) | |
118 | : THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset))) | |
119 | return thunk; | |
4977bab6 | 120 | |
bb5e8a7f MM |
121 | /* All thunks must be created before FUNCTION is actually emitted; |
122 | the ABI requires that all thunks be emitted together with the | |
123 | function to which they transfer control. */ | |
124 | my_friendly_assert (!TREE_ASM_WRITTEN (function), 20021025); | |
90d46c28 NS |
125 | /* Likewise, we can only be adding thunks to a function declared in |
126 | the class currently being laid out. */ | |
127 | my_friendly_assert (TYPE_SIZE (DECL_CONTEXT (function)) | |
128 | && TYPE_BEING_DEFINED (DECL_CONTEXT (function)), | |
129 | 20031211); | |
bb5e8a7f | 130 | |
4977bab6 | 131 | thunk = build_decl (FUNCTION_DECL, NULL_TREE, TREE_TYPE (function)); |
bb5e8a7f | 132 | DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function); |
07fa4878 | 133 | cxx_dup_lang_specific_decl (thunk); |
bb885938 NS |
134 | DECL_THUNKS (thunk) = NULL_TREE; |
135 | ||
bb5e8a7f MM |
136 | DECL_CONTEXT (thunk) = DECL_CONTEXT (function); |
137 | TREE_READONLY (thunk) = TREE_READONLY (function); | |
138 | TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function); | |
139 | TREE_PUBLIC (thunk) = TREE_PUBLIC (function); | |
140 | if (flag_weak) | |
141 | comdat_linkage (thunk); | |
4977bab6 | 142 | SET_DECL_THUNK_P (thunk, this_adjusting); |
07fa4878 NS |
143 | THUNK_TARGET (thunk) = function; |
144 | THUNK_FIXED_OFFSET (thunk) = d; | |
4977bab6 | 145 | THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset; |
e00853fd | 146 | THUNK_ALIAS (thunk) = NULL_TREE; |
4977bab6 | 147 | |
bb5e8a7f MM |
148 | /* The thunk itself is not a constructor or destructor, even if |
149 | the thing it is thunking to is. */ | |
150 | DECL_INTERFACE_KNOWN (thunk) = 1; | |
151 | DECL_NOT_REALLY_EXTERN (thunk) = 1; | |
152 | DECL_SAVED_FUNCTION_DATA (thunk) = NULL; | |
153 | DECL_DESTRUCTOR_P (thunk) = 0; | |
154 | DECL_CONSTRUCTOR_P (thunk) = 0; | |
155 | /* And neither is it a clone. */ | |
156 | DECL_CLONED_FUNCTION (thunk) = NULL_TREE; | |
157 | DECL_EXTERNAL (thunk) = 1; | |
158 | DECL_ARTIFICIAL (thunk) = 1; | |
159 | /* Even if this thunk is a member of a local class, we don't | |
160 | need a static chain. */ | |
161 | DECL_NO_STATIC_CHAIN (thunk) = 1; | |
162 | /* The THUNK is not a pending inline, even if the FUNCTION is. */ | |
163 | DECL_PENDING_INLINE_P (thunk) = 0; | |
eab5474f NS |
164 | DECL_INLINE (thunk) = 0; |
165 | DECL_DECLARED_INLINE_P (thunk) = 0; | |
bb5e8a7f MM |
166 | /* Nor has it been deferred. */ |
167 | DECL_DEFERRED_FN (thunk) = 0; | |
bb885938 | 168 | |
bb5e8a7f MM |
169 | /* Add it to the list of thunks associated with FUNCTION. */ |
170 | TREE_CHAIN (thunk) = DECL_THUNKS (function); | |
171 | DECL_THUNKS (function) = thunk; | |
cc600f33 | 172 | |
8926095f MS |
173 | return thunk; |
174 | } | |
175 | ||
07fa4878 | 176 | /* Finish THUNK, a thunk decl. */ |
eb448459 | 177 | |
8926095f | 178 | void |
07fa4878 | 179 | finish_thunk (tree thunk) |
4977bab6 ZW |
180 | { |
181 | tree function, name; | |
07fa4878 NS |
182 | tree fixed_offset = ssize_int (THUNK_FIXED_OFFSET (thunk)); |
183 | tree virtual_offset = THUNK_VIRTUAL_OFFSET (thunk); | |
184 | ||
4977bab6 | 185 | my_friendly_assert (!DECL_NAME (thunk) && DECL_THUNK_P (thunk), 20021127); |
07fa4878 NS |
186 | if (virtual_offset && DECL_RESULT_THUNK_P (thunk)) |
187 | virtual_offset = BINFO_VPTR_FIELD (virtual_offset); | |
188 | function = THUNK_TARGET (thunk); | |
4977bab6 | 189 | name = mangle_thunk (function, DECL_THIS_THUNK_P (thunk), |
07fa4878 | 190 | fixed_offset, virtual_offset); |
bb885938 NS |
191 | |
192 | /* We can end up with declarations of (logically) different | |
193 | covariant thunks, that do identical adjustments. The two thunks | |
194 | will be adjusting between within different hierarchies, which | |
195 | happen to have the same layout. We must nullify one of them to | |
196 | refer to the other. */ | |
197 | if (DECL_RESULT_THUNK_P (thunk)) | |
198 | { | |
199 | tree cov_probe; | |
200 | ||
201 | for (cov_probe = DECL_THUNKS (function); | |
202 | cov_probe; cov_probe = TREE_CHAIN (cov_probe)) | |
203 | if (DECL_NAME (cov_probe) == name) | |
204 | { | |
205 | my_friendly_assert (!DECL_THUNKS (thunk), 20031023); | |
e00853fd | 206 | THUNK_ALIAS (thunk) = (THUNK_ALIAS (cov_probe) |
bb885938 NS |
207 | ? THUNK_ALIAS (cov_probe) : cov_probe); |
208 | break; | |
209 | } | |
210 | } | |
211 | ||
4977bab6 ZW |
212 | DECL_NAME (thunk) = name; |
213 | SET_DECL_ASSEMBLER_NAME (thunk, name); | |
214 | } | |
215 | ||
216 | /* Adjust PTR by the constant FIXED_OFFSET, and by the vtable | |
217 | offset indicated by VIRTUAL_OFFSET, if that is | |
4de8668e | 218 | non-null. THIS_ADJUSTING is nonzero for a this adjusting thunk and |
9bcb9aae | 219 | zero for a result adjusting thunk. */ |
4977bab6 ZW |
220 | |
221 | static tree | |
222 | thunk_adjust (tree ptr, bool this_adjusting, | |
223 | HOST_WIDE_INT fixed_offset, tree virtual_offset) | |
224 | { | |
225 | if (this_adjusting) | |
226 | /* Adjust the pointer by the constant. */ | |
227 | ptr = fold (build (PLUS_EXPR, TREE_TYPE (ptr), ptr, | |
228 | ssize_int (fixed_offset))); | |
229 | ||
230 | /* If there's a virtual offset, look up that value in the vtable and | |
231 | adjust the pointer again. */ | |
232 | if (virtual_offset) | |
233 | { | |
234 | tree vtable; | |
235 | ||
4977bab6 ZW |
236 | ptr = save_expr (ptr); |
237 | /* The vptr is always at offset zero in the object. */ | |
238 | vtable = build1 (NOP_EXPR, | |
239 | build_pointer_type (build_pointer_type | |
240 | (vtable_entry_type)), | |
241 | ptr); | |
242 | /* Form the vtable address. */ | |
243 | vtable = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (vtable)), vtable); | |
244 | /* Find the entry with the vcall offset. */ | |
245 | vtable = build (PLUS_EXPR, TREE_TYPE (vtable), vtable, virtual_offset); | |
246 | /* Get the offset itself. */ | |
247 | vtable = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (vtable)), vtable); | |
248 | /* Adjust the `this' pointer. */ | |
249 | ptr = fold (build (PLUS_EXPR, TREE_TYPE (ptr), ptr, vtable)); | |
250 | } | |
251 | ||
252 | if (!this_adjusting) | |
253 | /* Adjust the pointer by the constant. */ | |
254 | ptr = fold (build (PLUS_EXPR, TREE_TYPE (ptr), ptr, | |
255 | ssize_int (fixed_offset))); | |
256 | ||
257 | return ptr; | |
258 | } | |
259 | ||
89ce1c8f JJ |
260 | static GTY (()) int thunk_labelno; |
261 | ||
262 | /* Create a static alias to function. */ | |
263 | ||
264 | static tree | |
265 | make_alias_for_thunk (tree function) | |
266 | { | |
267 | tree alias; | |
268 | char buf[256]; | |
269 | ||
270 | ASM_GENERATE_INTERNAL_LABEL (buf, "LTHUNK", thunk_labelno); | |
271 | thunk_labelno++; | |
272 | alias = build_decl (FUNCTION_DECL, get_identifier (buf), | |
273 | TREE_TYPE (function)); | |
274 | DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function); | |
275 | cxx_dup_lang_specific_decl (alias); | |
276 | DECL_CONTEXT (alias) = NULL; | |
277 | TREE_READONLY (alias) = TREE_READONLY (function); | |
278 | TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function); | |
279 | TREE_PUBLIC (alias) = 0; | |
280 | DECL_INTERFACE_KNOWN (alias) = 1; | |
281 | DECL_NOT_REALLY_EXTERN (alias) = 1; | |
282 | DECL_THIS_STATIC (alias) = 1; | |
283 | DECL_SAVED_FUNCTION_DATA (alias) = NULL; | |
284 | DECL_DESTRUCTOR_P (alias) = 0; | |
285 | DECL_CONSTRUCTOR_P (alias) = 0; | |
286 | DECL_CLONED_FUNCTION (alias) = NULL_TREE; | |
287 | DECL_EXTERNAL (alias) = 0; | |
288 | DECL_ARTIFICIAL (alias) = 1; | |
289 | DECL_NO_STATIC_CHAIN (alias) = 1; | |
290 | DECL_PENDING_INLINE_P (alias) = 0; | |
291 | DECL_INLINE (alias) = 0; | |
292 | DECL_DECLARED_INLINE_P (alias) = 0; | |
293 | DECL_DEFERRED_FN (alias) = 0; | |
294 | DECL_USE_TEMPLATE (alias) = 0; | |
295 | DECL_TEMPLATE_INSTANTIATED (alias) = 0; | |
296 | DECL_TEMPLATE_INFO (alias) = NULL; | |
297 | DECL_INITIAL (alias) = error_mark_node; | |
298 | TREE_ADDRESSABLE (alias) = 1; | |
299 | TREE_USED (alias) = 1; | |
300 | SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias)); | |
301 | TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1; | |
302 | if (!flag_syntax_only) | |
303 | assemble_alias (alias, DECL_ASSEMBLER_NAME (function)); | |
304 | return alias; | |
305 | } | |
306 | ||
4977bab6 ZW |
307 | /* Emit the definition of a C++ multiple inheritance or covariant |
308 | return vtable thunk. If EMIT_P is nonzero, the thunk is emitted | |
309 | immediately. */ | |
310 | ||
311 | void | |
312 | use_thunk (tree thunk_fndecl, bool emit_p) | |
8926095f | 313 | { |
7a3e01c4 | 314 | tree a, t, function, alias; |
4977bab6 ZW |
315 | tree virtual_offset; |
316 | HOST_WIDE_INT fixed_offset, virtual_value; | |
07fa4878 | 317 | bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl); |
4977bab6 | 318 | |
9bcb9aae | 319 | /* We should have called finish_thunk to give it a name. */ |
4977bab6 | 320 | my_friendly_assert (DECL_NAME (thunk_fndecl), 20021127); |
8926095f | 321 | |
bb885938 NS |
322 | /* We should never be using an alias, always refer to the |
323 | aliased thunk. */ | |
e00853fd | 324 | my_friendly_assert (!THUNK_ALIAS (thunk_fndecl), 20031023); |
bb885938 | 325 | |
8926095f MS |
326 | if (TREE_ASM_WRITTEN (thunk_fndecl)) |
327 | return; | |
31f8e4f3 | 328 | |
07fa4878 NS |
329 | function = THUNK_TARGET (thunk_fndecl); |
330 | if (DECL_RESULT (thunk_fndecl)) | |
6462c441 | 331 | /* We already turned this thunk into an ordinary function. |
dff94ad7 | 332 | There's no need to process this thunk again. */ |
6462c441 MM |
333 | return; |
334 | ||
31f8e4f3 MM |
335 | /* Thunks are always addressable; they only appear in vtables. */ |
336 | TREE_ADDRESSABLE (thunk_fndecl) = 1; | |
a0a33927 | 337 | |
31f8e4f3 MM |
338 | /* Figure out what function is being thunked to. It's referenced in |
339 | this translation unit. */ | |
809c8c30 JM |
340 | TREE_ADDRESSABLE (function) = 1; |
341 | mark_used (function); | |
31f8e4f3 MM |
342 | if (!emit_p) |
343 | return; | |
809c8c30 | 344 | |
4a77e08c DS |
345 | if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)) |
346 | alias = make_alias_for_thunk (function); | |
347 | else | |
348 | alias = function; | |
89ce1c8f | 349 | |
4977bab6 ZW |
350 | fixed_offset = THUNK_FIXED_OFFSET (thunk_fndecl); |
351 | virtual_offset = THUNK_VIRTUAL_OFFSET (thunk_fndecl); | |
3961e8fe | 352 | |
07fa4878 NS |
353 | if (virtual_offset) |
354 | { | |
355 | if (!this_adjusting) | |
356 | virtual_offset = BINFO_VPTR_FIELD (virtual_offset); | |
357 | virtual_value = tree_low_cst (virtual_offset, /*pos=*/0); | |
358 | my_friendly_assert (virtual_value, 20021026); | |
359 | } | |
360 | else | |
361 | virtual_value = 0; | |
4977bab6 | 362 | |
31f8e4f3 MM |
363 | /* And, if we need to emit the thunk, it's used. */ |
364 | mark_used (thunk_fndecl); | |
365 | /* This thunk is actually defined. */ | |
366 | DECL_EXTERNAL (thunk_fndecl) = 0; | |
15eb1e43 JM |
367 | /* The linkage of the function may have changed. FIXME in linkage |
368 | rewrite. */ | |
369 | TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function); | |
968b41a1 | 370 | DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function); |
4746cf84 MA |
371 | if (flag_weak && TREE_PUBLIC (thunk_fndecl)) |
372 | comdat_linkage (thunk_fndecl); | |
a0128b67 | 373 | |
6462c441 MM |
374 | if (flag_syntax_only) |
375 | { | |
376 | TREE_ASM_WRITTEN (thunk_fndecl) = 1; | |
377 | return; | |
378 | } | |
379 | ||
31f8e4f3 MM |
380 | push_to_top_level (); |
381 | ||
4a77e08c DS |
382 | if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function) |
383 | && targetm.have_named_sections) | |
89ce1c8f JJ |
384 | { |
385 | resolve_unique_section (function, 0, flag_function_sections); | |
386 | ||
387 | if (DECL_SECTION_NAME (function) != NULL && DECL_ONE_ONLY (function)) | |
388 | { | |
389 | resolve_unique_section (thunk_fndecl, 0, flag_function_sections); | |
390 | ||
391 | /* Output the thunk into the same section as function. */ | |
392 | DECL_SECTION_NAME (thunk_fndecl) = DECL_SECTION_NAME (function); | |
393 | } | |
394 | } | |
89ce1c8f | 395 | |
14691f8d RH |
396 | /* The back-end expects DECL_INITIAL to contain a BLOCK, so we |
397 | create one. */ | |
398 | DECL_INITIAL (thunk_fndecl) = make_node (BLOCK); | |
7a3e01c4 JDA |
399 | |
400 | /* Set up cloned argument trees for the thunk. */ | |
401 | t = NULL_TREE; | |
402 | for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a)) | |
403 | { | |
404 | tree x = copy_node (a); | |
405 | TREE_CHAIN (x) = t; | |
406 | DECL_CONTEXT (x) = thunk_fndecl; | |
407 | SET_DECL_RTL (x, NULL_RTX); | |
408 | t = x; | |
409 | } | |
410 | a = nreverse (t); | |
411 | DECL_ARGUMENTS (thunk_fndecl) = a; | |
412 | BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) = a; | |
07fa4878 NS |
413 | |
414 | if (this_adjusting | |
4977bab6 | 415 | && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset, |
89ce1c8f | 416 | virtual_value, alias)) |
3b62f224 | 417 | { |
3cce094d | 418 | const char *fnname; |
3b62f224 | 419 | current_function_decl = thunk_fndecl; |
3b62f224 MM |
420 | DECL_RESULT (thunk_fndecl) |
421 | = build_decl (RESULT_DECL, 0, integer_type_node); | |
422 | fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0); | |
ee6b0296 | 423 | init_function_start (thunk_fndecl); |
3b62f224 MM |
424 | current_function_is_thunk = 1; |
425 | assemble_start_function (thunk_fndecl, fnname); | |
eb0424da | 426 | |
4977bab6 | 427 | targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl, |
89ce1c8f | 428 | fixed_offset, virtual_value, alias); |
3961e8fe | 429 | |
3b62f224 | 430 | assemble_end_function (thunk_fndecl, fnname); |
3b62f224 | 431 | current_function_decl = 0; |
01d939e8 | 432 | cfun = 0; |
6462c441 | 433 | TREE_ASM_WRITTEN (thunk_fndecl) = 1; |
3b62f224 | 434 | } |
4e7512c9 | 435 | else |
14691f8d | 436 | { |
4977bab6 ZW |
437 | /* If this is a covariant thunk, or we don't have the necessary |
438 | code for efficient thunks, generate a thunk function that | |
439 | just makes a call to the real function. Unfortunately, this | |
440 | doesn't work for varargs. */ | |
14691f8d | 441 | |
14691f8d RH |
442 | if (varargs_function_p (function)) |
443 | error ("generic thunk code fails for method `%#D' which uses `...'", | |
444 | function); | |
445 | ||
14691f8d RH |
446 | DECL_RESULT (thunk_fndecl) = NULL_TREE; |
447 | ||
058b15c1 | 448 | start_preparsed_function (thunk_fndecl, NULL_TREE, SF_PRE_PARSED); |
14691f8d RH |
449 | /* We don't bother with a body block for thunks. */ |
450 | ||
1bb2cc34 | 451 | /* There's no need to check accessibility inside the thunk body. */ |
78757caa | 452 | push_deferring_access_checks (dk_no_check); |
1bb2cc34 | 453 | |
4977bab6 | 454 | t = a; |
07fa4878 | 455 | if (this_adjusting) |
4977bab6 ZW |
456 | t = thunk_adjust (t, /*this_adjusting=*/1, |
457 | fixed_offset, virtual_offset); | |
458 | ||
14691f8d RH |
459 | /* Build up the call to the real function. */ |
460 | t = tree_cons (NULL_TREE, t, NULL_TREE); | |
461 | for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a)) | |
462 | t = tree_cons (NULL_TREE, a, t); | |
463 | t = nreverse (t); | |
89ce1c8f | 464 | t = build_call (alias, t); |
dd292d0a | 465 | CALL_FROM_THUNK_P (t) = 1; |
4977bab6 | 466 | |
14691f8d RH |
467 | if (VOID_TYPE_P (TREE_TYPE (t))) |
468 | finish_expr_stmt (t); | |
469 | else | |
59445d74 RH |
470 | { |
471 | t = force_target_expr (TREE_TYPE (t), t); | |
472 | if (!this_adjusting) | |
473 | t = thunk_adjust (t, /*this_adjusting=*/0, | |
474 | fixed_offset, virtual_offset); | |
475 | finish_return_stmt (t); | |
476 | } | |
14691f8d RH |
477 | |
478 | /* Since we want to emit the thunk, we explicitly mark its name as | |
479 | referenced. */ | |
bb9a388d | 480 | mark_decl_referenced (thunk_fndecl); |
14691f8d RH |
481 | |
482 | /* But we don't want debugging information about it. */ | |
483 | DECL_IGNORED_P (thunk_fndecl) = 1; | |
484 | ||
1bb2cc34 | 485 | /* Re-enable access control. */ |
78757caa | 486 | pop_deferring_access_checks (); |
1bb2cc34 | 487 | |
ab0ba00c | 488 | expand_body (finish_function (0)); |
14691f8d | 489 | } |
31f8e4f3 MM |
490 | |
491 | pop_from_top_level (); | |
8926095f | 492 | } |
f376e137 MS |
493 | \f |
494 | /* Code for synthesizing methods which have default semantics defined. */ | |
495 | ||
f376e137 | 496 | /* Generate code for default X(X&) constructor. */ |
e92cc029 | 497 | |
824b9a4c | 498 | static void |
4977bab6 | 499 | do_build_copy_constructor (tree fndecl) |
f376e137 | 500 | { |
e0fff4b3 | 501 | tree parm = FUNCTION_FIRST_USER_PARM (fndecl); |
f376e137 MS |
502 | tree t; |
503 | ||
f376e137 MS |
504 | parm = convert_from_reference (parm); |
505 | ||
a59ca936 JM |
506 | if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type) |
507 | && is_empty_class (current_class_type)) | |
508 | /* Don't copy the padding byte; it might not have been allocated | |
509 | if *this is a base subobject. */; | |
510 | else if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)) | |
f376e137 | 511 | { |
4ac14744 | 512 | t = build (INIT_EXPR, void_type_node, current_class_ref, parm); |
f1dedc31 | 513 | finish_expr_stmt (t); |
f376e137 MS |
514 | } |
515 | else | |
516 | { | |
517 | tree fields = TYPE_FIELDS (current_class_type); | |
518 | int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type); | |
519 | tree binfos = TYPE_BINFO_BASETYPES (current_class_type); | |
fd74ca0b | 520 | tree member_init_list = NULL_TREE; |
89d684bb | 521 | int cvquals = cp_type_quals (TREE_TYPE (parm)); |
f376e137 | 522 | int i; |
58c42dc2 | 523 | tree binfo; |
f376e137 | 524 | |
713ccd0c NS |
525 | /* Initialize all the base-classes with the parameter converted |
526 | to their type so that we get their copy constructor and not | |
527 | another constructor that takes current_class_type. We must | |
528 | deal with the binfo's directly as a direct base might be | |
529 | inaccessible due to ambiguity. */ | |
58c42dc2 NS |
530 | for (i = 0; (binfo = VEC_iterate |
531 | (tree, CLASSTYPE_VBASECLASSES (current_class_type), i)); | |
532 | i++) | |
01f9e964 | 533 | { |
2282d28d MM |
534 | member_init_list |
535 | = tree_cons (binfo, | |
536 | build_tree_list (NULL_TREE, | |
537 | build_base_path (PLUS_EXPR, parm, | |
538 | binfo, 1)), | |
539 | member_init_list); | |
01f9e964 JM |
540 | } |
541 | ||
f376e137 MS |
542 | for (i = 0; i < n_bases; ++i) |
543 | { | |
713ccd0c NS |
544 | tree binfo = TREE_VEC_ELT (binfos, i); |
545 | if (TREE_VIA_VIRTUAL (binfo)) | |
8ccc31eb | 546 | continue; |
f376e137 | 547 | |
2282d28d MM |
548 | member_init_list |
549 | = tree_cons (binfo, | |
550 | build_tree_list (NULL_TREE, | |
551 | build_base_path (PLUS_EXPR, parm, | |
552 | binfo, 1)), | |
553 | member_init_list); | |
f376e137 | 554 | } |
1b5f5f76 | 555 | |
f376e137 MS |
556 | for (; fields; fields = TREE_CHAIN (fields)) |
557 | { | |
01f9e964 | 558 | tree init; |
a5894242 | 559 | tree field = fields; |
33dd07ee | 560 | tree expr_type; |
a5894242 MS |
561 | |
562 | if (TREE_CODE (field) != FIELD_DECL) | |
f376e137 | 563 | continue; |
8dff1027 MS |
564 | |
565 | init = parm; | |
a5894242 | 566 | if (DECL_NAME (field)) |
f376e137 | 567 | { |
a5894242 | 568 | if (VFIELD_NAME_P (DECL_NAME (field))) |
f376e137 | 569 | continue; |
f376e137 MS |
570 | |
571 | /* True for duplicate members. */ | |
a5894242 | 572 | if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field) |
f376e137 MS |
573 | continue; |
574 | } | |
a5894242 | 575 | else if ((t = TREE_TYPE (field)) != NULL_TREE |
6bdb8141 | 576 | && ANON_AGGR_TYPE_P (t) |
0171aeab | 577 | && TYPE_FIELDS (t) != NULL_TREE) |
6bdb8141 JM |
578 | /* Just use the field; anonymous types can't have |
579 | nontrivial copy ctors or assignment ops. */; | |
0171aeab JM |
580 | else |
581 | continue; | |
f376e137 | 582 | |
33dd07ee MM |
583 | /* Compute the type of "init->field". If the copy-constructor |
584 | parameter is, for example, "const S&", and the type of | |
585 | the field is "T", then the type will usually be "const | |
586 | T". (There are no cv-qualified variants of reference | |
587 | types.) */ | |
588 | expr_type = TREE_TYPE (field); | |
589 | if (TREE_CODE (expr_type) != REFERENCE_TYPE) | |
590 | expr_type = cp_build_qualified_type (expr_type, cvquals); | |
44de5aeb | 591 | init = build (COMPONENT_REF, expr_type, init, field, NULL_TREE); |
f376e137 MS |
592 | init = build_tree_list (NULL_TREE, init); |
593 | ||
fd74ca0b MM |
594 | member_init_list |
595 | = tree_cons (field, init, member_init_list); | |
f376e137 | 596 | } |
2282d28d | 597 | finish_mem_initializers (member_init_list); |
f376e137 | 598 | } |
f376e137 MS |
599 | } |
600 | ||
824b9a4c | 601 | static void |
4977bab6 | 602 | do_build_assign_ref (tree fndecl) |
f376e137 MS |
603 | { |
604 | tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); | |
f1dedc31 | 605 | tree compound_stmt; |
f376e137 | 606 | |
325c3691 | 607 | compound_stmt = begin_compound_stmt (0); |
f376e137 MS |
608 | parm = convert_from_reference (parm); |
609 | ||
a59ca936 JM |
610 | if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type) |
611 | && is_empty_class (current_class_type)) | |
612 | /* Don't copy the padding byte; it might not have been allocated | |
613 | if *this is a base subobject. */; | |
614 | else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)) | |
f376e137 | 615 | { |
4ac14744 | 616 | tree t = build (MODIFY_EXPR, void_type_node, current_class_ref, parm); |
f1dedc31 | 617 | finish_expr_stmt (t); |
f376e137 MS |
618 | } |
619 | else | |
620 | { | |
4ba126e4 | 621 | tree fields; |
89d684bb | 622 | int cvquals = cp_type_quals (TREE_TYPE (parm)); |
f376e137 MS |
623 | int i; |
624 | ||
22ed7e5f | 625 | /* Assign to each of the direct base classes. */ |
4ba126e4 | 626 | for (i = 0; i < CLASSTYPE_N_BASECLASSES (current_class_type); ++i) |
f376e137 | 627 | { |
4ba126e4 MM |
628 | tree binfo; |
629 | tree converted_parm; | |
630 | ||
631 | binfo = BINFO_BASETYPE (TYPE_BINFO (current_class_type), i); | |
632 | /* We must convert PARM directly to the base class | |
633 | explicitly since the base class may be ambiguous. */ | |
634 | converted_parm = build_base_path (PLUS_EXPR, parm, binfo, 1); | |
635 | /* Call the base class assignment operator. */ | |
636 | finish_expr_stmt | |
637 | (build_special_member_call (current_class_ref, | |
638 | ansi_assopname (NOP_EXPR), | |
639 | build_tree_list (NULL_TREE, | |
640 | converted_parm), | |
641 | binfo, | |
642 | LOOKUP_NORMAL | LOOKUP_NONVIRTUAL)); | |
f376e137 | 643 | } |
4ba126e4 MM |
644 | |
645 | /* Assign to each of the non-static data members. */ | |
646 | for (fields = TYPE_FIELDS (current_class_type); | |
647 | fields; | |
648 | fields = TREE_CHAIN (fields)) | |
f376e137 | 649 | { |
0171aeab | 650 | tree comp, init, t; |
a5894242 MS |
651 | tree field = fields; |
652 | ||
17bbb839 | 653 | if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field)) |
f376e137 | 654 | continue; |
e349ee73 | 655 | |
1b8899d1 | 656 | if (CP_TYPE_CONST_P (TREE_TYPE (field))) |
e349ee73 | 657 | { |
33bd39a2 | 658 | error ("non-static const member `%#D', can't use default assignment operator", field); |
e349ee73 MS |
659 | continue; |
660 | } | |
661 | else if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE) | |
662 | { | |
33bd39a2 | 663 | error ("non-static reference member `%#D', can't use default assignment operator", field); |
e349ee73 MS |
664 | continue; |
665 | } | |
666 | ||
8dff1027 MS |
667 | comp = current_class_ref; |
668 | init = parm; | |
669 | ||
a5894242 | 670 | if (DECL_NAME (field)) |
f376e137 | 671 | { |
a5894242 | 672 | if (VFIELD_NAME_P (DECL_NAME (field))) |
f376e137 | 673 | continue; |
f376e137 MS |
674 | |
675 | /* True for duplicate members. */ | |
a5894242 | 676 | if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field) |
f376e137 MS |
677 | continue; |
678 | } | |
a5894242 | 679 | else if ((t = TREE_TYPE (field)) != NULL_TREE |
6bdb8141 | 680 | && ANON_AGGR_TYPE_P (t) |
0171aeab | 681 | && TYPE_FIELDS (t) != NULL_TREE) |
6bdb8141 JM |
682 | /* Just use the field; anonymous types can't have |
683 | nontrivial copy ctors or assignment ops. */; | |
0171aeab JM |
684 | else |
685 | continue; | |
f376e137 | 686 | |
44de5aeb RK |
687 | comp = build (COMPONENT_REF, TREE_TYPE (field), comp, field, |
688 | NULL_TREE); | |
31b1b957 | 689 | init = build (COMPONENT_REF, |
451c0899 | 690 | cp_build_qualified_type (TREE_TYPE (field), cvquals), |
44de5aeb | 691 | init, field, NULL_TREE); |
f376e137 | 692 | |
a1c2b86d JJ |
693 | if (DECL_NAME (field)) |
694 | finish_expr_stmt (build_modify_expr (comp, NOP_EXPR, init)); | |
695 | else | |
696 | finish_expr_stmt (build (MODIFY_EXPR, TREE_TYPE (comp), comp, | |
697 | init)); | |
f376e137 MS |
698 | } |
699 | } | |
62409b39 | 700 | finish_return_stmt (current_class_ref); |
7a3397c7 | 701 | finish_compound_stmt (compound_stmt); |
f376e137 MS |
702 | } |
703 | ||
704 | void | |
4977bab6 | 705 | synthesize_method (tree fndecl) |
f376e137 | 706 | { |
4977bab6 | 707 | bool nested = (current_function_decl != NULL_TREE); |
4f1c5b7d | 708 | tree context = decl_function_context (fndecl); |
4977bab6 | 709 | bool need_body = true; |
ade3dc07 | 710 | tree stmt; |
db5ae43f | 711 | |
b7067a12 JM |
712 | if (at_eof) |
713 | import_export_decl (fndecl); | |
714 | ||
db9b2174 MM |
715 | /* If we've been asked to synthesize a clone, just synthesize the |
716 | cloned function instead. Doing so will automatically fill in the | |
717 | body for the clone. */ | |
718 | if (DECL_CLONED_FUNCTION_P (fndecl)) | |
719 | { | |
720 | synthesize_method (DECL_CLONED_FUNCTION (fndecl)); | |
721 | return; | |
722 | } | |
723 | ||
afb19ffb KL |
724 | /* We may be in the middle of deferred access check. Disable |
725 | it now. */ | |
726 | push_deferring_access_checks (dk_no_deferred); | |
727 | ||
9a3b49ac MS |
728 | if (! context) |
729 | push_to_top_level (); | |
730 | else if (nested) | |
99dccabc | 731 | push_function_context_to (context); |
db5ae43f | 732 | |
62409b39 MM |
733 | /* Put the function definition at the position where it is needed, |
734 | rather than within the body of the class. That way, an error | |
735 | during the generation of the implicit body points at the place | |
736 | where the attempt to generate the function occurs, giving the | |
737 | user a hint as to why we are attempting to generate the | |
c6002625 | 738 | function. */ |
f31686a3 | 739 | DECL_SOURCE_LOCATION (fndecl) = input_location; |
62409b39 | 740 | |
e76a2646 | 741 | interface_unknown = 1; |
058b15c1 | 742 | start_preparsed_function (fndecl, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED); |
ade3dc07 | 743 | stmt = begin_function_body (); |
db5ae43f | 744 | |
596ea4e5 | 745 | if (DECL_OVERLOADED_OPERATOR_P (fndecl) == NOP_EXPR) |
62409b39 MM |
746 | { |
747 | do_build_assign_ref (fndecl); | |
4977bab6 | 748 | need_body = false; |
62409b39 | 749 | } |
cdd2559c | 750 | else if (DECL_CONSTRUCTOR_P (fndecl)) |
db5ae43f | 751 | { |
e0fff4b3 | 752 | tree arg_chain = FUNCTION_FIRST_USER_PARMTYPE (fndecl); |
db5ae43f MS |
753 | if (arg_chain != void_list_node) |
754 | do_build_copy_constructor (fndecl); | |
755 | else if (TYPE_NEEDS_CONSTRUCTING (current_class_type)) | |
cdd2559c | 756 | finish_mem_initializers (NULL_TREE); |
62409b39 | 757 | } |
f18a14bc | 758 | |
62409b39 MM |
759 | /* If we haven't yet generated the body of the function, just |
760 | generate an empty compound statement. */ | |
761 | if (need_body) | |
762 | { | |
763 | tree compound_stmt; | |
325c3691 | 764 | compound_stmt = begin_compound_stmt (BCS_FN_BODY); |
7a3397c7 | 765 | finish_compound_stmt (compound_stmt); |
db5ae43f MS |
766 | } |
767 | ||
ade3dc07 | 768 | finish_function_body (stmt); |
8cd2462c | 769 | expand_or_defer_fn (finish_function (0)); |
28cbf42c | 770 | |
db5ae43f | 771 | extract_interface_info (); |
9a3b49ac MS |
772 | if (! context) |
773 | pop_from_top_level (); | |
774 | else if (nested) | |
99dccabc | 775 | pop_function_context_from (context); |
afb19ffb KL |
776 | |
777 | pop_deferring_access_checks (); | |
f376e137 | 778 | } |
9eb71d8c | 779 | |
03378143 NS |
780 | /* Use EXTRACTOR to locate the relevant function called for each base & |
781 | class field of TYPE. CLIENT allows additional information to be passed | |
f62ea157 JM |
782 | to EXTRACTOR. Generates the union of all exceptions generated by those |
783 | functions. Note that we haven't updated TYPE_FIELDS and such of any | |
784 | variants yet, so we need to look at the main one. */ | |
03378143 NS |
785 | |
786 | static tree | |
4977bab6 ZW |
787 | synthesize_exception_spec (tree type, tree (*extractor) (tree, void*), |
788 | void *client) | |
03378143 NS |
789 | { |
790 | tree raises = empty_except_spec; | |
791 | tree fields = TYPE_FIELDS (type); | |
792 | int i, n_bases = CLASSTYPE_N_BASECLASSES (type); | |
793 | tree binfos = TYPE_BINFO_BASETYPES (type); | |
f62ea157 | 794 | |
03378143 NS |
795 | for (i = 0; i != n_bases; i++) |
796 | { | |
797 | tree base = BINFO_TYPE (TREE_VEC_ELT (binfos, i)); | |
798 | tree fn = (*extractor) (base, client); | |
799 | if (fn) | |
800 | { | |
801 | tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); | |
802 | ||
803 | raises = merge_exception_specifiers (raises, fn_raises); | |
804 | } | |
805 | } | |
806 | for (; fields; fields = TREE_CHAIN (fields)) | |
807 | { | |
808 | tree type = TREE_TYPE (fields); | |
809 | tree fn; | |
810 | ||
17bbb839 | 811 | if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields)) |
03378143 NS |
812 | continue; |
813 | while (TREE_CODE (type) == ARRAY_TYPE) | |
814 | type = TREE_TYPE (type); | |
815 | if (TREE_CODE (type) != RECORD_TYPE) | |
816 | continue; | |
817 | ||
818 | fn = (*extractor) (type, client); | |
819 | if (fn) | |
820 | { | |
821 | tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); | |
822 | ||
823 | raises = merge_exception_specifiers (raises, fn_raises); | |
824 | } | |
825 | } | |
826 | return raises; | |
827 | } | |
828 | ||
829 | /* Locate the dtor of TYPE. */ | |
830 | ||
831 | static tree | |
4977bab6 | 832 | locate_dtor (tree type, void *client ATTRIBUTE_UNUSED) |
03378143 NS |
833 | { |
834 | tree fns; | |
835 | ||
836 | if (!TYPE_HAS_DESTRUCTOR (type)) | |
837 | return NULL_TREE; | |
838 | fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), | |
839 | CLASSTYPE_DESTRUCTOR_SLOT); | |
840 | return fns; | |
841 | } | |
842 | ||
843 | /* Locate the default ctor of TYPE. */ | |
844 | ||
845 | static tree | |
4977bab6 | 846 | locate_ctor (tree type, void *client ATTRIBUTE_UNUSED) |
03378143 NS |
847 | { |
848 | tree fns; | |
849 | ||
850 | if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type)) | |
851 | return NULL_TREE; | |
852 | ||
853 | fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), | |
854 | CLASSTYPE_CONSTRUCTOR_SLOT); | |
855 | for (; fns; fns = OVL_NEXT (fns)) | |
856 | { | |
857 | tree fn = OVL_CURRENT (fns); | |
858 | tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn)); | |
859 | ||
860 | if (sufficient_parms_p (TREE_CHAIN (parms))) | |
861 | return fn; | |
862 | } | |
863 | return NULL_TREE; | |
864 | } | |
865 | ||
866 | struct copy_data | |
867 | { | |
868 | tree name; | |
869 | int quals; | |
870 | }; | |
871 | ||
872 | /* Locate the copy ctor or copy assignment of TYPE. CLIENT_ | |
873 | points to a COPY_DATA holding the name (NULL for the ctor) | |
874 | and desired qualifiers of the source operand. */ | |
875 | ||
876 | static tree | |
4977bab6 | 877 | locate_copy (tree type, void *client_) |
03378143 NS |
878 | { |
879 | struct copy_data *client = (struct copy_data *)client_; | |
880 | tree fns; | |
881 | int ix = -1; | |
882 | tree best = NULL_TREE; | |
4977bab6 | 883 | bool excess_p = false; |
03378143 NS |
884 | |
885 | if (client->name) | |
886 | { | |
887 | if (TYPE_HAS_ASSIGN_REF (type)) | |
888 | ix = lookup_fnfields_1 (type, client->name); | |
889 | } | |
890 | else if (TYPE_HAS_INIT_REF (type)) | |
891 | ix = CLASSTYPE_CONSTRUCTOR_SLOT; | |
892 | if (ix < 0) | |
893 | return NULL_TREE; | |
894 | fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), ix); | |
895 | ||
896 | for (; fns; fns = OVL_NEXT (fns)) | |
897 | { | |
898 | tree fn = OVL_CURRENT (fns); | |
899 | tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn)); | |
900 | tree src_type; | |
901 | int excess; | |
902 | int quals; | |
903 | ||
904 | parms = TREE_CHAIN (parms); | |
905 | if (!parms) | |
906 | continue; | |
ee76b931 | 907 | src_type = non_reference (TREE_VALUE (parms)); |
03378143 NS |
908 | if (!same_type_ignoring_top_level_qualifiers_p (src_type, type)) |
909 | continue; | |
910 | if (!sufficient_parms_p (TREE_CHAIN (parms))) | |
911 | continue; | |
89d684bb | 912 | quals = cp_type_quals (src_type); |
03378143 NS |
913 | if (client->quals & ~quals) |
914 | continue; | |
915 | excess = quals & ~client->quals; | |
916 | if (!best || (excess_p && !excess)) | |
917 | { | |
918 | best = fn; | |
919 | excess_p = excess; | |
920 | } | |
921 | else | |
922 | /* Ambiguous */ | |
923 | return NULL_TREE; | |
924 | } | |
925 | return best; | |
926 | } | |
927 | ||
9eb71d8c MM |
928 | /* Implicitly declare the special function indicated by KIND, as a |
929 | member of TYPE. For copy constructors and assignment operators, | |
930 | CONST_P indicates whether these functions should take a const | |
931 | reference argument or a non-const reference. */ | |
932 | ||
933 | tree | |
4977bab6 | 934 | implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) |
9eb71d8c | 935 | { |
058b15c1 MM |
936 | tree fn; |
937 | tree parameter_types = void_list_node; | |
938 | tree return_type = void_type_node; | |
939 | tree fn_type; | |
03378143 | 940 | tree raises = empty_except_spec; |
058b15c1 MM |
941 | tree rhs_parm_type = NULL_TREE; |
942 | tree name; | |
9eb71d8c MM |
943 | |
944 | switch (kind) | |
945 | { | |
9eb71d8c | 946 | case sfk_destructor: |
03378143 | 947 | /* Destructor. */ |
058b15c1 | 948 | name = constructor_name (type); |
03378143 | 949 | raises = synthesize_exception_spec (type, &locate_dtor, 0); |
9eb71d8c MM |
950 | break; |
951 | ||
952 | case sfk_constructor: | |
953 | /* Default constructor. */ | |
058b15c1 | 954 | name = constructor_name (type); |
03378143 | 955 | raises = synthesize_exception_spec (type, &locate_ctor, 0); |
058b15c1 | 956 | TYPE_HAS_CONSTRUCTOR (type) = 1; |
9eb71d8c MM |
957 | break; |
958 | ||
959 | case sfk_copy_constructor: | |
058b15c1 MM |
960 | TYPE_HAS_CONSTRUCTOR (type) = 1; |
961 | /* Fall through. */ | |
9eb71d8c | 962 | case sfk_assignment_operator: |
03378143 NS |
963 | { |
964 | struct copy_data data; | |
965 | ||
a2095778 NS |
966 | data.name = NULL; |
967 | data.quals = 0; | |
968 | if (kind == sfk_assignment_operator) | |
969 | { | |
058b15c1 | 970 | return_type = build_reference_type (type); |
a2095778 NS |
971 | name = ansi_assopname (NOP_EXPR); |
972 | data.name = name; | |
973 | } | |
058b15c1 MM |
974 | else |
975 | name = constructor_name (type); | |
976 | ||
9eb71d8c | 977 | if (const_p) |
a2095778 NS |
978 | { |
979 | data.quals = TYPE_QUAL_CONST; | |
058b15c1 | 980 | rhs_parm_type = build_qualified_type (type, TYPE_QUAL_CONST); |
a2095778 | 981 | } |
058b15c1 MM |
982 | else |
983 | rhs_parm_type = type; | |
984 | rhs_parm_type = build_reference_type (rhs_parm_type); | |
985 | parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types); | |
03378143 | 986 | raises = synthesize_exception_spec (type, &locate_copy, &data); |
9eb71d8c | 987 | break; |
03378143 | 988 | } |
9eb71d8c | 989 | default: |
a98facb0 | 990 | abort (); |
9eb71d8c MM |
991 | } |
992 | ||
058b15c1 MM |
993 | /* Create the function. */ |
994 | fn_type = build_method_type_directly (type, return_type, parameter_types); | |
995 | if (raises) | |
996 | fn_type = build_exception_variant (fn_type, raises); | |
997 | fn = build_lang_decl (FUNCTION_DECL, name, fn_type); | |
998 | if (kind == sfk_constructor || kind == sfk_copy_constructor) | |
999 | DECL_CONSTRUCTOR_P (fn) = 1; | |
1000 | else if (kind == sfk_destructor) | |
1001 | DECL_DESTRUCTOR_P (fn) = 1; | |
1002 | else | |
1003 | { | |
1004 | DECL_ASSIGNMENT_OPERATOR_P (fn) = 1; | |
1005 | SET_OVERLOADED_OPERATOR_CODE (fn, NOP_EXPR); | |
1006 | } | |
1007 | /* Create the argument list. The call to "grokclassfn" will add the | |
1008 | "this" parameter and any other implicit parameters. */ | |
1009 | if (rhs_parm_type) | |
1010 | { | |
1011 | /* Note that this parameter is *not* marked DECL_ARTIFICIAL; we | |
1012 | want its type to be included in the mangled function | |
1013 | name. */ | |
1014 | DECL_ARGUMENTS (fn) = cp_build_parm_decl (NULL_TREE, rhs_parm_type); | |
1015 | TREE_READONLY (DECL_ARGUMENTS (fn)) = 1; | |
1016 | } | |
9eb71d8c | 1017 | |
058b15c1 | 1018 | grokclassfn (type, fn, kind == sfk_destructor ? DTOR_FLAG : NO_SPECIAL, |
3c01e5df | 1019 | TYPE_UNQUALIFIED); |
058b15c1 MM |
1020 | grok_special_member_properties (fn); |
1021 | cp_finish_decl (fn, /*init=*/NULL_TREE, /*asmspec_tree=*/NULL_TREE, | |
1022 | /*flags=*/LOOKUP_ONLYCONVERTING); | |
1023 | DECL_IN_AGGR_P (fn) = 1; | |
c727aa5e | 1024 | DECL_ARTIFICIAL (fn) = 1; |
9eb71d8c | 1025 | DECL_NOT_REALLY_EXTERN (fn) = 1; |
79065db2 | 1026 | DECL_DECLARED_INLINE_P (fn) = 1; |
9eb71d8c | 1027 | DECL_INLINE (fn) = 1; |
bf277438 GK |
1028 | if (TREE_USED (fn)) |
1029 | abort (); | |
9eb71d8c MM |
1030 | |
1031 | return fn; | |
1032 | } | |
e0fff4b3 JM |
1033 | |
1034 | /* Given a FUNCTION_DECL FN and a chain LIST, skip as many elements of LIST | |
1035 | as there are artificial parms in FN. */ | |
1036 | ||
1037 | tree | |
4977bab6 | 1038 | skip_artificial_parms_for (tree fn, tree list) |
e0fff4b3 JM |
1039 | { |
1040 | if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) | |
1041 | list = TREE_CHAIN (list); | |
1042 | else | |
1043 | return list; | |
1044 | ||
1045 | if (DECL_HAS_IN_CHARGE_PARM_P (fn)) | |
1046 | list = TREE_CHAIN (list); | |
1047 | if (DECL_HAS_VTT_PARM_P (fn)) | |
1048 | list = TREE_CHAIN (list); | |
1049 | return list; | |
1050 | } | |
89ce1c8f JJ |
1051 | |
1052 | #include "gt-cp-method.h" |