]>
Commit | Line | Data |
---|---|---|
8d08fdba MS |
1 | /* Handle the hair of processing (but not expanding) inline functions. |
2 | Also manage function and variable name overloading. | |
d6a8bdff JL |
3 | Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, |
4 | 1999, 2000 Free Software Foundation, Inc. | |
8d08fdba MS |
5 | Contributed by Michael Tiemann (tiemann@cygnus.com) |
6 | ||
e5e809f4 | 7 | This file is part of GNU CC. |
8d08fdba MS |
8 | |
9 | GNU CC is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 2, or (at your option) | |
12 | any later version. | |
13 | ||
14 | GNU CC is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with GNU CC; 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" |
8d08fdba MS |
28 | #include "tree.h" |
29 | #include "cp-tree.h" | |
8d08fdba | 30 | #include "obstack.h" |
8926095f MS |
31 | #include "rtl.h" |
32 | #include "expr.h" | |
33 | #include "output.h" | |
8926095f | 34 | #include "flags.h" |
54f92bfb | 35 | #include "toplev.h" |
9cd64686 | 36 | #include "ggc.h" |
b1afd7f4 | 37 | #include "tm_p.h" |
8d08fdba | 38 | |
669ec2b4 JM |
39 | /* Various flags to control the mangling process. */ |
40 | ||
41 | enum mangling_flags | |
42 | { | |
43 | /* No flags. */ | |
44 | mf_none = 0, | |
45 | /* The thing we are presently mangling is part of a template type, | |
46 | rather than a fully instantiated type. Therefore, we may see | |
47 | complex expressions where we would normally expect to see a | |
48 | simple integer constant. */ | |
49 | mf_maybe_uninstantiated = 1, | |
50 | /* When mangling a numeric value, use the form `_XX_' (instead of | |
51 | just `XX') if the value has more than one digit. */ | |
52 | mf_use_underscores_around_value = 2, | |
53 | }; | |
54 | ||
55 | typedef enum mangling_flags mangling_flags; | |
56 | ||
8d08fdba MS |
57 | /* TREE_LIST of the current inline functions that need to be |
58 | processed. */ | |
59 | struct pending_inline *pending_inlines; | |
60 | ||
669ec2b4 JM |
61 | #define obstack_chunk_alloc xmalloc |
62 | #define obstack_chunk_free free | |
63 | ||
158991b7 KG |
64 | static void do_build_assign_ref PARAMS ((tree)); |
65 | static void do_build_copy_constructor PARAMS ((tree)); | |
669ec2b4 | 66 | #if HOST_BITS_PER_WIDE_INT >= 64 |
9399bad3 | 67 | static void build_mangled_C99_name PARAMS ((int)); |
669ec2b4 | 68 | #endif |
03378143 NS |
69 | static tree synthesize_exception_spec PARAMS ((tree, tree (*) (tree, void *), void *)); |
70 | static tree locate_dtor PARAMS ((tree, void *)); | |
71 | static tree locate_ctor PARAMS ((tree, void *)); | |
72 | static tree locate_copy PARAMS ((tree, void *)); | |
669ec2b4 | 73 | |
669ec2b4 JM |
74 | /* Called once to initialize method.c. */ |
75 | ||
76 | void | |
77 | init_method () | |
78 | { | |
1f84ec23 | 79 | init_mangle (); |
669ec2b4 JM |
80 | } |
81 | ||
669ec2b4 | 82 | \f |
36a117a5 | 83 | /* Set the mangled name (DECL_ASSEMBLER_NAME) for DECL. */ |
386b8a85 | 84 | |
c1def683 | 85 | void |
36a117a5 | 86 | set_mangled_name_for_decl (decl) |
9a68c51f | 87 | tree decl; |
386b8a85 | 88 | { |
6b4b3deb MM |
89 | if (processing_template_decl) |
90 | /* There's no need to mangle the name of a template function. */ | |
91 | return; | |
92 | ||
1f84ec23 | 93 | DECL_ASSEMBLER_NAME (decl) = mangle_decl (decl); |
669ec2b4 JM |
94 | } |
95 | ||
8d08fdba MS |
96 | \f |
97 | /* Given a tree_code CODE, and some arguments (at least one), | |
98 | attempt to use an overloaded operator on the arguments. | |
99 | ||
100 | For unary operators, only the first argument need be checked. | |
101 | For binary operators, both arguments may need to be checked. | |
102 | ||
103 | Member functions can convert class references to class pointers, | |
104 | for one-level deep indirection. More than that is not supported. | |
105 | Operators [](), ()(), and ->() must be member functions. | |
106 | ||
107 | We call function call building calls with LOOKUP_COMPLAIN if they | |
108 | are our only hope. This is true when we see a vanilla operator | |
109 | applied to something of aggregate type. If this fails, we are free | |
110 | to return `error_mark_node', because we will have reported the | |
111 | error. | |
112 | ||
113 | Operators NEW and DELETE overload in funny ways: operator new takes | |
114 | a single `size' parameter, and operator delete takes a pointer to the | |
115 | storage being deleted. When overloading these operators, success is | |
116 | assumed. If there is a failure, report an error message and return | |
117 | `error_mark_node'. */ | |
118 | ||
119 | /* NOSTRICT */ | |
120 | tree | |
121 | build_opfncall (code, flags, xarg1, xarg2, arg3) | |
122 | enum tree_code code; | |
123 | int flags; | |
124 | tree xarg1, xarg2, arg3; | |
125 | { | |
277294d7 | 126 | return build_new_op (code, flags, xarg1, xarg2, arg3); |
8d08fdba MS |
127 | } |
128 | \f | |
129 | /* This function takes an identifier, ID, and attempts to figure out what | |
130 | it means. There are a number of possible scenarios, presented in increasing | |
131 | order of hair: | |
132 | ||
133 | 1) not in a class's scope | |
134 | 2) in class's scope, member name of the class's method | |
135 | 3) in class's scope, but not a member name of the class | |
136 | 4) in class's scope, member name of a class's variable | |
137 | ||
138 | NAME is $1 from the bison rule. It is an IDENTIFIER_NODE. | |
139 | VALUE is $$ from the bison rule. It is the value returned by lookup_name ($1) | |
8d08fdba MS |
140 | |
141 | As a last ditch, try to look up the name as a label and return that | |
142 | address. | |
143 | ||
144 | Values which are declared as being of REFERENCE_TYPE are | |
145 | automatically dereferenced here (as a hack to make the | |
146 | compiler faster). */ | |
147 | ||
148 | tree | |
5566b478 | 149 | hack_identifier (value, name) |
8d08fdba | 150 | tree value, name; |
8d08fdba | 151 | { |
de22184b | 152 | tree type; |
8d08fdba | 153 | |
bd6dd845 | 154 | if (value == error_mark_node) |
8d08fdba MS |
155 | { |
156 | if (current_class_name) | |
157 | { | |
bd0d5d4a JM |
158 | tree fields = lookup_fnfields (TYPE_BINFO (current_class_type), |
159 | name, 1); | |
8d08fdba MS |
160 | if (fields == error_mark_node) |
161 | return error_mark_node; | |
162 | if (fields) | |
163 | { | |
164 | tree fndecl; | |
165 | ||
166 | fndecl = TREE_VALUE (fields); | |
167 | my_friendly_assert (TREE_CODE (fndecl) == FUNCTION_DECL, 251); | |
2c73f9f5 ML |
168 | /* I could not trigger this code. MvL */ |
169 | my_friendly_abort (980325); | |
170 | #ifdef DEAD | |
8d08fdba MS |
171 | if (DECL_CHAIN (fndecl) == NULL_TREE) |
172 | { | |
8251199e | 173 | warning ("methods cannot be converted to function pointers"); |
8d08fdba MS |
174 | return fndecl; |
175 | } | |
176 | else | |
177 | { | |
8251199e | 178 | error ("ambiguous request for method pointer `%s'", |
8d08fdba MS |
179 | IDENTIFIER_POINTER (name)); |
180 | return error_mark_node; | |
181 | } | |
2c73f9f5 | 182 | #endif |
8d08fdba MS |
183 | } |
184 | } | |
185 | if (flag_labels_ok && IDENTIFIER_LABEL_VALUE (name)) | |
186 | { | |
187 | return IDENTIFIER_LABEL_VALUE (name); | |
188 | } | |
189 | return error_mark_node; | |
190 | } | |
191 | ||
192 | type = TREE_TYPE (value); | |
193 | if (TREE_CODE (value) == FIELD_DECL) | |
194 | { | |
4ac14744 | 195 | if (current_class_ptr == NULL_TREE) |
8d08fdba | 196 | { |
672476cb MM |
197 | if (current_function_decl |
198 | && DECL_STATIC_FUNCTION_P (current_function_decl)) | |
8251199e | 199 | cp_error ("invalid use of member `%D' in static member function", |
672476cb MM |
200 | value); |
201 | else | |
202 | /* We can get here when processing a bad default | |
203 | argument, like: | |
204 | struct S { int a; void f(int i = a); } */ | |
8251199e | 205 | cp_error ("invalid use of member `%D'", value); |
672476cb | 206 | |
8d08fdba MS |
207 | return error_mark_node; |
208 | } | |
4ac14744 | 209 | TREE_USED (current_class_ptr) = 1; |
a5894242 | 210 | |
8d08fdba MS |
211 | /* Mark so that if we are in a constructor, and then find that |
212 | this field was initialized by a base initializer, | |
213 | we can emit an error message. */ | |
214 | TREE_USED (value) = 1; | |
4ac14744 | 215 | value = build_component_ref (current_class_ref, name, NULL_TREE, 1); |
8d08fdba | 216 | } |
8f032717 MM |
217 | else if ((TREE_CODE (value) == FUNCTION_DECL |
218 | && DECL_FUNCTION_MEMBER_P (value)) | |
219 | || (TREE_CODE (value) == OVERLOAD | |
220 | && DECL_FUNCTION_MEMBER_P (OVL_CURRENT (value)))) | |
51924768 JM |
221 | { |
222 | tree decl; | |
223 | ||
8f032717 MM |
224 | if (TREE_CODE (value) == OVERLOAD) |
225 | value = OVL_CURRENT (value); | |
226 | ||
4f1c5b7d | 227 | decl = maybe_dummy_object (DECL_CONTEXT (value), 0); |
51924768 JM |
228 | value = build_component_ref (decl, name, NULL_TREE, 1); |
229 | } | |
6b5fbb55 | 230 | else if (really_overloaded_fn (value)) |
8f032717 | 231 | ; |
2c73f9f5 ML |
232 | else if (TREE_CODE (value) == OVERLOAD) |
233 | /* not really overloaded function */ | |
234 | mark_used (OVL_FUNCTION (value)); | |
a5ef9010 JM |
235 | else if (TREE_CODE (value) == TREE_LIST) |
236 | { | |
72b7eeff | 237 | /* Ambiguous reference to base members, possibly other cases?. */ |
a5ef9010 JM |
238 | tree t = value; |
239 | while (t && TREE_CODE (t) == TREE_LIST) | |
240 | { | |
72b7eeff | 241 | mark_used (TREE_VALUE (t)); |
a5ef9010 JM |
242 | t = TREE_CHAIN (t); |
243 | } | |
244 | } | |
2c73f9f5 | 245 | else if (TREE_CODE (value) == NAMESPACE_DECL) |
0e607f34 | 246 | { |
8251199e | 247 | cp_error ("use of namespace `%D' as expression", value); |
0e607f34 JM |
248 | return error_mark_node; |
249 | } | |
250 | else if (DECL_CLASS_TEMPLATE_P (value)) | |
251 | { | |
8251199e | 252 | cp_error ("use of class template `%T' as expression", value); |
0e607f34 JM |
253 | return error_mark_node; |
254 | } | |
8d08fdba | 255 | else |
72b7eeff | 256 | mark_used (value); |
8d08fdba | 257 | |
c6882a35 JM |
258 | if (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == PARM_DECL |
259 | || TREE_CODE (value) == RESULT_DECL) | |
5566b478 MS |
260 | { |
261 | tree context = decl_function_context (value); | |
262 | if (context != NULL_TREE && context != current_function_decl | |
263 | && ! TREE_STATIC (value)) | |
264 | { | |
8251199e | 265 | cp_error ("use of %s from containing function", |
5566b478 MS |
266 | (TREE_CODE (value) == VAR_DECL |
267 | ? "`auto' variable" : "parameter")); | |
8251199e | 268 | cp_error_at (" `%#D' declared here", value); |
e76a2646 | 269 | value = error_mark_node; |
5566b478 MS |
270 | } |
271 | } | |
272 | ||
2f939d94 | 273 | if (DECL_P (value) && DECL_NONLOCAL (value)) |
8d08fdba | 274 | { |
70adf8a9 | 275 | if (DECL_CLASS_SCOPE_P (value) |
4f1c5b7d | 276 | && DECL_CONTEXT (value) != current_class_type) |
8d08fdba | 277 | { |
d6479fe7 | 278 | tree path; |
4f1c5b7d | 279 | path = currently_open_derived_class (DECL_CONTEXT (value)); |
70adf8a9 | 280 | enforce_access (path, value); |
8d08fdba | 281 | } |
8d08fdba | 282 | } |
280f9385 MM |
283 | else if (TREE_CODE (value) == TREE_LIST |
284 | && TREE_TYPE (value) == error_mark_node) | |
8d08fdba | 285 | { |
bd0d5d4a JM |
286 | cp_error ("\ |
287 | request for member `%D' is ambiguous in multiple inheritance lattice", | |
288 | name); | |
66543169 | 289 | print_candidates (value); |
0cfdd854 | 290 | return error_mark_node; |
8d08fdba MS |
291 | } |
292 | ||
75d587eb | 293 | if (! processing_template_decl) |
6b5fbb55 | 294 | value = convert_from_reference (value); |
8d08fdba MS |
295 | return value; |
296 | } | |
297 | ||
8926095f | 298 | \f |
1f6e1acc AS |
299 | /* Return a thunk to FUNCTION. For a virtual thunk, DELTA is the |
300 | offset to this used to locate the vptr, and VCALL_INDEX is used to | |
301 | look up the eventual subobject location. For a non-virtual thunk, | |
302 | DELTA is the offset to this and VCALL_INDEX is zero. */ | |
303 | ||
8926095f | 304 | tree |
31f8e4f3 | 305 | make_thunk (function, delta, vcall_index, generate_with_vtable_p) |
8926095f | 306 | tree function; |
31f8e4f3 MM |
307 | tree delta; |
308 | tree vcall_index; | |
309 | int generate_with_vtable_p; | |
8926095f | 310 | { |
b87692e5 | 311 | tree thunk_id; |
8926095f | 312 | tree thunk; |
8926095f | 313 | tree func_decl; |
31f8e4f3 MM |
314 | tree vcall_offset; |
315 | HOST_WIDE_INT d; | |
316 | ||
317 | /* Scale the VCALL_INDEX to be in terms of bytes. */ | |
318 | if (vcall_index) | |
319 | vcall_offset | |
320 | = size_binop (MULT_EXPR, | |
321 | vcall_index, | |
322 | convert (ssizetype, | |
323 | TYPE_SIZE_UNIT (vtable_entry_type))); | |
324 | else | |
325 | vcall_offset = NULL_TREE; | |
326 | ||
327 | d = tree_low_cst (delta, 0); | |
cc600f33 | 328 | |
8926095f MS |
329 | if (TREE_CODE (function) != ADDR_EXPR) |
330 | abort (); | |
331 | func_decl = TREE_OPERAND (function, 0); | |
332 | if (TREE_CODE (func_decl) != FUNCTION_DECL) | |
333 | abort (); | |
cc600f33 | 334 | |
1f84ec23 MM |
335 | thunk_id = mangle_thunk (TREE_OPERAND (function, 0), |
336 | delta, vcall_offset); | |
a0a33927 | 337 | thunk = IDENTIFIER_GLOBAL_VALUE (thunk_id); |
eb68cb58 | 338 | if (thunk && !DECL_THUNK_P (thunk)) |
a0a33927 | 339 | { |
8251199e | 340 | cp_error ("implementation-reserved name `%D' used", thunk_id); |
2c73f9f5 ML |
341 | thunk = NULL_TREE; |
342 | SET_IDENTIFIER_GLOBAL_VALUE (thunk_id, thunk); | |
a0a33927 MS |
343 | } |
344 | if (thunk == NULL_TREE) | |
345 | { | |
eb448459 | 346 | thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (func_decl)); |
6462c441 MM |
347 | DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (func_decl); |
348 | copy_lang_decl (func_decl); | |
349 | DECL_CONTEXT (thunk) = DECL_CONTEXT (func_decl); | |
eb448459 MS |
350 | TREE_READONLY (thunk) = TREE_READONLY (func_decl); |
351 | TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (func_decl); | |
7fcdf4c2 | 352 | comdat_linkage (thunk); |
eb68cb58 | 353 | SET_DECL_THUNK_P (thunk); |
a0a33927 | 354 | DECL_INITIAL (thunk) = function; |
31f8e4f3 | 355 | THUNK_DELTA (thunk) = d; |
1f6e1acc | 356 | THUNK_VCALL_OFFSET (thunk) = vcall_offset; |
31f8e4f3 | 357 | THUNK_GENERATE_WITH_VTABLE_P (thunk) = generate_with_vtable_p; |
6462c441 MM |
358 | /* The thunk itself is not a constructor or destructor, even if |
359 | the thing it is thunking to is. */ | |
360 | DECL_INTERFACE_KNOWN (thunk) = 1; | |
361 | DECL_NOT_REALLY_EXTERN (thunk) = 1; | |
362 | DECL_SAVED_FUNCTION_DATA (thunk) = NULL; | |
363 | DECL_DESTRUCTOR_P (thunk) = 0; | |
364 | DECL_CONSTRUCTOR_P (thunk) = 0; | |
72b7eeff | 365 | DECL_EXTERNAL (thunk) = 1; |
eb448459 | 366 | DECL_ARTIFICIAL (thunk) = 1; |
c67dca7a | 367 | DECL_VTT_PARM (thunk) = NULL_TREE; |
eb68cb58 MM |
368 | /* Even if this thunk is a member of a local class, we don't |
369 | need a static chain. */ | |
370 | DECL_NO_STATIC_CHAIN (thunk) = 1; | |
6462c441 MM |
371 | /* The THUNK is not a pending inline, even if the FUNC_DECL is. */ |
372 | DECL_PENDING_INLINE_P (thunk) = 0; | |
373 | /* Nor has it been deferred. */ | |
374 | DECL_DEFERRED_FN (thunk) = 0; | |
a0a33927 MS |
375 | /* So that finish_file can write out any thunks that need to be: */ |
376 | pushdecl_top_level (thunk); | |
31f8e4f3 | 377 | /* Create RTL for this thunk so that its address can be taken. */ |
6c418184 | 378 | make_decl_rtl (thunk, NULL); |
a0a33927 | 379 | } |
8926095f MS |
380 | return thunk; |
381 | } | |
382 | ||
eb448459 MS |
383 | /* Emit the definition of a C++ multiple inheritance vtable thunk. */ |
384 | ||
8926095f | 385 | void |
31f8e4f3 | 386 | use_thunk (thunk_fndecl, emit_p) |
824b9a4c | 387 | tree thunk_fndecl; |
31f8e4f3 MM |
388 | int emit_p; |
389 | ||
8926095f | 390 | { |
6462c441 MM |
391 | tree fnaddr; |
392 | tree function; | |
31f8e4f3 MM |
393 | tree vcall_offset; |
394 | HOST_WIDE_INT delta; | |
8926095f MS |
395 | |
396 | if (TREE_ASM_WRITTEN (thunk_fndecl)) | |
397 | return; | |
31f8e4f3 MM |
398 | |
399 | fnaddr = DECL_INITIAL (thunk_fndecl); | |
6462c441 MM |
400 | if (TREE_CODE (DECL_INITIAL (thunk_fndecl)) != ADDR_EXPR) |
401 | /* We already turned this thunk into an ordinary function. | |
402 | There's no need to process this thunk again. (We can't just | |
403 | clear DECL_THUNK_P because that will confuse | |
404 | FNADDR_FROM_VTABLE_ENTRY and friends.) */ | |
405 | return; | |
406 | ||
31f8e4f3 MM |
407 | /* Thunks are always addressable; they only appear in vtables. */ |
408 | TREE_ADDRESSABLE (thunk_fndecl) = 1; | |
a0a33927 | 409 | |
31f8e4f3 MM |
410 | /* Figure out what function is being thunked to. It's referenced in |
411 | this translation unit. */ | |
412 | function = TREE_OPERAND (fnaddr, 0); | |
809c8c30 JM |
413 | TREE_ADDRESSABLE (function) = 1; |
414 | mark_used (function); | |
31f8e4f3 MM |
415 | TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (function)) = 1; |
416 | if (!emit_p) | |
417 | return; | |
809c8c30 | 418 | |
31f8e4f3 MM |
419 | delta = THUNK_DELTA (thunk_fndecl); |
420 | vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl); | |
421 | ||
422 | /* And, if we need to emit the thunk, it's used. */ | |
423 | mark_used (thunk_fndecl); | |
424 | /* This thunk is actually defined. */ | |
425 | DECL_EXTERNAL (thunk_fndecl) = 0; | |
a0128b67 | 426 | |
6462c441 MM |
427 | if (flag_syntax_only) |
428 | { | |
429 | TREE_ASM_WRITTEN (thunk_fndecl) = 1; | |
430 | return; | |
431 | } | |
432 | ||
31f8e4f3 MM |
433 | push_to_top_level (); |
434 | ||
a80e4195 | 435 | #ifdef ASM_OUTPUT_MI_THUNK |
31f8e4f3 | 436 | if (!vcall_offset) |
3b62f224 | 437 | { |
3cce094d | 438 | const char *fnname; |
3b62f224 | 439 | current_function_decl = thunk_fndecl; |
3b62f224 MM |
440 | DECL_RESULT (thunk_fndecl) |
441 | = build_decl (RESULT_DECL, 0, integer_type_node); | |
442 | fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0); | |
443 | init_function_start (thunk_fndecl, input_filename, lineno); | |
444 | current_function_is_thunk = 1; | |
445 | assemble_start_function (thunk_fndecl, fnname); | |
446 | ASM_OUTPUT_MI_THUNK (asm_out_file, thunk_fndecl, delta, function); | |
447 | assemble_end_function (thunk_fndecl, fnname); | |
3b62f224 | 448 | current_function_decl = 0; |
01d939e8 | 449 | cfun = 0; |
6462c441 | 450 | TREE_ASM_WRITTEN (thunk_fndecl) = 1; |
3b62f224 | 451 | } |
4e7512c9 | 452 | else |
aa95639e | 453 | #endif /* ASM_OUTPUT_MI_THUNK */ |
3b62f224 | 454 | { |
eb448459 MS |
455 | /* If we don't have the necessary macro for efficient thunks, generate a |
456 | thunk function that just makes a call to the real function. | |
457 | Unfortunately, this doesn't work for varargs. */ | |
458 | ||
eb66be0e | 459 | tree a, t; |
8926095f | 460 | |
eb448459 | 461 | if (varargs_function_p (function)) |
8251199e | 462 | cp_error ("generic thunk code fails for method `%#D' which uses `...'", |
eb448459 MS |
463 | function); |
464 | ||
eb66be0e MS |
465 | /* Set up clone argument trees for the thunk. */ |
466 | t = NULL_TREE; | |
467 | for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a)) | |
468 | { | |
469 | tree x = copy_node (a); | |
470 | TREE_CHAIN (x) = t; | |
471 | DECL_CONTEXT (x) = thunk_fndecl; | |
472 | t = x; | |
473 | } | |
474 | a = nreverse (t); | |
475 | DECL_ARGUMENTS (thunk_fndecl) = a; | |
476 | DECL_RESULT (thunk_fndecl) = NULL_TREE; | |
eb68cb58 | 477 | |
4e7512c9 | 478 | start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED); |
eb66be0e | 479 | |
4e7512c9 MM |
480 | /* Adjust the this pointer by the constant. */ |
481 | t = ssize_int (delta); | |
eb66be0e | 482 | t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t)); |
4e7512c9 MM |
483 | /* If there's a vcall offset, look up that value in the vtable and |
484 | adjust the `this' pointer again. */ | |
193833ed | 485 | if (vcall_offset && !integer_zerop (vcall_offset)) |
4e7512c9 MM |
486 | { |
487 | tree orig_this; | |
488 | ||
489 | t = save_expr (t); | |
490 | orig_this = t; | |
491 | /* The vptr is always at offset zero in the object. */ | |
492 | t = build1 (NOP_EXPR, | |
493 | build_pointer_type (build_pointer_type | |
494 | (vtable_entry_type)), | |
495 | t); | |
496 | /* Form the vtable address. */ | |
497 | t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t); | |
498 | /* Find the entry with the vcall offset. */ | |
31f8e4f3 | 499 | t = build (PLUS_EXPR, TREE_TYPE (t), t, vcall_offset); |
4e7512c9 MM |
500 | /* Calculate the offset itself. */ |
501 | t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t); | |
502 | /* Adjust the `this' pointer. */ | |
503 | t = fold (build (PLUS_EXPR, | |
504 | TREE_TYPE (orig_this), | |
505 | orig_this, | |
506 | t)); | |
507 | } | |
508 | ||
509 | /* Build up the call to the real function. */ | |
e1b3e07d | 510 | t = tree_cons (NULL_TREE, t, NULL_TREE); |
eb66be0e | 511 | for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a)) |
e1b3e07d | 512 | t = tree_cons (NULL_TREE, a, t); |
eb66be0e | 513 | t = nreverse (t); |
0c11ada6 | 514 | t = build_call (function, t); |
b72801e2 | 515 | if (VOID_TYPE_P (TREE_TYPE (t))) |
baf05df0 | 516 | finish_expr_stmt (t); |
b72801e2 NS |
517 | else |
518 | finish_return_stmt (t); | |
eb66be0e | 519 | |
4e7512c9 | 520 | /* The back-end expects DECL_INITIAL to contain a BLOCK, so we |
6462c441 | 521 | create one. */ |
4e7512c9 MM |
522 | DECL_INITIAL (thunk_fndecl) = make_node (BLOCK); |
523 | BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) | |
524 | = DECL_ARGUMENTS (thunk_fndecl); | |
0acf7199 | 525 | expand_body (finish_function (0)); |
eb448459 | 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 | ||
f376e137 | 533 | /* Generate code for default X(X&) constructor. */ |
e92cc029 | 534 | |
824b9a4c | 535 | static void |
db5ae43f | 536 | do_build_copy_constructor (fndecl) |
f376e137 MS |
537 | tree fndecl; |
538 | { | |
539 | tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); | |
540 | tree t; | |
541 | ||
454fa7a7 | 542 | if (DECL_HAS_IN_CHARGE_PARM_P (fndecl)) |
f376e137 MS |
543 | parm = TREE_CHAIN (parm); |
544 | parm = convert_from_reference (parm); | |
545 | ||
a59ca936 JM |
546 | if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type) |
547 | && is_empty_class (current_class_type)) | |
548 | /* Don't copy the padding byte; it might not have been allocated | |
549 | if *this is a base subobject. */; | |
550 | else if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)) | |
f376e137 | 551 | { |
4ac14744 | 552 | t = build (INIT_EXPR, void_type_node, current_class_ref, parm); |
f1dedc31 | 553 | finish_expr_stmt (t); |
f376e137 MS |
554 | } |
555 | else | |
556 | { | |
557 | tree fields = TYPE_FIELDS (current_class_type); | |
558 | int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type); | |
559 | tree binfos = TYPE_BINFO_BASETYPES (current_class_type); | |
fd74ca0b MM |
560 | tree member_init_list = NULL_TREE; |
561 | tree base_init_list = NULL_TREE; | |
31b1b957 | 562 | int cvquals = CP_TYPE_QUALS (TREE_TYPE (parm)); |
f376e137 MS |
563 | int i; |
564 | ||
1b5f5f76 | 565 | /* Initialize all the base-classes. */ |
f376e137 MS |
566 | for (t = CLASSTYPE_VBASECLASSES (current_class_type); t; |
567 | t = TREE_CHAIN (t)) | |
fd74ca0b | 568 | base_init_list |
a55583e9 | 569 | = tree_cons (BINFO_TYPE (TREE_VALUE (t)), parm, |
fd74ca0b | 570 | base_init_list); |
f376e137 MS |
571 | for (i = 0; i < n_bases; ++i) |
572 | { | |
1b5f5f76 MM |
573 | t = TREE_VEC_ELT (binfos, i); |
574 | if (TREE_VIA_VIRTUAL (t)) | |
8ccc31eb | 575 | continue; |
f376e137 | 576 | |
fd74ca0b MM |
577 | base_init_list |
578 | = tree_cons (BINFO_TYPE (t), parm, base_init_list); | |
f376e137 | 579 | } |
1b5f5f76 | 580 | |
f376e137 MS |
581 | for (; fields; fields = TREE_CHAIN (fields)) |
582 | { | |
de22184b | 583 | tree init, t; |
a5894242 MS |
584 | tree field = fields; |
585 | ||
586 | if (TREE_CODE (field) != FIELD_DECL) | |
f376e137 | 587 | continue; |
8dff1027 MS |
588 | |
589 | init = parm; | |
a5894242 | 590 | if (DECL_NAME (field)) |
f376e137 | 591 | { |
a5894242 | 592 | if (VFIELD_NAME_P (DECL_NAME (field))) |
f376e137 | 593 | continue; |
a5894242 | 594 | if (VBASE_NAME_P (DECL_NAME (field))) |
f376e137 MS |
595 | continue; |
596 | ||
597 | /* True for duplicate members. */ | |
a5894242 | 598 | if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field) |
f376e137 MS |
599 | continue; |
600 | } | |
a5894242 | 601 | else if ((t = TREE_TYPE (field)) != NULL_TREE |
6bdb8141 | 602 | && ANON_AGGR_TYPE_P (t) |
0171aeab | 603 | && TYPE_FIELDS (t) != NULL_TREE) |
6bdb8141 JM |
604 | /* Just use the field; anonymous types can't have |
605 | nontrivial copy ctors or assignment ops. */; | |
0171aeab JM |
606 | else |
607 | continue; | |
f376e137 | 608 | |
31b1b957 NS |
609 | init = build (COMPONENT_REF, |
610 | build_qualified_type (TREE_TYPE (field), cvquals), | |
611 | init, field); | |
f376e137 MS |
612 | init = build_tree_list (NULL_TREE, init); |
613 | ||
fd74ca0b MM |
614 | member_init_list |
615 | = tree_cons (field, init, member_init_list); | |
f376e137 | 616 | } |
fd74ca0b MM |
617 | member_init_list = nreverse (member_init_list); |
618 | base_init_list = nreverse (base_init_list); | |
619 | setup_vtbl_ptr (member_init_list, base_init_list); | |
f376e137 | 620 | } |
f376e137 MS |
621 | } |
622 | ||
824b9a4c | 623 | static void |
db5ae43f | 624 | do_build_assign_ref (fndecl) |
f376e137 MS |
625 | tree fndecl; |
626 | { | |
627 | tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); | |
f1dedc31 | 628 | tree compound_stmt; |
f376e137 | 629 | |
f1dedc31 | 630 | compound_stmt = begin_compound_stmt (/*has_no_scope=*/0); |
f376e137 MS |
631 | parm = convert_from_reference (parm); |
632 | ||
a59ca936 JM |
633 | if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type) |
634 | && is_empty_class (current_class_type)) | |
635 | /* Don't copy the padding byte; it might not have been allocated | |
636 | if *this is a base subobject. */; | |
637 | else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)) | |
f376e137 | 638 | { |
4ac14744 | 639 | tree t = build (MODIFY_EXPR, void_type_node, current_class_ref, parm); |
f1dedc31 | 640 | finish_expr_stmt (t); |
f376e137 MS |
641 | } |
642 | else | |
643 | { | |
644 | tree fields = TYPE_FIELDS (current_class_type); | |
645 | int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type); | |
646 | tree binfos = TYPE_BINFO_BASETYPES (current_class_type); | |
31b1b957 | 647 | int cvquals = CP_TYPE_QUALS (TREE_TYPE (parm)); |
f376e137 MS |
648 | int i; |
649 | ||
650 | for (i = 0; i < n_bases; ++i) | |
651 | { | |
652 | tree basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, i)); | |
31b1b957 | 653 | tree p = build_qualified_type (basetype, cvquals); |
717e3f73 NS |
654 | |
655 | p = convert_to_reference | |
656 | (build_reference_type (p), parm, | |
657 | CONV_IMPLICIT, LOOKUP_COMPLAIN, NULL_TREE); | |
e349ee73 | 658 | p = convert_from_reference (p); |
596ea4e5 | 659 | p = build_member_call (basetype, ansi_assopname (NOP_EXPR), |
051e6fd7 | 660 | build_tree_list (NULL_TREE, p)); |
62409b39 | 661 | finish_expr_stmt (p); |
f376e137 MS |
662 | } |
663 | for (; fields; fields = TREE_CHAIN (fields)) | |
664 | { | |
0171aeab | 665 | tree comp, init, t; |
a5894242 MS |
666 | tree field = fields; |
667 | ||
668 | if (TREE_CODE (field) != FIELD_DECL) | |
f376e137 | 669 | continue; |
e349ee73 | 670 | |
1b8899d1 | 671 | if (CP_TYPE_CONST_P (TREE_TYPE (field))) |
e349ee73 | 672 | { |
31b1b957 | 673 | cp_error ("non-static const member `%#D', can't use default assignment operator", field); |
e349ee73 MS |
674 | continue; |
675 | } | |
676 | else if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE) | |
677 | { | |
31b1b957 | 678 | cp_error ("non-static reference member `%#D', can't use default assignment operator", field); |
e349ee73 MS |
679 | continue; |
680 | } | |
681 | ||
8dff1027 MS |
682 | comp = current_class_ref; |
683 | init = parm; | |
684 | ||
a5894242 | 685 | if (DECL_NAME (field)) |
f376e137 | 686 | { |
a5894242 | 687 | if (VFIELD_NAME_P (DECL_NAME (field))) |
f376e137 | 688 | continue; |
a5894242 | 689 | if (VBASE_NAME_P (DECL_NAME (field))) |
f376e137 MS |
690 | continue; |
691 | ||
692 | /* True for duplicate members. */ | |
a5894242 | 693 | if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field) |
f376e137 MS |
694 | continue; |
695 | } | |
a5894242 | 696 | else if ((t = TREE_TYPE (field)) != NULL_TREE |
6bdb8141 | 697 | && ANON_AGGR_TYPE_P (t) |
0171aeab | 698 | && TYPE_FIELDS (t) != NULL_TREE) |
6bdb8141 JM |
699 | /* Just use the field; anonymous types can't have |
700 | nontrivial copy ctors or assignment ops. */; | |
0171aeab JM |
701 | else |
702 | continue; | |
f376e137 | 703 | |
8dff1027 | 704 | comp = build (COMPONENT_REF, TREE_TYPE (field), comp, field); |
31b1b957 NS |
705 | init = build (COMPONENT_REF, |
706 | build_qualified_type (TREE_TYPE (field), cvquals), | |
707 | init, field); | |
f376e137 | 708 | |
62409b39 | 709 | finish_expr_stmt (build_modify_expr (comp, NOP_EXPR, init)); |
f376e137 MS |
710 | } |
711 | } | |
62409b39 | 712 | finish_return_stmt (current_class_ref); |
f1dedc31 | 713 | finish_compound_stmt (/*has_no_scope=*/0, compound_stmt); |
f376e137 MS |
714 | } |
715 | ||
716 | void | |
db5ae43f | 717 | synthesize_method (fndecl) |
f376e137 MS |
718 | tree fndecl; |
719 | { | |
db5ae43f | 720 | int nested = (current_function_decl != NULL_TREE); |
4f1c5b7d | 721 | tree context = decl_function_context (fndecl); |
62409b39 | 722 | int need_body = 1; |
db5ae43f | 723 | |
b7067a12 JM |
724 | if (at_eof) |
725 | import_export_decl (fndecl); | |
726 | ||
db9b2174 MM |
727 | /* If we've been asked to synthesize a clone, just synthesize the |
728 | cloned function instead. Doing so will automatically fill in the | |
729 | body for the clone. */ | |
730 | if (DECL_CLONED_FUNCTION_P (fndecl)) | |
731 | { | |
732 | synthesize_method (DECL_CLONED_FUNCTION (fndecl)); | |
733 | return; | |
734 | } | |
735 | ||
9a3b49ac MS |
736 | if (! context) |
737 | push_to_top_level (); | |
738 | else if (nested) | |
99dccabc | 739 | push_function_context_to (context); |
db5ae43f | 740 | |
62409b39 MM |
741 | /* Put the function definition at the position where it is needed, |
742 | rather than within the body of the class. That way, an error | |
743 | during the generation of the implicit body points at the place | |
744 | where the attempt to generate the function occurs, giving the | |
745 | user a hint as to why we are attempting to generate the | |
746 | function. */ | |
747 | DECL_SOURCE_LINE (fndecl) = lineno; | |
748 | DECL_SOURCE_FILE (fndecl) = input_filename; | |
749 | ||
e76a2646 | 750 | interface_unknown = 1; |
a8f73d4b | 751 | start_function (NULL_TREE, fndecl, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED); |
f1dedc31 | 752 | clear_last_expr (); |
db5ae43f | 753 | |
596ea4e5 | 754 | if (DECL_OVERLOADED_OPERATOR_P (fndecl) == NOP_EXPR) |
62409b39 MM |
755 | { |
756 | do_build_assign_ref (fndecl); | |
757 | need_body = 0; | |
758 | } | |
9eb71d8c | 759 | else if (DECL_DESTRUCTOR_P (fndecl)) |
fd74ca0b | 760 | setup_vtbl_ptr (NULL_TREE, NULL_TREE); |
db5ae43f MS |
761 | else |
762 | { | |
763 | tree arg_chain = FUNCTION_ARG_CHAIN (fndecl); | |
454fa7a7 | 764 | if (DECL_HAS_IN_CHARGE_PARM_P (fndecl)) |
db5ae43f MS |
765 | arg_chain = TREE_CHAIN (arg_chain); |
766 | if (arg_chain != void_list_node) | |
767 | do_build_copy_constructor (fndecl); | |
768 | else if (TYPE_NEEDS_CONSTRUCTING (current_class_type)) | |
fd74ca0b | 769 | setup_vtbl_ptr (NULL_TREE, NULL_TREE); |
62409b39 | 770 | } |
f18a14bc | 771 | |
62409b39 MM |
772 | /* If we haven't yet generated the body of the function, just |
773 | generate an empty compound statement. */ | |
774 | if (need_body) | |
775 | { | |
776 | tree compound_stmt; | |
777 | compound_stmt = begin_compound_stmt (/*has_no_scope=*/0); | |
778 | finish_compound_stmt (/*has_no_scope=*/0, compound_stmt); | |
db5ae43f MS |
779 | } |
780 | ||
0acf7199 | 781 | expand_body (finish_function (0)); |
28cbf42c | 782 | |
db5ae43f | 783 | extract_interface_info (); |
9a3b49ac MS |
784 | if (! context) |
785 | pop_from_top_level (); | |
786 | else if (nested) | |
99dccabc | 787 | pop_function_context_from (context); |
f376e137 | 788 | } |
9eb71d8c | 789 | |
03378143 NS |
790 | /* Use EXTRACTOR to locate the relevant function called for each base & |
791 | class field of TYPE. CLIENT allows additional information to be passed | |
792 | to EXTRACTOR. Generates the union of all exceptions generated by | |
793 | those functions. */ | |
794 | ||
795 | static tree | |
796 | synthesize_exception_spec (type, extractor, client) | |
797 | tree type; | |
798 | tree (*extractor) (tree, void *); | |
799 | void *client; | |
800 | { | |
801 | tree raises = empty_except_spec; | |
802 | tree fields = TYPE_FIELDS (type); | |
803 | int i, n_bases = CLASSTYPE_N_BASECLASSES (type); | |
804 | tree binfos = TYPE_BINFO_BASETYPES (type); | |
805 | ||
806 | for (i = 0; i != n_bases; i++) | |
807 | { | |
808 | tree base = BINFO_TYPE (TREE_VEC_ELT (binfos, i)); | |
809 | tree fn = (*extractor) (base, client); | |
810 | if (fn) | |
811 | { | |
812 | tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); | |
813 | ||
814 | raises = merge_exception_specifiers (raises, fn_raises); | |
815 | } | |
816 | } | |
817 | for (; fields; fields = TREE_CHAIN (fields)) | |
818 | { | |
819 | tree type = TREE_TYPE (fields); | |
820 | tree fn; | |
821 | ||
822 | if (TREE_CODE (fields) != FIELD_DECL) | |
823 | continue; | |
824 | while (TREE_CODE (type) == ARRAY_TYPE) | |
825 | type = TREE_TYPE (type); | |
826 | if (TREE_CODE (type) != RECORD_TYPE) | |
827 | continue; | |
828 | ||
829 | fn = (*extractor) (type, client); | |
830 | if (fn) | |
831 | { | |
832 | tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); | |
833 | ||
834 | raises = merge_exception_specifiers (raises, fn_raises); | |
835 | } | |
836 | } | |
837 | return raises; | |
838 | } | |
839 | ||
840 | /* Locate the dtor of TYPE. */ | |
841 | ||
842 | static tree | |
843 | locate_dtor (type, client) | |
844 | tree type; | |
845 | void *client ATTRIBUTE_UNUSED; | |
846 | { | |
847 | tree fns; | |
848 | ||
849 | if (!TYPE_HAS_DESTRUCTOR (type)) | |
850 | return NULL_TREE; | |
851 | fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), | |
852 | CLASSTYPE_DESTRUCTOR_SLOT); | |
853 | return fns; | |
854 | } | |
855 | ||
856 | /* Locate the default ctor of TYPE. */ | |
857 | ||
858 | static tree | |
859 | locate_ctor (type, client) | |
860 | tree type; | |
861 | void *client ATTRIBUTE_UNUSED; | |
862 | { | |
863 | tree fns; | |
864 | ||
865 | if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type)) | |
866 | return NULL_TREE; | |
867 | ||
868 | fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), | |
869 | CLASSTYPE_CONSTRUCTOR_SLOT); | |
870 | for (; fns; fns = OVL_NEXT (fns)) | |
871 | { | |
872 | tree fn = OVL_CURRENT (fns); | |
873 | tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn)); | |
874 | ||
875 | if (sufficient_parms_p (TREE_CHAIN (parms))) | |
876 | return fn; | |
877 | } | |
878 | return NULL_TREE; | |
879 | } | |
880 | ||
881 | struct copy_data | |
882 | { | |
883 | tree name; | |
884 | int quals; | |
885 | }; | |
886 | ||
887 | /* Locate the copy ctor or copy assignment of TYPE. CLIENT_ | |
888 | points to a COPY_DATA holding the name (NULL for the ctor) | |
889 | and desired qualifiers of the source operand. */ | |
890 | ||
891 | static tree | |
892 | locate_copy (type, client_) | |
893 | tree type; | |
894 | void *client_; | |
895 | { | |
896 | struct copy_data *client = (struct copy_data *)client_; | |
897 | tree fns; | |
898 | int ix = -1; | |
899 | tree best = NULL_TREE; | |
900 | int excess_p = 0; | |
901 | ||
902 | if (client->name) | |
903 | { | |
904 | if (TYPE_HAS_ASSIGN_REF (type)) | |
905 | ix = lookup_fnfields_1 (type, client->name); | |
906 | } | |
907 | else if (TYPE_HAS_INIT_REF (type)) | |
908 | ix = CLASSTYPE_CONSTRUCTOR_SLOT; | |
909 | if (ix < 0) | |
910 | return NULL_TREE; | |
911 | fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), ix); | |
912 | ||
913 | for (; fns; fns = OVL_NEXT (fns)) | |
914 | { | |
915 | tree fn = OVL_CURRENT (fns); | |
916 | tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn)); | |
917 | tree src_type; | |
918 | int excess; | |
919 | int quals; | |
920 | ||
921 | parms = TREE_CHAIN (parms); | |
922 | if (!parms) | |
923 | continue; | |
924 | src_type = TREE_VALUE (parms); | |
925 | if (TREE_CODE (src_type) == REFERENCE_TYPE) | |
926 | src_type = TREE_TYPE (src_type); | |
927 | if (!same_type_ignoring_top_level_qualifiers_p (src_type, type)) | |
928 | continue; | |
929 | if (!sufficient_parms_p (TREE_CHAIN (parms))) | |
930 | continue; | |
931 | quals = CP_TYPE_QUALS (src_type); | |
932 | if (client->quals & ~quals) | |
933 | continue; | |
934 | excess = quals & ~client->quals; | |
935 | if (!best || (excess_p && !excess)) | |
936 | { | |
937 | best = fn; | |
938 | excess_p = excess; | |
939 | } | |
940 | else | |
941 | /* Ambiguous */ | |
942 | return NULL_TREE; | |
943 | } | |
944 | return best; | |
945 | } | |
946 | ||
9eb71d8c MM |
947 | /* Implicitly declare the special function indicated by KIND, as a |
948 | member of TYPE. For copy constructors and assignment operators, | |
949 | CONST_P indicates whether these functions should take a const | |
950 | reference argument or a non-const reference. */ | |
951 | ||
952 | tree | |
953 | implicitly_declare_fn (kind, type, const_p) | |
954 | special_function_kind kind; | |
955 | tree type; | |
956 | int const_p; | |
957 | { | |
958 | tree declspecs = NULL_TREE; | |
959 | tree fn, args = NULL_TREE; | |
03378143 | 960 | tree raises = empty_except_spec; |
9eb71d8c MM |
961 | tree argtype; |
962 | int retref = 0; | |
963 | tree name = constructor_name (TYPE_IDENTIFIER (type)); | |
964 | ||
965 | switch (kind) | |
966 | { | |
9eb71d8c | 967 | case sfk_destructor: |
03378143 | 968 | /* Destructor. */ |
718b8ea5 | 969 | name = build_nt (BIT_NOT_EXPR, name); |
9eb71d8c | 970 | args = void_list_node; |
03378143 | 971 | raises = synthesize_exception_spec (type, &locate_dtor, 0); |
9eb71d8c MM |
972 | break; |
973 | ||
974 | case sfk_constructor: | |
975 | /* Default constructor. */ | |
976 | args = void_list_node; | |
03378143 | 977 | raises = synthesize_exception_spec (type, &locate_ctor, 0); |
9eb71d8c MM |
978 | break; |
979 | ||
980 | case sfk_copy_constructor: | |
03378143 NS |
981 | { |
982 | struct copy_data data; | |
983 | ||
9eb71d8c MM |
984 | if (const_p) |
985 | type = build_qualified_type (type, TYPE_QUAL_CONST); | |
986 | argtype = build_reference_type (type); | |
987 | args = tree_cons (NULL_TREE, | |
988 | build_tree_list (hash_tree_chain (argtype, NULL_TREE), | |
989 | get_identifier ("_ctor_arg")), | |
990 | void_list_node); | |
03378143 NS |
991 | data.name = NULL; |
992 | data.quals = const_p ? TYPE_QUAL_CONST : 0; | |
993 | raises = synthesize_exception_spec (type, &locate_copy, &data); | |
9eb71d8c | 994 | break; |
03378143 | 995 | } |
9eb71d8c | 996 | case sfk_assignment_operator: |
03378143 NS |
997 | { |
998 | struct copy_data data; | |
999 | ||
9eb71d8c | 1000 | retref = 1; |
1f8f4a0b | 1001 | declspecs = build_tree_list (NULL_TREE, type); |
9eb71d8c MM |
1002 | |
1003 | if (const_p) | |
1004 | type = build_qualified_type (type, TYPE_QUAL_CONST); | |
1005 | ||
596ea4e5 | 1006 | name = ansi_assopname (NOP_EXPR); |
9eb71d8c MM |
1007 | |
1008 | argtype = build_reference_type (type); | |
1009 | args = tree_cons (NULL_TREE, | |
1010 | build_tree_list (hash_tree_chain (argtype, NULL_TREE), | |
1011 | get_identifier ("_ctor_arg")), | |
1012 | void_list_node); | |
03378143 NS |
1013 | data.name = name; |
1014 | data.quals = const_p ? TYPE_QUAL_CONST : 0; | |
1015 | raises = synthesize_exception_spec (type, &locate_copy, &data); | |
9eb71d8c | 1016 | break; |
03378143 | 1017 | } |
9eb71d8c MM |
1018 | default: |
1019 | my_friendly_abort (59); | |
1020 | } | |
1021 | ||
1022 | TREE_PARMLIST (args) = 1; | |
1023 | ||
1024 | { | |
03378143 | 1025 | tree declarator = make_call_declarator (name, args, NULL_TREE, raises); |
9eb71d8c | 1026 | if (retref) |
718b8ea5 | 1027 | declarator = build_nt (ADDR_EXPR, declarator); |
9eb71d8c MM |
1028 | |
1029 | fn = grokfield (declarator, declspecs, NULL_TREE, NULL_TREE, NULL_TREE); | |
1030 | } | |
1031 | ||
1032 | my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 20000408); | |
1033 | ||
1034 | if (kind != sfk_constructor && kind != sfk_destructor) | |
c727aa5e NS |
1035 | DECL_ARTIFICIAL (TREE_CHAIN (DECL_ARGUMENTS (fn))) = 1; |
1036 | DECL_ARTIFICIAL (fn) = 1; | |
9eb71d8c MM |
1037 | DECL_NOT_REALLY_EXTERN (fn) = 1; |
1038 | DECL_THIS_INLINE (fn) = 1; | |
1039 | DECL_INLINE (fn) = 1; | |
1040 | defer_fn (fn); | |
1041 | ||
1042 | return fn; | |
1043 | } |