]>
Commit | Line | Data |
---|---|---|
8d08fdba MS |
1 | /* Handle the hair of processing (but not expanding) inline functions. |
2 | Also manage function and variable name overloading. | |
c8094d83 | 3 | Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, |
c166b898 | 4 | 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009 |
e77f031d | 5 | Free Software Foundation, Inc. |
8d08fdba MS |
6 | Contributed by Michael Tiemann (tiemann@cygnus.com) |
7 | ||
f5adbb8d | 8 | This file is part of GCC. |
c8094d83 | 9 | |
f5adbb8d | 10 | GCC is free software; you can redistribute it and/or modify |
8d08fdba | 11 | it under the terms of the GNU General Public License as published by |
e77f031d | 12 | the Free Software Foundation; either version 3, or (at your option) |
8d08fdba MS |
13 | any later version. |
14 | ||
f5adbb8d | 15 | GCC is distributed in the hope that it will be useful, |
8d08fdba MS |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | GNU General Public License for more details. | |
19 | ||
20 | You should have received a copy of the GNU General Public License | |
e77f031d NC |
21 | along with GCC; see the file COPYING3. If not see |
22 | <http://www.gnu.org/licenses/>. */ | |
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" |
e21aff8a | 39 | #include "tree-pass.h" |
3e3935a9 | 40 | #include "diagnostic.h" |
ff2c88a5 | 41 | #include "cgraph.h" |
8d08fdba | 42 | |
669ec2b4 JM |
43 | /* Various flags to control the mangling process. */ |
44 | ||
45 | enum mangling_flags | |
46 | { | |
47 | /* No flags. */ | |
48 | mf_none = 0, | |
49 | /* The thing we are presently mangling is part of a template type, | |
50 | rather than a fully instantiated type. Therefore, we may see | |
51 | complex expressions where we would normally expect to see a | |
52 | simple integer constant. */ | |
53 | mf_maybe_uninstantiated = 1, | |
54 | /* When mangling a numeric value, use the form `_XX_' (instead of | |
55 | just `XX') if the value has more than one digit. */ | |
de94b46c | 56 | mf_use_underscores_around_value = 2 |
669ec2b4 JM |
57 | }; |
58 | ||
59 | typedef enum mangling_flags mangling_flags; | |
60 | ||
4977bab6 ZW |
61 | static tree thunk_adjust (tree, bool, HOST_WIDE_INT, tree); |
62 | static void do_build_assign_ref (tree); | |
63 | static void do_build_copy_constructor (tree); | |
64 | static tree synthesize_exception_spec (tree, tree (*) (tree, void *), 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 | 89 | tree thunk; |
c8094d83 | 90 | |
50bc768d | 91 | gcc_assert (TREE_CODE (function) == FUNCTION_DECL); |
9bcb9aae | 92 | /* We can have this thunks to covariant thunks, but not vice versa. */ |
50bc768d NS |
93 | gcc_assert (!DECL_THIS_THUNK_P (function)); |
94 | gcc_assert (!DECL_RESULT_THUNK_P (function) || this_adjusting); | |
c8094d83 | 95 | |
4977bab6 ZW |
96 | /* Scale the VIRTUAL_OFFSET to be in terms of bytes. */ |
97 | if (this_adjusting && virtual_offset) | |
c8094d83 | 98 | virtual_offset |
31f8e4f3 | 99 | = size_binop (MULT_EXPR, |
0cbd7506 MS |
100 | virtual_offset, |
101 | convert (ssizetype, | |
102 | TYPE_SIZE_UNIT (vtable_entry_type))); | |
c8094d83 | 103 | |
4977bab6 | 104 | d = tree_low_cst (fixed_offset, 0); |
c8094d83 | 105 | |
4977bab6 ZW |
106 | /* See if we already have the thunk in question. For this_adjusting |
107 | thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it | |
9bcb9aae | 108 | will be a BINFO. */ |
bb5e8a7f | 109 | for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk)) |
e00853fd NS |
110 | if (DECL_THIS_THUNK_P (thunk) == this_adjusting |
111 | && THUNK_FIXED_OFFSET (thunk) == d | |
112 | && !virtual_offset == !THUNK_VIRTUAL_OFFSET (thunk) | |
113 | && (!virtual_offset | |
114 | || (this_adjusting | |
115 | ? tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk), | |
116 | virtual_offset) | |
117 | : THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset))) | |
118 | return thunk; | |
c8094d83 | 119 | |
bb5e8a7f MM |
120 | /* All thunks must be created before FUNCTION is actually emitted; |
121 | the ABI requires that all thunks be emitted together with the | |
122 | function to which they transfer control. */ | |
50bc768d | 123 | gcc_assert (!TREE_ASM_WRITTEN (function)); |
90d46c28 NS |
124 | /* Likewise, we can only be adding thunks to a function declared in |
125 | the class currently being laid out. */ | |
50bc768d NS |
126 | gcc_assert (TYPE_SIZE (DECL_CONTEXT (function)) |
127 | && TYPE_BEING_DEFINED (DECL_CONTEXT (function))); | |
bb5e8a7f | 128 | |
c2255bc4 AH |
129 | thunk = build_decl (DECL_SOURCE_LOCATION (function), |
130 | FUNCTION_DECL, NULL_TREE, TREE_TYPE (function)); | |
bb5e8a7f | 131 | DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function); |
07fa4878 | 132 | cxx_dup_lang_specific_decl (thunk); |
bb885938 | 133 | DECL_THUNKS (thunk) = NULL_TREE; |
c8094d83 | 134 | |
bb5e8a7f MM |
135 | DECL_CONTEXT (thunk) = DECL_CONTEXT (function); |
136 | TREE_READONLY (thunk) = TREE_READONLY (function); | |
137 | TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function); | |
138 | TREE_PUBLIC (thunk) = TREE_PUBLIC (function); | |
4977bab6 | 139 | SET_DECL_THUNK_P (thunk, this_adjusting); |
07fa4878 NS |
140 | THUNK_TARGET (thunk) = function; |
141 | THUNK_FIXED_OFFSET (thunk) = d; | |
4977bab6 | 142 | THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset; |
e00853fd | 143 | THUNK_ALIAS (thunk) = NULL_TREE; |
c8094d83 | 144 | |
bb5e8a7f MM |
145 | /* The thunk itself is not a constructor or destructor, even if |
146 | the thing it is thunking to is. */ | |
147 | DECL_INTERFACE_KNOWN (thunk) = 1; | |
148 | DECL_NOT_REALLY_EXTERN (thunk) = 1; | |
149 | DECL_SAVED_FUNCTION_DATA (thunk) = NULL; | |
150 | DECL_DESTRUCTOR_P (thunk) = 0; | |
151 | DECL_CONSTRUCTOR_P (thunk) = 0; | |
bb5e8a7f MM |
152 | DECL_EXTERNAL (thunk) = 1; |
153 | DECL_ARTIFICIAL (thunk) = 1; | |
bb5e8a7f MM |
154 | /* The THUNK is not a pending inline, even if the FUNCTION is. */ |
155 | DECL_PENDING_INLINE_P (thunk) = 0; | |
eab5474f | 156 | DECL_DECLARED_INLINE_P (thunk) = 0; |
cf5131b4 JM |
157 | /* Nor is it a template instantiation. */ |
158 | DECL_USE_TEMPLATE (thunk) = 0; | |
159 | DECL_TEMPLATE_INFO (thunk) = NULL; | |
c8094d83 | 160 | |
bb5e8a7f MM |
161 | /* Add it to the list of thunks associated with FUNCTION. */ |
162 | TREE_CHAIN (thunk) = DECL_THUNKS (function); | |
163 | DECL_THUNKS (function) = thunk; | |
cc600f33 | 164 | |
8926095f MS |
165 | return thunk; |
166 | } | |
167 | ||
07fa4878 | 168 | /* Finish THUNK, a thunk decl. */ |
eb448459 | 169 | |
8926095f | 170 | void |
07fa4878 | 171 | finish_thunk (tree thunk) |
4977bab6 ZW |
172 | { |
173 | tree function, name; | |
ce552f75 | 174 | tree fixed_offset = ssize_int (THUNK_FIXED_OFFSET (thunk)); |
07fa4878 NS |
175 | tree virtual_offset = THUNK_VIRTUAL_OFFSET (thunk); |
176 | ||
50bc768d | 177 | gcc_assert (!DECL_NAME (thunk) && DECL_THUNK_P (thunk)); |
07fa4878 NS |
178 | if (virtual_offset && DECL_RESULT_THUNK_P (thunk)) |
179 | virtual_offset = BINFO_VPTR_FIELD (virtual_offset); | |
180 | function = THUNK_TARGET (thunk); | |
4977bab6 | 181 | name = mangle_thunk (function, DECL_THIS_THUNK_P (thunk), |
07fa4878 | 182 | fixed_offset, virtual_offset); |
bb885938 NS |
183 | |
184 | /* We can end up with declarations of (logically) different | |
185 | covariant thunks, that do identical adjustments. The two thunks | |
186 | will be adjusting between within different hierarchies, which | |
187 | happen to have the same layout. We must nullify one of them to | |
188 | refer to the other. */ | |
189 | if (DECL_RESULT_THUNK_P (thunk)) | |
190 | { | |
191 | tree cov_probe; | |
192 | ||
193 | for (cov_probe = DECL_THUNKS (function); | |
194 | cov_probe; cov_probe = TREE_CHAIN (cov_probe)) | |
195 | if (DECL_NAME (cov_probe) == name) | |
196 | { | |
50bc768d | 197 | gcc_assert (!DECL_THUNKS (thunk)); |
e00853fd | 198 | THUNK_ALIAS (thunk) = (THUNK_ALIAS (cov_probe) |
bb885938 NS |
199 | ? THUNK_ALIAS (cov_probe) : cov_probe); |
200 | break; | |
201 | } | |
202 | } | |
c8094d83 | 203 | |
4977bab6 ZW |
204 | DECL_NAME (thunk) = name; |
205 | SET_DECL_ASSEMBLER_NAME (thunk, name); | |
206 | } | |
207 | ||
208 | /* Adjust PTR by the constant FIXED_OFFSET, and by the vtable | |
209 | offset indicated by VIRTUAL_OFFSET, if that is | |
4de8668e | 210 | non-null. THIS_ADJUSTING is nonzero for a this adjusting thunk and |
9bcb9aae | 211 | zero for a result adjusting thunk. */ |
4977bab6 ZW |
212 | |
213 | static tree | |
214 | thunk_adjust (tree ptr, bool this_adjusting, | |
215 | HOST_WIDE_INT fixed_offset, tree virtual_offset) | |
216 | { | |
217 | if (this_adjusting) | |
218 | /* Adjust the pointer by the constant. */ | |
db3927fb AH |
219 | ptr = fold_build2_loc (input_location, |
220 | POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr, | |
5be014d5 | 221 | size_int (fixed_offset)); |
4977bab6 ZW |
222 | |
223 | /* If there's a virtual offset, look up that value in the vtable and | |
224 | adjust the pointer again. */ | |
225 | if (virtual_offset) | |
226 | { | |
227 | tree vtable; | |
228 | ||
4977bab6 ZW |
229 | ptr = save_expr (ptr); |
230 | /* The vptr is always at offset zero in the object. */ | |
231 | vtable = build1 (NOP_EXPR, | |
c8094d83 | 232 | build_pointer_type (build_pointer_type |
4977bab6 ZW |
233 | (vtable_entry_type)), |
234 | ptr); | |
235 | /* Form the vtable address. */ | |
236 | vtable = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (vtable)), vtable); | |
237 | /* Find the entry with the vcall offset. */ | |
db3927fb AH |
238 | vtable = fold_build2_loc (input_location, |
239 | POINTER_PLUS_EXPR, TREE_TYPE (vtable), vtable, | |
240 | fold_convert (sizetype, virtual_offset)); | |
4977bab6 ZW |
241 | /* Get the offset itself. */ |
242 | vtable = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (vtable)), vtable); | |
243 | /* Adjust the `this' pointer. */ | |
db3927fb AH |
244 | ptr = fold_build2_loc (input_location, |
245 | POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr, | |
5be014d5 | 246 | fold_convert (sizetype, vtable)); |
4977bab6 | 247 | } |
c8094d83 | 248 | |
4977bab6 ZW |
249 | if (!this_adjusting) |
250 | /* Adjust the pointer by the constant. */ | |
db3927fb AH |
251 | ptr = fold_build2_loc (input_location, |
252 | POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr, | |
5be014d5 | 253 | size_int (fixed_offset)); |
4977bab6 ZW |
254 | |
255 | return ptr; | |
256 | } | |
257 | ||
89ce1c8f JJ |
258 | static GTY (()) int thunk_labelno; |
259 | ||
260 | /* Create a static alias to function. */ | |
261 | ||
6de33afa RH |
262 | tree |
263 | make_alias_for (tree function, tree newid) | |
89ce1c8f | 264 | { |
c2255bc4 AH |
265 | tree alias = build_decl (DECL_SOURCE_LOCATION (function), |
266 | FUNCTION_DECL, newid, TREE_TYPE (function)); | |
89ce1c8f JJ |
267 | DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function); |
268 | cxx_dup_lang_specific_decl (alias); | |
269 | DECL_CONTEXT (alias) = NULL; | |
270 | TREE_READONLY (alias) = TREE_READONLY (function); | |
271 | TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function); | |
272 | TREE_PUBLIC (alias) = 0; | |
273 | DECL_INTERFACE_KNOWN (alias) = 1; | |
274 | DECL_NOT_REALLY_EXTERN (alias) = 1; | |
275 | DECL_THIS_STATIC (alias) = 1; | |
276 | DECL_SAVED_FUNCTION_DATA (alias) = NULL; | |
277 | DECL_DESTRUCTOR_P (alias) = 0; | |
278 | DECL_CONSTRUCTOR_P (alias) = 0; | |
89ce1c8f JJ |
279 | DECL_EXTERNAL (alias) = 0; |
280 | DECL_ARTIFICIAL (alias) = 1; | |
89ce1c8f | 281 | DECL_PENDING_INLINE_P (alias) = 0; |
89ce1c8f | 282 | DECL_DECLARED_INLINE_P (alias) = 0; |
89ce1c8f JJ |
283 | DECL_USE_TEMPLATE (alias) = 0; |
284 | DECL_TEMPLATE_INSTANTIATED (alias) = 0; | |
285 | DECL_TEMPLATE_INFO (alias) = NULL; | |
286 | DECL_INITIAL (alias) = error_mark_node; | |
287 | TREE_ADDRESSABLE (alias) = 1; | |
288 | TREE_USED (alias) = 1; | |
289 | SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias)); | |
290 | TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1; | |
6de33afa RH |
291 | return alias; |
292 | } | |
293 | ||
294 | static tree | |
295 | make_alias_for_thunk (tree function) | |
296 | { | |
297 | tree alias; | |
298 | char buf[256]; | |
299 | ||
300 | ASM_GENERATE_INTERNAL_LABEL (buf, "LTHUNK", thunk_labelno); | |
301 | thunk_labelno++; | |
302 | ||
303 | alias = make_alias_for (function, get_identifier (buf)); | |
304 | ||
89ce1c8f JJ |
305 | if (!flag_syntax_only) |
306 | assemble_alias (alias, DECL_ASSEMBLER_NAME (function)); | |
6de33afa | 307 | |
89ce1c8f JJ |
308 | return alias; |
309 | } | |
310 | ||
4977bab6 ZW |
311 | /* Emit the definition of a C++ multiple inheritance or covariant |
312 | return vtable thunk. If EMIT_P is nonzero, the thunk is emitted | |
313 | immediately. */ | |
314 | ||
315 | void | |
316 | use_thunk (tree thunk_fndecl, bool emit_p) | |
8926095f | 317 | { |
7a3e01c4 | 318 | tree a, t, function, alias; |
4977bab6 ZW |
319 | tree virtual_offset; |
320 | HOST_WIDE_INT fixed_offset, virtual_value; | |
07fa4878 | 321 | bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl); |
4977bab6 | 322 | |
9bcb9aae | 323 | /* We should have called finish_thunk to give it a name. */ |
50bc768d | 324 | gcc_assert (DECL_NAME (thunk_fndecl)); |
8926095f | 325 | |
bb885938 NS |
326 | /* We should never be using an alias, always refer to the |
327 | aliased thunk. */ | |
50bc768d | 328 | gcc_assert (!THUNK_ALIAS (thunk_fndecl)); |
bb885938 | 329 | |
8926095f MS |
330 | if (TREE_ASM_WRITTEN (thunk_fndecl)) |
331 | return; | |
c8094d83 | 332 | |
07fa4878 NS |
333 | function = THUNK_TARGET (thunk_fndecl); |
334 | if (DECL_RESULT (thunk_fndecl)) | |
6462c441 | 335 | /* We already turned this thunk into an ordinary function. |
dff94ad7 | 336 | There's no need to process this thunk again. */ |
6462c441 MM |
337 | return; |
338 | ||
742f25b3 NS |
339 | if (DECL_THUNK_P (function)) |
340 | /* The target is itself a thunk, process it now. */ | |
341 | use_thunk (function, emit_p); | |
c8094d83 | 342 | |
31f8e4f3 MM |
343 | /* Thunks are always addressable; they only appear in vtables. */ |
344 | TREE_ADDRESSABLE (thunk_fndecl) = 1; | |
a0a33927 | 345 | |
31f8e4f3 MM |
346 | /* Figure out what function is being thunked to. It's referenced in |
347 | this translation unit. */ | |
809c8c30 JM |
348 | TREE_ADDRESSABLE (function) = 1; |
349 | mark_used (function); | |
31f8e4f3 MM |
350 | if (!emit_p) |
351 | return; | |
809c8c30 | 352 | |
4a77e08c DS |
353 | if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)) |
354 | alias = make_alias_for_thunk (function); | |
355 | else | |
356 | alias = function; | |
89ce1c8f | 357 | |
4977bab6 ZW |
358 | fixed_offset = THUNK_FIXED_OFFSET (thunk_fndecl); |
359 | virtual_offset = THUNK_VIRTUAL_OFFSET (thunk_fndecl); | |
3961e8fe | 360 | |
07fa4878 NS |
361 | if (virtual_offset) |
362 | { | |
363 | if (!this_adjusting) | |
364 | virtual_offset = BINFO_VPTR_FIELD (virtual_offset); | |
365 | virtual_value = tree_low_cst (virtual_offset, /*pos=*/0); | |
50bc768d | 366 | gcc_assert (virtual_value); |
07fa4878 NS |
367 | } |
368 | else | |
369 | virtual_value = 0; | |
c8094d83 | 370 | |
31f8e4f3 MM |
371 | /* And, if we need to emit the thunk, it's used. */ |
372 | mark_used (thunk_fndecl); | |
373 | /* This thunk is actually defined. */ | |
374 | DECL_EXTERNAL (thunk_fndecl) = 0; | |
15eb1e43 JM |
375 | /* The linkage of the function may have changed. FIXME in linkage |
376 | rewrite. */ | |
377 | TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function); | |
968b41a1 | 378 | DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function); |
c8094d83 | 379 | DECL_VISIBILITY_SPECIFIED (thunk_fndecl) |
73a8adb6 | 380 | = DECL_VISIBILITY_SPECIFIED (function); |
bf2f234e | 381 | if (DECL_ONE_ONLY (function)) |
fc26fae3 | 382 | make_decl_one_only (thunk_fndecl, cxx_comdat_group (thunk_fndecl)); |
a0128b67 | 383 | |
6462c441 MM |
384 | if (flag_syntax_only) |
385 | { | |
386 | TREE_ASM_WRITTEN (thunk_fndecl) = 1; | |
387 | return; | |
388 | } | |
389 | ||
31f8e4f3 MM |
390 | push_to_top_level (); |
391 | ||
4a77e08c DS |
392 | if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function) |
393 | && targetm.have_named_sections) | |
89ce1c8f JJ |
394 | { |
395 | resolve_unique_section (function, 0, flag_function_sections); | |
396 | ||
397 | if (DECL_SECTION_NAME (function) != NULL && DECL_ONE_ONLY (function)) | |
398 | { | |
399 | resolve_unique_section (thunk_fndecl, 0, flag_function_sections); | |
400 | ||
401 | /* Output the thunk into the same section as function. */ | |
402 | DECL_SECTION_NAME (thunk_fndecl) = DECL_SECTION_NAME (function); | |
403 | } | |
404 | } | |
89ce1c8f | 405 | |
7a3e01c4 JDA |
406 | /* Set up cloned argument trees for the thunk. */ |
407 | t = NULL_TREE; | |
408 | for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a)) | |
409 | { | |
410 | tree x = copy_node (a); | |
411 | TREE_CHAIN (x) = t; | |
412 | DECL_CONTEXT (x) = thunk_fndecl; | |
413 | SET_DECL_RTL (x, NULL_RTX); | |
dbb87a8a | 414 | DECL_HAS_VALUE_EXPR_P (x) = 0; |
7a3e01c4 JDA |
415 | t = x; |
416 | } | |
417 | a = nreverse (t); | |
418 | DECL_ARGUMENTS (thunk_fndecl) = a; | |
c8094d83 | 419 | |
07fa4878 | 420 | if (this_adjusting |
4977bab6 | 421 | && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset, |
89ce1c8f | 422 | virtual_value, alias)) |
3b62f224 | 423 | { |
3cce094d | 424 | const char *fnname; |
72c4a4ca GK |
425 | tree fn_block; |
426 | ||
3b62f224 | 427 | current_function_decl = thunk_fndecl; |
3b62f224 | 428 | DECL_RESULT (thunk_fndecl) |
c2255bc4 AH |
429 | = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl), |
430 | RESULT_DECL, 0, integer_type_node); | |
af34b82f | 431 | fnname = IDENTIFIER_POINTER (DECL_NAME (thunk_fndecl)); |
3b426391 | 432 | /* The back end expects DECL_INITIAL to contain a BLOCK, so we |
72c4a4ca GK |
433 | create one. */ |
434 | fn_block = make_node (BLOCK); | |
435 | BLOCK_VARS (fn_block) = a; | |
436 | DECL_INITIAL (thunk_fndecl) = fn_block; | |
ee6b0296 | 437 | init_function_start (thunk_fndecl); |
3c072c6b | 438 | cfun->is_thunk = 1; |
3b62f224 | 439 | assemble_start_function (thunk_fndecl, fnname); |
eb0424da | 440 | |
4977bab6 | 441 | targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl, |
89ce1c8f | 442 | fixed_offset, virtual_value, alias); |
3961e8fe | 443 | |
3b62f224 | 444 | assemble_end_function (thunk_fndecl, fnname); |
8402b3e1 | 445 | init_insn_lengths (); |
dc0c6451 | 446 | free_after_compilation (cfun); |
3b62f224 | 447 | current_function_decl = 0; |
db2960f4 | 448 | set_cfun (NULL); |
6462c441 | 449 | TREE_ASM_WRITTEN (thunk_fndecl) = 1; |
3b62f224 | 450 | } |
4e7512c9 | 451 | else |
14691f8d | 452 | { |
94a0dd7b SL |
453 | int i; |
454 | tree *argarray = (tree *) alloca (list_length (a) * sizeof (tree)); | |
4977bab6 ZW |
455 | /* If this is a covariant thunk, or we don't have the necessary |
456 | code for efficient thunks, generate a thunk function that | |
457 | just makes a call to the real function. Unfortunately, this | |
458 | doesn't work for varargs. */ | |
14691f8d | 459 | |
14691f8d | 460 | if (varargs_function_p (function)) |
2a13a625 | 461 | error ("generic thunk code fails for method %q#D which uses %<...%>", |
14691f8d RH |
462 | function); |
463 | ||
14691f8d RH |
464 | DECL_RESULT (thunk_fndecl) = NULL_TREE; |
465 | ||
058b15c1 | 466 | start_preparsed_function (thunk_fndecl, NULL_TREE, SF_PRE_PARSED); |
14691f8d RH |
467 | /* We don't bother with a body block for thunks. */ |
468 | ||
1bb2cc34 | 469 | /* There's no need to check accessibility inside the thunk body. */ |
78757caa | 470 | push_deferring_access_checks (dk_no_check); |
1bb2cc34 | 471 | |
4977bab6 | 472 | t = a; |
07fa4878 | 473 | if (this_adjusting) |
4977bab6 ZW |
474 | t = thunk_adjust (t, /*this_adjusting=*/1, |
475 | fixed_offset, virtual_offset); | |
c8094d83 | 476 | |
14691f8d | 477 | /* Build up the call to the real function. */ |
94a0dd7b SL |
478 | argarray[0] = t; |
479 | for (i = 1, a = TREE_CHAIN (a); a; a = TREE_CHAIN (a), i++) | |
480 | argarray[i] = a; | |
481 | t = build_call_a (alias, i, argarray); | |
dd292d0a | 482 | CALL_FROM_THUNK_P (t) = 1; |
62cbbe84 | 483 | CALL_CANNOT_INLINE_P (t) = 1; |
c8094d83 | 484 | |
14691f8d RH |
485 | if (VOID_TYPE_P (TREE_TYPE (t))) |
486 | finish_expr_stmt (t); | |
487 | else | |
59445d74 | 488 | { |
59445d74 | 489 | if (!this_adjusting) |
38a37714 NS |
490 | { |
491 | tree cond = NULL_TREE; | |
492 | ||
493 | if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE) | |
494 | { | |
495 | /* If the return type is a pointer, we need to | |
496 | protect against NULL. We know there will be an | |
497 | adjustment, because that's why we're emitting a | |
498 | thunk. */ | |
499 | t = save_expr (t); | |
500 | cond = cp_convert (boolean_type_node, t); | |
501 | } | |
c8094d83 | 502 | |
38a37714 NS |
503 | t = thunk_adjust (t, /*this_adjusting=*/0, |
504 | fixed_offset, virtual_offset); | |
505 | if (cond) | |
506 | t = build3 (COND_EXPR, TREE_TYPE (t), cond, t, | |
507 | cp_convert (TREE_TYPE (t), integer_zero_node)); | |
508 | } | |
9e1e64ec | 509 | if (MAYBE_CLASS_TYPE_P (TREE_TYPE (t))) |
831d8bd7 | 510 | t = build_cplus_new (TREE_TYPE (t), t); |
59445d74 RH |
511 | finish_return_stmt (t); |
512 | } | |
14691f8d RH |
513 | |
514 | /* Since we want to emit the thunk, we explicitly mark its name as | |
515 | referenced. */ | |
bb9a388d | 516 | mark_decl_referenced (thunk_fndecl); |
14691f8d RH |
517 | |
518 | /* But we don't want debugging information about it. */ | |
519 | DECL_IGNORED_P (thunk_fndecl) = 1; | |
520 | ||
1bb2cc34 | 521 | /* Re-enable access control. */ |
78757caa | 522 | pop_deferring_access_checks (); |
1bb2cc34 | 523 | |
e21aff8a | 524 | thunk_fndecl = finish_function (0); |
ff2c88a5 | 525 | cgraph_add_new_function (thunk_fndecl, false); |
14691f8d | 526 | } |
31f8e4f3 MM |
527 | |
528 | pop_from_top_level (); | |
8926095f | 529 | } |
f376e137 MS |
530 | \f |
531 | /* Code for synthesizing methods which have default semantics defined. */ | |
532 | ||
d5f4eddd | 533 | /* Generate code for default X(X&) or X(X&&) constructor. */ |
e92cc029 | 534 | |
824b9a4c | 535 | static void |
4977bab6 | 536 | do_build_copy_constructor (tree fndecl) |
f376e137 | 537 | { |
e0fff4b3 | 538 | tree parm = FUNCTION_FIRST_USER_PARM (fndecl); |
d5f4eddd | 539 | bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl); |
f376e137 | 540 | |
f376e137 MS |
541 | parm = convert_from_reference (parm); |
542 | ||
a59ca936 JM |
543 | if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type) |
544 | && is_empty_class (current_class_type)) | |
545 | /* Don't copy the padding byte; it might not have been allocated | |
546 | if *this is a base subobject. */; | |
547 | else if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)) | |
f376e137 | 548 | { |
fd749a60 | 549 | tree t = build2 (INIT_EXPR, void_type_node, current_class_ref, parm); |
f1dedc31 | 550 | finish_expr_stmt (t); |
f376e137 MS |
551 | } |
552 | else | |
553 | { | |
554 | tree fields = TYPE_FIELDS (current_class_type); | |
fd74ca0b | 555 | tree member_init_list = NULL_TREE; |
89d684bb | 556 | int cvquals = cp_type_quals (TREE_TYPE (parm)); |
f376e137 | 557 | int i; |
fa743e8c | 558 | tree binfo, base_binfo; |
d5f4eddd | 559 | tree init; |
d4e6fecb | 560 | VEC(tree,gc) *vbases; |
f376e137 | 561 | |
713ccd0c NS |
562 | /* Initialize all the base-classes with the parameter converted |
563 | to their type so that we get their copy constructor and not | |
564 | another constructor that takes current_class_type. We must | |
565 | deal with the binfo's directly as a direct base might be | |
566 | inaccessible due to ambiguity. */ | |
9ba5ff0f NS |
567 | for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0; |
568 | VEC_iterate (tree, vbases, i, binfo); i++) | |
01f9e964 | 569 | { |
d5f4eddd JM |
570 | init = build_base_path (PLUS_EXPR, parm, binfo, 1); |
571 | if (move_p) | |
572 | init = move (init); | |
c8094d83 | 573 | member_init_list |
2282d28d | 574 | = tree_cons (binfo, |
d5f4eddd | 575 | build_tree_list (NULL_TREE, init), |
2282d28d | 576 | member_init_list); |
01f9e964 JM |
577 | } |
578 | ||
fa743e8c NS |
579 | for (binfo = TYPE_BINFO (current_class_type), i = 0; |
580 | BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) | |
f376e137 | 581 | { |
fa743e8c | 582 | if (BINFO_VIRTUAL_P (base_binfo)) |
c8094d83 | 583 | continue; |
f376e137 | 584 | |
d5f4eddd JM |
585 | init = build_base_path (PLUS_EXPR, parm, base_binfo, 1); |
586 | if (move_p) | |
587 | init = move (init); | |
c8094d83 | 588 | member_init_list |
fa743e8c | 589 | = tree_cons (base_binfo, |
d5f4eddd | 590 | build_tree_list (NULL_TREE, init), |
2282d28d | 591 | member_init_list); |
f376e137 | 592 | } |
1b5f5f76 | 593 | |
f376e137 MS |
594 | for (; fields; fields = TREE_CHAIN (fields)) |
595 | { | |
a5894242 | 596 | tree field = fields; |
33dd07ee | 597 | tree expr_type; |
a5894242 MS |
598 | |
599 | if (TREE_CODE (field) != FIELD_DECL) | |
f376e137 | 600 | continue; |
8dff1027 | 601 | |
fd749a60 | 602 | expr_type = TREE_TYPE (field); |
a5894242 | 603 | if (DECL_NAME (field)) |
f376e137 | 604 | { |
a5894242 | 605 | if (VFIELD_NAME_P (DECL_NAME (field))) |
f376e137 | 606 | continue; |
f376e137 | 607 | } |
fd749a60 | 608 | else if (ANON_AGGR_TYPE_P (expr_type) && TYPE_FIELDS (expr_type)) |
6bdb8141 JM |
609 | /* Just use the field; anonymous types can't have |
610 | nontrivial copy ctors or assignment ops. */; | |
0171aeab JM |
611 | else |
612 | continue; | |
f376e137 | 613 | |
33dd07ee MM |
614 | /* Compute the type of "init->field". If the copy-constructor |
615 | parameter is, for example, "const S&", and the type of | |
616 | the field is "T", then the type will usually be "const | |
617 | T". (There are no cv-qualified variants of reference | |
618 | types.) */ | |
33dd07ee | 619 | if (TREE_CODE (expr_type) != REFERENCE_TYPE) |
fd749a60 NS |
620 | { |
621 | int quals = cvquals; | |
c8094d83 | 622 | |
fd749a60 NS |
623 | if (DECL_MUTABLE_P (field)) |
624 | quals &= ~TYPE_QUAL_CONST; | |
625 | expr_type = cp_build_qualified_type (expr_type, quals); | |
626 | } | |
c8094d83 | 627 | |
d5f4eddd JM |
628 | init = build3 (COMPONENT_REF, expr_type, parm, field, NULL_TREE); |
629 | if (move_p && TREE_CODE (expr_type) != REFERENCE_TYPE) | |
630 | init = move (init); | |
f376e137 MS |
631 | init = build_tree_list (NULL_TREE, init); |
632 | ||
fd749a60 | 633 | member_init_list = tree_cons (field, init, member_init_list); |
f376e137 | 634 | } |
2282d28d | 635 | finish_mem_initializers (member_init_list); |
f376e137 | 636 | } |
f376e137 MS |
637 | } |
638 | ||
824b9a4c | 639 | static void |
4977bab6 | 640 | do_build_assign_ref (tree fndecl) |
f376e137 MS |
641 | { |
642 | tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); | |
f1dedc31 | 643 | tree compound_stmt; |
f376e137 | 644 | |
325c3691 | 645 | compound_stmt = begin_compound_stmt (0); |
f376e137 MS |
646 | parm = convert_from_reference (parm); |
647 | ||
a59ca936 JM |
648 | if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type) |
649 | && is_empty_class (current_class_type)) | |
650 | /* Don't copy the padding byte; it might not have been allocated | |
651 | if *this is a base subobject. */; | |
652 | else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)) | |
f376e137 | 653 | { |
f293ce4b | 654 | tree t = build2 (MODIFY_EXPR, void_type_node, current_class_ref, parm); |
f1dedc31 | 655 | finish_expr_stmt (t); |
f376e137 MS |
656 | } |
657 | else | |
658 | { | |
4ba126e4 | 659 | tree fields; |
89d684bb | 660 | int cvquals = cp_type_quals (TREE_TYPE (parm)); |
f376e137 | 661 | int i; |
fa743e8c | 662 | tree binfo, base_binfo; |
f376e137 | 663 | |
22ed7e5f | 664 | /* Assign to each of the direct base classes. */ |
fa743e8c NS |
665 | for (binfo = TYPE_BINFO (current_class_type), i = 0; |
666 | BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) | |
f376e137 | 667 | { |
4ba126e4 | 668 | tree converted_parm; |
c166b898 | 669 | VEC(tree,gc) *parmvec; |
4ba126e4 | 670 | |
4ba126e4 MM |
671 | /* We must convert PARM directly to the base class |
672 | explicitly since the base class may be ambiguous. */ | |
fa743e8c | 673 | converted_parm = build_base_path (PLUS_EXPR, parm, base_binfo, 1); |
4ba126e4 | 674 | /* Call the base class assignment operator. */ |
c166b898 | 675 | parmvec = make_tree_vector_single (converted_parm); |
c8094d83 MS |
676 | finish_expr_stmt |
677 | (build_special_member_call (current_class_ref, | |
4ba126e4 | 678 | ansi_assopname (NOP_EXPR), |
c166b898 | 679 | &parmvec, |
fa743e8c | 680 | base_binfo, |
5ade1ed2 DG |
681 | LOOKUP_NORMAL | LOOKUP_NONVIRTUAL, |
682 | tf_warning_or_error)); | |
c166b898 | 683 | release_tree_vector (parmvec); |
f376e137 | 684 | } |
4ba126e4 MM |
685 | |
686 | /* Assign to each of the non-static data members. */ | |
c8094d83 MS |
687 | for (fields = TYPE_FIELDS (current_class_type); |
688 | fields; | |
4ba126e4 | 689 | fields = TREE_CHAIN (fields)) |
f376e137 | 690 | { |
fd749a60 NS |
691 | tree comp = current_class_ref; |
692 | tree init = parm; | |
a5894242 | 693 | tree field = fields; |
fd749a60 NS |
694 | tree expr_type; |
695 | int quals; | |
a5894242 | 696 | |
17bbb839 | 697 | if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field)) |
f376e137 | 698 | continue; |
e349ee73 | 699 | |
fd749a60 | 700 | expr_type = TREE_TYPE (field); |
c8094d83 | 701 | |
fd749a60 | 702 | if (CP_TYPE_CONST_P (expr_type)) |
e349ee73 | 703 | { |
0cbd7506 MS |
704 | error ("non-static const member %q#D, can't use default " |
705 | "assignment operator", field); | |
e349ee73 MS |
706 | continue; |
707 | } | |
fd749a60 | 708 | else if (TREE_CODE (expr_type) == REFERENCE_TYPE) |
e349ee73 | 709 | { |
2a13a625 | 710 | error ("non-static reference member %q#D, can't use " |
0cbd7506 | 711 | "default assignment operator", field); |
e349ee73 MS |
712 | continue; |
713 | } | |
714 | ||
a5894242 | 715 | if (DECL_NAME (field)) |
f376e137 | 716 | { |
a5894242 | 717 | if (VFIELD_NAME_P (DECL_NAME (field))) |
f376e137 | 718 | continue; |
f376e137 | 719 | } |
fd749a60 NS |
720 | else if (ANON_AGGR_TYPE_P (expr_type) |
721 | && TYPE_FIELDS (expr_type) != NULL_TREE) | |
6bdb8141 JM |
722 | /* Just use the field; anonymous types can't have |
723 | nontrivial copy ctors or assignment ops. */; | |
0171aeab JM |
724 | else |
725 | continue; | |
f376e137 | 726 | |
fd749a60 | 727 | comp = build3 (COMPONENT_REF, expr_type, comp, field, NULL_TREE); |
c8094d83 | 728 | |
fd749a60 NS |
729 | /* Compute the type of init->field */ |
730 | quals = cvquals; | |
731 | if (DECL_MUTABLE_P (field)) | |
732 | quals &= ~TYPE_QUAL_CONST; | |
733 | expr_type = cp_build_qualified_type (expr_type, quals); | |
c8094d83 | 734 | |
fd749a60 | 735 | init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE); |
f376e137 | 736 | |
a1c2b86d | 737 | if (DECL_NAME (field)) |
5ade1ed2 DG |
738 | init = cp_build_modify_expr (comp, NOP_EXPR, init, |
739 | tf_warning_or_error); | |
a1c2b86d | 740 | else |
fd749a60 NS |
741 | init = build2 (MODIFY_EXPR, TREE_TYPE (comp), comp, init); |
742 | finish_expr_stmt (init); | |
f376e137 MS |
743 | } |
744 | } | |
62409b39 | 745 | finish_return_stmt (current_class_ref); |
7a3397c7 | 746 | finish_compound_stmt (compound_stmt); |
f376e137 MS |
747 | } |
748 | ||
3e3935a9 NS |
749 | /* Synthesize FNDECL, a non-static member function. */ |
750 | ||
f376e137 | 751 | void |
4977bab6 | 752 | synthesize_method (tree fndecl) |
f376e137 | 753 | { |
4977bab6 | 754 | bool nested = (current_function_decl != NULL_TREE); |
4f1c5b7d | 755 | tree context = decl_function_context (fndecl); |
4977bab6 | 756 | bool need_body = true; |
ade3dc07 | 757 | tree stmt; |
39a87435 | 758 | location_t save_input_location = input_location; |
3e3935a9 NS |
759 | int error_count = errorcount; |
760 | int warning_count = warningcount; | |
db5ae43f | 761 | |
3e3935a9 NS |
762 | /* Reset the source location, we might have been previously |
763 | deferred, and thus have saved where we were first needed. */ | |
764 | DECL_SOURCE_LOCATION (fndecl) | |
765 | = DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (fndecl))); | |
c8094d83 | 766 | |
db9b2174 MM |
767 | /* If we've been asked to synthesize a clone, just synthesize the |
768 | cloned function instead. Doing so will automatically fill in the | |
769 | body for the clone. */ | |
770 | if (DECL_CLONED_FUNCTION_P (fndecl)) | |
3e3935a9 | 771 | fndecl = DECL_CLONED_FUNCTION (fndecl); |
db9b2174 | 772 | |
afb19ffb KL |
773 | /* We may be in the middle of deferred access check. Disable |
774 | it now. */ | |
775 | push_deferring_access_checks (dk_no_deferred); | |
776 | ||
9a3b49ac MS |
777 | if (! context) |
778 | push_to_top_level (); | |
779 | else if (nested) | |
d2784db4 | 780 | push_function_context (); |
db5ae43f | 781 | |
39a87435 | 782 | input_location = DECL_SOURCE_LOCATION (fndecl); |
62409b39 | 783 | |
058b15c1 | 784 | start_preparsed_function (fndecl, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED); |
ade3dc07 | 785 | stmt = begin_function_body (); |
db5ae43f | 786 | |
596ea4e5 | 787 | if (DECL_OVERLOADED_OPERATOR_P (fndecl) == NOP_EXPR) |
62409b39 MM |
788 | { |
789 | do_build_assign_ref (fndecl); | |
4977bab6 | 790 | need_body = false; |
62409b39 | 791 | } |
cdd2559c | 792 | else if (DECL_CONSTRUCTOR_P (fndecl)) |
db5ae43f | 793 | { |
e0fff4b3 | 794 | tree arg_chain = FUNCTION_FIRST_USER_PARMTYPE (fndecl); |
db5ae43f MS |
795 | if (arg_chain != void_list_node) |
796 | do_build_copy_constructor (fndecl); | |
c7b0e027 | 797 | else |
cdd2559c | 798 | finish_mem_initializers (NULL_TREE); |
62409b39 | 799 | } |
f18a14bc | 800 | |
62409b39 MM |
801 | /* If we haven't yet generated the body of the function, just |
802 | generate an empty compound statement. */ | |
803 | if (need_body) | |
804 | { | |
805 | tree compound_stmt; | |
325c3691 | 806 | compound_stmt = begin_compound_stmt (BCS_FN_BODY); |
7a3397c7 | 807 | finish_compound_stmt (compound_stmt); |
db5ae43f MS |
808 | } |
809 | ||
ade3dc07 | 810 | finish_function_body (stmt); |
8cd2462c | 811 | expand_or_defer_fn (finish_function (0)); |
28cbf42c | 812 | |
39a87435 AO |
813 | input_location = save_input_location; |
814 | ||
9a3b49ac MS |
815 | if (! context) |
816 | pop_from_top_level (); | |
817 | else if (nested) | |
d2784db4 | 818 | pop_function_context (); |
afb19ffb KL |
819 | |
820 | pop_deferring_access_checks (); | |
3e3935a9 NS |
821 | |
822 | if (error_count != errorcount || warning_count != warningcount) | |
1f5b3869 MLI |
823 | inform (input_location, "synthesized method %qD first required here ", |
824 | fndecl); | |
f376e137 | 825 | } |
9eb71d8c | 826 | |
03378143 NS |
827 | /* Use EXTRACTOR to locate the relevant function called for each base & |
828 | class field of TYPE. CLIENT allows additional information to be passed | |
f62ea157 JM |
829 | to EXTRACTOR. Generates the union of all exceptions generated by those |
830 | functions. Note that we haven't updated TYPE_FIELDS and such of any | |
831 | variants yet, so we need to look at the main one. */ | |
03378143 NS |
832 | |
833 | static tree | |
4977bab6 | 834 | synthesize_exception_spec (tree type, tree (*extractor) (tree, void*), |
0cbd7506 | 835 | void *client) |
03378143 NS |
836 | { |
837 | tree raises = empty_except_spec; | |
838 | tree fields = TYPE_FIELDS (type); | |
fa743e8c NS |
839 | tree binfo, base_binfo; |
840 | int i; | |
f62ea157 | 841 | |
fa743e8c NS |
842 | for (binfo = TYPE_BINFO (type), i = 0; |
843 | BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) | |
03378143 | 844 | { |
fa743e8c | 845 | tree fn = (*extractor) (BINFO_TYPE (base_binfo), client); |
03378143 | 846 | if (fn) |
0cbd7506 MS |
847 | { |
848 | tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); | |
c8094d83 | 849 | |
0cbd7506 MS |
850 | raises = merge_exception_specifiers (raises, fn_raises); |
851 | } | |
03378143 NS |
852 | } |
853 | for (; fields; fields = TREE_CHAIN (fields)) | |
854 | { | |
855 | tree type = TREE_TYPE (fields); | |
856 | tree fn; | |
c8094d83 | 857 | |
17bbb839 | 858 | if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields)) |
0cbd7506 | 859 | continue; |
03378143 | 860 | while (TREE_CODE (type) == ARRAY_TYPE) |
0cbd7506 | 861 | type = TREE_TYPE (type); |
6276e725 | 862 | if (!CLASS_TYPE_P (type)) |
0cbd7506 | 863 | continue; |
c8094d83 | 864 | |
03378143 NS |
865 | fn = (*extractor) (type, client); |
866 | if (fn) | |
0cbd7506 MS |
867 | { |
868 | tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); | |
c8094d83 | 869 | |
0cbd7506 MS |
870 | raises = merge_exception_specifiers (raises, fn_raises); |
871 | } | |
03378143 NS |
872 | } |
873 | return raises; | |
874 | } | |
875 | ||
876 | /* Locate the dtor of TYPE. */ | |
877 | ||
cb68ec50 | 878 | tree |
4977bab6 | 879 | locate_dtor (tree type, void *client ATTRIBUTE_UNUSED) |
03378143 | 880 | { |
9f4faeae | 881 | return CLASSTYPE_DESTRUCTORS (type); |
03378143 NS |
882 | } |
883 | ||
884 | /* Locate the default ctor of TYPE. */ | |
885 | ||
cb68ec50 | 886 | tree |
4977bab6 | 887 | locate_ctor (tree type, void *client ATTRIBUTE_UNUSED) |
03378143 NS |
888 | { |
889 | tree fns; | |
c8094d83 | 890 | |
03378143 NS |
891 | if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type)) |
892 | return NULL_TREE; | |
aaaa46d2 | 893 | |
508a1c9c MM |
894 | /* Call lookup_fnfields_1 to create the constructor declarations, if |
895 | necessary. */ | |
896 | if (CLASSTYPE_LAZY_DEFAULT_CTOR (type)) | |
897 | return lazily_declare_fn (sfk_constructor, type); | |
898 | ||
aaaa46d2 | 899 | for (fns = CLASSTYPE_CONSTRUCTORS (type); fns; fns = OVL_NEXT (fns)) |
03378143 NS |
900 | { |
901 | tree fn = OVL_CURRENT (fns); | |
902 | tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn)); | |
c8094d83 | 903 | |
63752e29 JM |
904 | parms = skip_artificial_parms_for (fn, parms); |
905 | ||
906 | if (sufficient_parms_p (parms)) | |
0cbd7506 | 907 | return fn; |
03378143 | 908 | } |
6276e725 | 909 | gcc_unreachable (); |
03378143 NS |
910 | } |
911 | ||
912 | struct copy_data | |
913 | { | |
914 | tree name; | |
915 | int quals; | |
916 | }; | |
917 | ||
918 | /* Locate the copy ctor or copy assignment of TYPE. CLIENT_ | |
919 | points to a COPY_DATA holding the name (NULL for the ctor) | |
920 | and desired qualifiers of the source operand. */ | |
921 | ||
cb68ec50 | 922 | tree |
4977bab6 | 923 | locate_copy (tree type, void *client_) |
03378143 NS |
924 | { |
925 | struct copy_data *client = (struct copy_data *)client_; | |
926 | tree fns; | |
03378143 | 927 | tree best = NULL_TREE; |
4977bab6 | 928 | bool excess_p = false; |
c8094d83 | 929 | |
03378143 NS |
930 | if (client->name) |
931 | { | |
508a1c9c MM |
932 | int ix; |
933 | ix = lookup_fnfields_1 (type, client->name); | |
934 | if (ix < 0) | |
935 | return NULL_TREE; | |
936 | fns = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), ix); | |
03378143 NS |
937 | } |
938 | else if (TYPE_HAS_INIT_REF (type)) | |
508a1c9c MM |
939 | { |
940 | /* If construction of the copy constructor was postponed, create | |
941 | it now. */ | |
942 | if (CLASSTYPE_LAZY_COPY_CTOR (type)) | |
943 | lazily_declare_fn (sfk_copy_constructor, type); | |
d5f4eddd JM |
944 | if (CLASSTYPE_LAZY_MOVE_CTOR (type)) |
945 | lazily_declare_fn (sfk_move_constructor, type); | |
508a1c9c MM |
946 | fns = CLASSTYPE_CONSTRUCTORS (type); |
947 | } | |
948 | else | |
03378143 | 949 | return NULL_TREE; |
03378143 NS |
950 | for (; fns; fns = OVL_NEXT (fns)) |
951 | { | |
952 | tree fn = OVL_CURRENT (fns); | |
953 | tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn)); | |
954 | tree src_type; | |
955 | int excess; | |
956 | int quals; | |
c8094d83 | 957 | |
6276e725 | 958 | parms = skip_artificial_parms_for (fn, parms); |
03378143 | 959 | if (!parms) |
0cbd7506 | 960 | continue; |
ee76b931 | 961 | src_type = non_reference (TREE_VALUE (parms)); |
492b73bd LM |
962 | |
963 | if (src_type == error_mark_node) | |
964 | return NULL_TREE; | |
965 | ||
03378143 | 966 | if (!same_type_ignoring_top_level_qualifiers_p (src_type, type)) |
0cbd7506 | 967 | continue; |
03378143 | 968 | if (!sufficient_parms_p (TREE_CHAIN (parms))) |
0cbd7506 | 969 | continue; |
89d684bb | 970 | quals = cp_type_quals (src_type); |
03378143 | 971 | if (client->quals & ~quals) |
0cbd7506 | 972 | continue; |
03378143 NS |
973 | excess = quals & ~client->quals; |
974 | if (!best || (excess_p && !excess)) | |
0cbd7506 MS |
975 | { |
976 | best = fn; | |
977 | excess_p = excess; | |
978 | } | |
03378143 | 979 | else |
0cbd7506 MS |
980 | /* Ambiguous */ |
981 | return NULL_TREE; | |
03378143 NS |
982 | } |
983 | return best; | |
984 | } | |
985 | ||
9eb71d8c MM |
986 | /* Implicitly declare the special function indicated by KIND, as a |
987 | member of TYPE. For copy constructors and assignment operators, | |
988 | CONST_P indicates whether these functions should take a const | |
27d6592c MM |
989 | reference argument or a non-const reference. Returns the |
990 | FUNCTION_DECL for the implicitly declared function. */ | |
9eb71d8c | 991 | |
993acaec | 992 | static tree |
4977bab6 | 993 | implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) |
9eb71d8c | 994 | { |
058b15c1 MM |
995 | tree fn; |
996 | tree parameter_types = void_list_node; | |
44d10c10 | 997 | tree return_type; |
058b15c1 | 998 | tree fn_type; |
03378143 | 999 | tree raises = empty_except_spec; |
058b15c1 | 1000 | tree rhs_parm_type = NULL_TREE; |
e2537f2c | 1001 | tree this_parm; |
058b15c1 | 1002 | tree name; |
64b2bdb3 MM |
1003 | HOST_WIDE_INT saved_processing_template_decl; |
1004 | ||
b2b800a0 | 1005 | /* Because we create declarations for implicitly declared functions |
64b2bdb3 MM |
1006 | lazily, we may be creating the declaration for a member of TYPE |
1007 | while in some completely different context. However, TYPE will | |
1008 | never be a dependent class (because we never want to do lookups | |
1009 | for implicitly defined functions in a dependent class). | |
1010 | Furthermore, we must set PROCESSING_TEMPLATE_DECL to zero here | |
1011 | because we only create clones for constructors and destructors | |
1012 | when not in a template. */ | |
1013 | gcc_assert (!dependent_type_p (type)); | |
1014 | saved_processing_template_decl = processing_template_decl; | |
1015 | processing_template_decl = 0; | |
9eb71d8c | 1016 | |
508a1c9c MM |
1017 | type = TYPE_MAIN_VARIANT (type); |
1018 | ||
44d10c10 PB |
1019 | if (targetm.cxx.cdtor_returns_this () && !TYPE_FOR_JAVA (type)) |
1020 | { | |
1021 | if (kind == sfk_destructor) | |
1022 | /* See comment in check_special_function_return_type. */ | |
1023 | return_type = build_pointer_type (void_type_node); | |
1024 | else | |
1025 | return_type = build_pointer_type (type); | |
1026 | } | |
1027 | else | |
1028 | return_type = void_type_node; | |
1029 | ||
9eb71d8c MM |
1030 | switch (kind) |
1031 | { | |
9eb71d8c | 1032 | case sfk_destructor: |
03378143 | 1033 | /* Destructor. */ |
058b15c1 | 1034 | name = constructor_name (type); |
03378143 | 1035 | raises = synthesize_exception_spec (type, &locate_dtor, 0); |
9eb71d8c MM |
1036 | break; |
1037 | ||
1038 | case sfk_constructor: | |
1039 | /* Default constructor. */ | |
058b15c1 | 1040 | name = constructor_name (type); |
03378143 | 1041 | raises = synthesize_exception_spec (type, &locate_ctor, 0); |
9eb71d8c MM |
1042 | break; |
1043 | ||
1044 | case sfk_copy_constructor: | |
9eb71d8c | 1045 | case sfk_assignment_operator: |
d5f4eddd | 1046 | case sfk_move_constructor: |
03378143 NS |
1047 | { |
1048 | struct copy_data data; | |
c8094d83 | 1049 | |
a2095778 NS |
1050 | data.name = NULL; |
1051 | data.quals = 0; | |
1052 | if (kind == sfk_assignment_operator) | |
0cbd7506 | 1053 | { |
058b15c1 | 1054 | return_type = build_reference_type (type); |
0cbd7506 MS |
1055 | name = ansi_assopname (NOP_EXPR); |
1056 | data.name = name; | |
1057 | } | |
058b15c1 MM |
1058 | else |
1059 | name = constructor_name (type); | |
1060 | ||
9eb71d8c | 1061 | if (const_p) |
0cbd7506 MS |
1062 | { |
1063 | data.quals = TYPE_QUAL_CONST; | |
058b15c1 | 1064 | rhs_parm_type = build_qualified_type (type, TYPE_QUAL_CONST); |
0cbd7506 | 1065 | } |
058b15c1 MM |
1066 | else |
1067 | rhs_parm_type = type; | |
d5f4eddd JM |
1068 | rhs_parm_type |
1069 | = cp_build_reference_type (rhs_parm_type, | |
1070 | kind == sfk_move_constructor); | |
058b15c1 | 1071 | parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types); |
03378143 | 1072 | raises = synthesize_exception_spec (type, &locate_copy, &data); |
9eb71d8c | 1073 | break; |
03378143 | 1074 | } |
9eb71d8c | 1075 | default: |
8dc2b103 | 1076 | gcc_unreachable (); |
9eb71d8c MM |
1077 | } |
1078 | ||
058b15c1 MM |
1079 | /* Create the function. */ |
1080 | fn_type = build_method_type_directly (type, return_type, parameter_types); | |
1081 | if (raises) | |
1082 | fn_type = build_exception_variant (fn_type, raises); | |
1083 | fn = build_lang_decl (FUNCTION_DECL, name, fn_type); | |
aaaa46d2 | 1084 | DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (TYPE_NAME (type)); |
d5f4eddd JM |
1085 | if (kind == sfk_constructor || kind == sfk_copy_constructor |
1086 | || kind == sfk_move_constructor) | |
058b15c1 MM |
1087 | DECL_CONSTRUCTOR_P (fn) = 1; |
1088 | else if (kind == sfk_destructor) | |
1089 | DECL_DESTRUCTOR_P (fn) = 1; | |
1090 | else | |
1091 | { | |
1092 | DECL_ASSIGNMENT_OPERATOR_P (fn) = 1; | |
1093 | SET_OVERLOADED_OPERATOR_CODE (fn, NOP_EXPR); | |
1094 | } | |
b21a6ea1 NS |
1095 | |
1096 | /* If pointers to member functions use the least significant bit to | |
1097 | indicate whether a function is virtual, ensure a pointer | |
1098 | to this function will have that bit clear. */ | |
1099 | if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn | |
1100 | && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT) | |
1101 | DECL_ALIGN (fn) = 2 * BITS_PER_UNIT; | |
1102 | ||
e2537f2c | 1103 | /* Create the explicit arguments. */ |
058b15c1 MM |
1104 | if (rhs_parm_type) |
1105 | { | |
1106 | /* Note that this parameter is *not* marked DECL_ARTIFICIAL; we | |
1107 | want its type to be included in the mangled function | |
1108 | name. */ | |
1109 | DECL_ARGUMENTS (fn) = cp_build_parm_decl (NULL_TREE, rhs_parm_type); | |
1110 | TREE_READONLY (DECL_ARGUMENTS (fn)) = 1; | |
1111 | } | |
3db45ab5 | 1112 | /* Add the "this" parameter. */ |
e2537f2c MM |
1113 | this_parm = build_this_parm (fn_type, TYPE_UNQUALIFIED); |
1114 | TREE_CHAIN (this_parm) = DECL_ARGUMENTS (fn); | |
1115 | DECL_ARGUMENTS (fn) = this_parm; | |
9eb71d8c | 1116 | |
e2537f2c | 1117 | grokclassfn (type, fn, kind == sfk_destructor ? DTOR_FLAG : NO_SPECIAL); |
4684cd27 | 1118 | set_linkage_according_to_type (type, fn); |
0e6df31e | 1119 | rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof); |
058b15c1 | 1120 | DECL_IN_AGGR_P (fn) = 1; |
c727aa5e | 1121 | DECL_ARTIFICIAL (fn) = 1; |
b87d79e6 | 1122 | DECL_DEFAULTED_FN (fn) = 1; |
9eb71d8c | 1123 | DECL_NOT_REALLY_EXTERN (fn) = 1; |
79065db2 | 1124 | DECL_DECLARED_INLINE_P (fn) = 1; |
8dc2b103 | 1125 | gcc_assert (!TREE_USED (fn)); |
9f4faeae | 1126 | |
64b2bdb3 MM |
1127 | /* Restore PROCESSING_TEMPLATE_DECL. */ |
1128 | processing_template_decl = saved_processing_template_decl; | |
1129 | ||
9eb71d8c MM |
1130 | return fn; |
1131 | } | |
e0fff4b3 | 1132 | |
508a1c9c MM |
1133 | /* Add an implicit declaration to TYPE for the kind of function |
1134 | indicated by SFK. Return the FUNCTION_DECL for the new implicit | |
1135 | declaration. */ | |
1136 | ||
1137 | tree | |
1138 | lazily_declare_fn (special_function_kind sfk, tree type) | |
1139 | { | |
1140 | tree fn; | |
1141 | bool const_p; | |
1142 | ||
1143 | /* Figure out whether or not the argument has a const reference | |
1144 | type. */ | |
1145 | if (sfk == sfk_copy_constructor) | |
1146 | const_p = TYPE_HAS_CONST_INIT_REF (type); | |
1147 | else if (sfk == sfk_assignment_operator) | |
1148 | const_p = TYPE_HAS_CONST_ASSIGN_REF (type); | |
1149 | else | |
1150 | /* In this case, CONST_P will be ignored. */ | |
1151 | const_p = false; | |
1152 | /* Declare the function. */ | |
1153 | fn = implicitly_declare_fn (sfk, type, const_p); | |
9f4faeae MM |
1154 | /* A destructor may be virtual. */ |
1155 | if (sfk == sfk_destructor) | |
1156 | check_for_override (fn, type); | |
508a1c9c | 1157 | /* Add it to CLASSTYPE_METHOD_VEC. */ |
b2a9b208 | 1158 | add_method (type, fn, NULL_TREE); |
508a1c9c | 1159 | /* Add it to TYPE_METHODS. */ |
c8094d83 | 1160 | if (sfk == sfk_destructor |
9f4faeae MM |
1161 | && DECL_VIRTUAL_P (fn) |
1162 | && abi_version_at_least (2)) | |
1163 | /* The ABI requires that a virtual destructor go at the end of the | |
1164 | vtable. */ | |
1165 | TYPE_METHODS (type) = chainon (TYPE_METHODS (type), fn); | |
1166 | else | |
1167 | { | |
1168 | /* G++ 3.2 put the implicit destructor at the *beginning* of the | |
1169 | TYPE_METHODS list, which cause the destructor to be emitted | |
c8094d83 | 1170 | in an incorrect location in the vtable. */ |
ee18fe39 | 1171 | if (warn_abi && sfk == sfk_destructor && DECL_VIRTUAL_P (fn)) |
b323323f | 1172 | warning (OPT_Wabi, "vtable layout for class %qT may not be ABI-compliant" |
9f4faeae MM |
1173 | "and may change in a future version of GCC due to " |
1174 | "implicit virtual destructor", | |
1175 | type); | |
1176 | TREE_CHAIN (fn) = TYPE_METHODS (type); | |
1177 | TYPE_METHODS (type) = fn; | |
1178 | } | |
508a1c9c | 1179 | maybe_add_class_template_decl_list (type, fn, /*friend_p=*/0); |
9f4faeae MM |
1180 | if (sfk == sfk_assignment_operator) |
1181 | CLASSTYPE_LAZY_ASSIGNMENT_OP (type) = 0; | |
1182 | else | |
508a1c9c MM |
1183 | { |
1184 | /* Remember that the function has been created. */ | |
1185 | if (sfk == sfk_constructor) | |
1186 | CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0; | |
9f4faeae | 1187 | else if (sfk == sfk_copy_constructor) |
508a1c9c | 1188 | CLASSTYPE_LAZY_COPY_CTOR (type) = 0; |
d5f4eddd JM |
1189 | else if (sfk == sfk_move_constructor) |
1190 | CLASSTYPE_LAZY_MOVE_CTOR (type) = 0; | |
9f4faeae MM |
1191 | else if (sfk == sfk_destructor) |
1192 | CLASSTYPE_LAZY_DESTRUCTOR (type) = 0; | |
508a1c9c MM |
1193 | /* Create appropriate clones. */ |
1194 | clone_function_decl (fn, /*update_method_vec=*/true); | |
1195 | } | |
1196 | ||
1197 | return fn; | |
1198 | } | |
1199 | ||
e0fff4b3 JM |
1200 | /* Given a FUNCTION_DECL FN and a chain LIST, skip as many elements of LIST |
1201 | as there are artificial parms in FN. */ | |
1202 | ||
1203 | tree | |
58f9752a | 1204 | skip_artificial_parms_for (const_tree fn, tree list) |
e0fff4b3 JM |
1205 | { |
1206 | if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) | |
1207 | list = TREE_CHAIN (list); | |
1208 | else | |
1209 | return list; | |
1210 | ||
1211 | if (DECL_HAS_IN_CHARGE_PARM_P (fn)) | |
1212 | list = TREE_CHAIN (list); | |
1213 | if (DECL_HAS_VTT_PARM_P (fn)) | |
1214 | list = TREE_CHAIN (list); | |
1215 | return list; | |
1216 | } | |
89ce1c8f | 1217 | |
94a0dd7b SL |
1218 | /* Given a FUNCTION_DECL FN and a chain LIST, return the number of |
1219 | artificial parms in FN. */ | |
1220 | ||
1221 | int | |
58f9752a | 1222 | num_artificial_parms_for (const_tree fn) |
94a0dd7b SL |
1223 | { |
1224 | int count = 0; | |
1225 | ||
1226 | if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) | |
1227 | count++; | |
1228 | else | |
1229 | return 0; | |
1230 | ||
1231 | if (DECL_HAS_IN_CHARGE_PARM_P (fn)) | |
1232 | count++; | |
1233 | if (DECL_HAS_VTT_PARM_P (fn)) | |
1234 | count++; | |
1235 | return count; | |
1236 | } | |
1237 | ||
1238 | ||
89ce1c8f | 1239 | #include "gt-cp-method.h" |