gcc41 removal: Part 1 of 2: makefiles
[dragonfly.git] / contrib / gcc-4.1 / gcc / cp / cp-gimplify.c
1 /* C++-specific tree lowering bits; see also c-gimplify.c and tree-gimple.c.
2
3    Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
4    Contributed by Jason Merrill <jason@redhat.com>
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING.  If not, write to the Free
20 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.  */
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "tree.h"
28 #include "cp-tree.h"
29 #include "c-common.h"
30 #include "toplev.h"
31 #include "tree-gimple.h"
32 #include "hashtab.h"
33 #include "pointer-set.h"
34 #include "flags.h"
35
36 /* Local declarations.  */
37
38 enum bc_t { bc_break = 0, bc_continue = 1 };
39
40 static struct cp_gimplify_ctx
41 {
42   /* Stack of labels which are targets for "break" or "continue",
43      linked through TREE_CHAIN.  */
44   tree current_label[2];
45 } *ctxp;
46
47 static void
48 push_context (void)
49 {
50   gcc_assert (!ctxp);
51   ctxp = ((struct cp_gimplify_ctx *)
52           xcalloc (1, sizeof (struct cp_gimplify_ctx)));
53 }
54
55 static void
56 pop_context (void)
57 {
58   gcc_assert (ctxp
59               && !ctxp->current_label[0]
60               && !ctxp->current_label[1]);
61   free (ctxp);
62   ctxp = NULL;
63 }
64
65 /* Begin a scope which can be exited by a break or continue statement.  BC
66    indicates which.
67
68    Just creates a label and pushes it into the current context.  */
69
70 static tree
71 begin_bc_block (enum bc_t bc)
72 {
73   tree label = create_artificial_label ();
74   TREE_CHAIN (label) = ctxp->current_label[bc];
75   ctxp->current_label[bc] = label;
76   return label;
77 }
78
79 /* Finish a scope which can be exited by a break or continue statement.
80    LABEL was returned from the most recent call to begin_bc_block.  BODY is
81    an expression for the contents of the scope.
82
83    If we saw a break (or continue) in the scope, append a LABEL_EXPR to
84    body.  Otherwise, just forget the label.  */
85
86 static tree
87 finish_bc_block (enum bc_t bc, tree label, tree body)
88 {
89   gcc_assert (label == ctxp->current_label[bc]);
90
91   if (TREE_USED (label))
92     {
93       tree t, sl = NULL;
94
95       t = build1 (LABEL_EXPR, void_type_node, label);
96
97       append_to_statement_list (body, &sl);
98       append_to_statement_list (t, &sl);
99       body = sl;
100     }
101
102   ctxp->current_label[bc] = TREE_CHAIN (label);
103   TREE_CHAIN (label) = NULL_TREE;
104   return body;
105 }
106
107 /* Build a GOTO_EXPR to represent a break or continue statement.  BC
108    indicates which.  */
109
110 static tree
111 build_bc_goto (enum bc_t bc)
112 {
113   tree label = ctxp->current_label[bc];
114
115   if (label == NULL_TREE)
116     {
117       if (bc == bc_break)
118         error ("break statement not within loop or switch");
119       else
120         error ("continue statement not within loop or switch");
121
122       return NULL_TREE;
123     }
124
125   /* Mark the label used for finish_bc_block.  */
126   TREE_USED (label) = 1;
127   return build1 (GOTO_EXPR, void_type_node, label);
128 }
129
130 /* Genericize a TRY_BLOCK.  */
131
132 static void
133 genericize_try_block (tree *stmt_p)
134 {
135   tree body = TRY_STMTS (*stmt_p);
136   tree cleanup = TRY_HANDLERS (*stmt_p);
137
138   gimplify_stmt (&body);
139
140   if (CLEANUP_P (*stmt_p))
141     /* A cleanup is an expression, so it doesn't need to be genericized.  */;
142   else
143     gimplify_stmt (&cleanup);
144
145   *stmt_p = build2 (TRY_CATCH_EXPR, void_type_node, body, cleanup);
146 }
147
148 /* Genericize a HANDLER by converting to a CATCH_EXPR.  */
149
150 static void
151 genericize_catch_block (tree *stmt_p)
152 {
153   tree type = HANDLER_TYPE (*stmt_p);
154   tree body = HANDLER_BODY (*stmt_p);
155
156   gimplify_stmt (&body);
157
158   /* FIXME should the caught type go in TREE_TYPE?  */
159   *stmt_p = build2 (CATCH_EXPR, void_type_node, type, body);
160 }
161
162 /* Genericize an EH_SPEC_BLOCK by converting it to a
163    TRY_CATCH_EXPR/EH_FILTER_EXPR pair.  */
164
165 static void
166 genericize_eh_spec_block (tree *stmt_p)
167 {
168   tree body = EH_SPEC_STMTS (*stmt_p);
169   tree allowed = EH_SPEC_RAISES (*stmt_p);
170   tree failure = build_call (call_unexpected_node,
171                              tree_cons (NULL_TREE, build_exc_ptr (),
172                                         NULL_TREE));
173   gimplify_stmt (&body);
174
175   *stmt_p = gimple_build_eh_filter (body, allowed, failure);
176 }
177
178 /* Genericize an IF_STMT by turning it into a COND_EXPR.  */
179
180 static void
181 gimplify_if_stmt (tree *stmt_p)
182 {
183   tree stmt, cond, then_, else_;
184
185   stmt = *stmt_p;
186   cond = IF_COND (stmt);
187   then_ = THEN_CLAUSE (stmt);
188   else_ = ELSE_CLAUSE (stmt);
189
190   if (!then_)
191     then_ = build_empty_stmt ();
192   if (!else_)
193     else_ = build_empty_stmt ();
194
195   if (integer_nonzerop (cond) && !TREE_SIDE_EFFECTS (else_))
196     stmt = then_;
197   else if (integer_zerop (cond) && !TREE_SIDE_EFFECTS (then_))
198     stmt = else_;
199   else
200     stmt = build3 (COND_EXPR, void_type_node, cond, then_, else_);
201   *stmt_p = stmt;
202 }
203
204 /* Build a generic representation of one of the C loop forms.  COND is the
205    loop condition or NULL_TREE.  BODY is the (possibly compound) statement
206    controlled by the loop.  INCR is the increment expression of a for-loop,
207    or NULL_TREE.  COND_IS_FIRST indicates whether the condition is
208    evaluated before the loop body as in while and for loops, or after the
209    loop body as in do-while loops.  */
210
211 static tree
212 gimplify_cp_loop (tree cond, tree body, tree incr, bool cond_is_first)
213 {
214   tree top, entry, exit, cont_block, break_block, stmt_list, t;
215   location_t stmt_locus;
216
217   stmt_locus = input_location;
218   stmt_list = NULL_TREE;
219   entry = NULL_TREE;
220
221   break_block = begin_bc_block (bc_break);
222   cont_block = begin_bc_block (bc_continue);
223
224   /* If condition is zero don't generate a loop construct.  */
225   if (cond && integer_zerop (cond))
226     {
227       top = NULL_TREE;
228       exit = NULL_TREE;
229       if (cond_is_first)
230         {
231           t = build_bc_goto (bc_break);
232           append_to_statement_list (t, &stmt_list);
233         }
234     }
235   else
236     {
237       /* If we use a LOOP_EXPR here, we have to feed the whole thing
238          back through the main gimplifier to lower it.  Given that we
239          have to gimplify the loop body NOW so that we can resolve
240          break/continue stmts, seems easier to just expand to gotos.  */
241       top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
242
243       /* If we have an exit condition, then we build an IF with gotos either
244          out of the loop, or to the top of it.  If there's no exit condition,
245          then we just build a jump back to the top.  */
246       exit = build_and_jump (&LABEL_EXPR_LABEL (top));
247       if (cond && !integer_nonzerop (cond))
248         {
249           t = build_bc_goto (bc_break);
250           exit = build3 (COND_EXPR, void_type_node, cond, exit, t);
251           exit = fold (exit);
252           gimplify_stmt (&exit);
253
254           if (cond_is_first)
255             {
256               if (incr)
257                 {
258                   entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
259                   t = build_and_jump (&LABEL_EXPR_LABEL (entry));
260                 }
261               else
262                 t = build_bc_goto (bc_continue);
263               append_to_statement_list (t, &stmt_list);
264             }
265         }
266     }
267
268   gimplify_stmt (&body);
269   gimplify_stmt (&incr);
270
271   body = finish_bc_block (bc_continue, cont_block, body);
272
273   append_to_statement_list (top, &stmt_list);
274   append_to_statement_list (body, &stmt_list);
275   append_to_statement_list (incr, &stmt_list);
276   append_to_statement_list (entry, &stmt_list);
277   append_to_statement_list (exit, &stmt_list);
278
279   annotate_all_with_locus (&stmt_list, stmt_locus);
280
281   return finish_bc_block (bc_break, break_block, stmt_list);
282 }
283
284 /* Gimplify a FOR_STMT node.  Move the stuff in the for-init-stmt into the
285    prequeue and hand off to gimplify_cp_loop.  */
286
287 static void
288 gimplify_for_stmt (tree *stmt_p, tree *pre_p)
289 {
290   tree stmt = *stmt_p;
291
292   if (FOR_INIT_STMT (stmt))
293     gimplify_and_add (FOR_INIT_STMT (stmt), pre_p);
294
295   *stmt_p = gimplify_cp_loop (FOR_COND (stmt), FOR_BODY (stmt),
296                               FOR_EXPR (stmt), 1);
297 }
298
299 /* Gimplify a WHILE_STMT node.  */
300
301 static void
302 gimplify_while_stmt (tree *stmt_p)
303 {
304   tree stmt = *stmt_p;
305   *stmt_p = gimplify_cp_loop (WHILE_COND (stmt), WHILE_BODY (stmt),
306                               NULL_TREE, 1);
307 }
308
309 /* Gimplify a DO_STMT node.  */
310
311 static void
312 gimplify_do_stmt (tree *stmt_p)
313 {
314   tree stmt = *stmt_p;
315   *stmt_p = gimplify_cp_loop (DO_COND (stmt), DO_BODY (stmt),
316                               NULL_TREE, 0);
317 }
318
319 /* Genericize a SWITCH_STMT by turning it into a SWITCH_EXPR.  */
320
321 static void
322 gimplify_switch_stmt (tree *stmt_p)
323 {
324   tree stmt = *stmt_p;
325   tree break_block, body;
326   location_t stmt_locus = input_location;
327
328   break_block = begin_bc_block (bc_break);
329
330   body = SWITCH_STMT_BODY (stmt);
331   if (!body)
332     body = build_empty_stmt ();
333
334   *stmt_p = build3 (SWITCH_EXPR, SWITCH_STMT_TYPE (stmt),
335                     SWITCH_STMT_COND (stmt), body, NULL_TREE);
336   SET_EXPR_LOCATION (*stmt_p, stmt_locus);
337   gimplify_stmt (stmt_p);
338
339   *stmt_p = finish_bc_block (bc_break, break_block, *stmt_p);
340 }
341
342 /*  Gimplify an EXPR_STMT node.  */
343
344 static void
345 gimplify_expr_stmt (tree *stmt_p)
346 {
347   tree stmt = EXPR_STMT_EXPR (*stmt_p);
348
349   if (stmt == error_mark_node)
350     stmt = NULL;
351
352   /* Gimplification of a statement expression will nullify the
353      statement if all its side effects are moved to *PRE_P and *POST_P.
354
355      In this case we will not want to emit the gimplified statement.
356      However, we may still want to emit a warning, so we do that before
357      gimplification.  */
358   if (stmt && (extra_warnings || warn_unused_value))
359     {
360       if (!TREE_SIDE_EFFECTS (stmt))
361         {
362           if (!IS_EMPTY_STMT (stmt)
363               && !VOID_TYPE_P (TREE_TYPE (stmt))
364               && !TREE_NO_WARNING (stmt))
365             warning (0, "statement with no effect");
366         }
367       else if (warn_unused_value)
368         warn_if_unused_value (stmt, input_location);
369     }
370
371   if (stmt == NULL_TREE)
372     stmt = alloc_stmt_list ();
373
374   *stmt_p = stmt;
375 }
376
377 /* Gimplify initialization from an AGGR_INIT_EXPR.  */
378
379 static void
380 cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p)
381 {
382   tree from = TREE_OPERAND (*expr_p, 1);
383   tree to = TREE_OPERAND (*expr_p, 0);
384   tree sub;
385
386   /* If we are initializing something from a TARGET_EXPR, strip the
387      TARGET_EXPR and initialize it directly.  */
388   /* What about code that pulls out the temp and uses it elsewhere?  I
389      think that such code never uses the TARGET_EXPR as an initializer.  If
390      I'm wrong, we'll abort because the temp won't have any RTL.  In that
391      case, I guess we'll need to replace references somehow.  */
392   if (TREE_CODE (from) == TARGET_EXPR)
393     from = TARGET_EXPR_INITIAL (from);
394   if (TREE_CODE (from) == CLEANUP_POINT_EXPR)
395     from = TREE_OPERAND (from, 0);
396
397   /* Look through any COMPOUND_EXPRs.  */
398   sub = expr_last (from);
399
400   /* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and
401      replace the slot operand with our target.
402
403      Should we add a target parm to gimplify_expr instead?  No, as in this
404      case we want to replace the INIT_EXPR.  */
405   if (TREE_CODE (sub) == AGGR_INIT_EXPR)
406     {
407       gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
408       TREE_OPERAND (sub, 2) = to;
409       *expr_p = from;
410
411       /* The initialization is now a side-effect, so the container can
412          become void.  */
413       if (from != sub)
414         TREE_TYPE (from) = void_type_node;
415     }
416 }
417
418 /* Gimplify a MUST_NOT_THROW_EXPR.  */
419
420 static void
421 gimplify_must_not_throw_expr (tree *expr_p, tree *pre_p)
422 {
423   tree stmt = *expr_p;
424   tree temp = voidify_wrapper_expr (stmt, NULL);
425   tree body = TREE_OPERAND (stmt, 0);
426
427   gimplify_stmt (&body);
428
429   stmt = gimple_build_eh_filter (body, NULL_TREE,
430                                  build_call (terminate_node, NULL_TREE));
431
432   if (temp)
433     {
434       append_to_statement_list (stmt, pre_p);
435       *expr_p = temp;
436     }
437   else
438     *expr_p = stmt;
439 }
440
441 /* Do C++-specific gimplification.  Args are as for gimplify_expr.  */
442
443 int
444 cp_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p)
445 {
446   int saved_stmts_are_full_exprs_p = 0;
447   enum tree_code code = TREE_CODE (*expr_p);
448   enum gimplify_status ret;
449
450   if (STATEMENT_CODE_P (code))
451     {
452       saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
453       current_stmt_tree ()->stmts_are_full_exprs_p
454         = STMT_IS_FULL_EXPR_P (*expr_p);
455     }
456
457   switch (code)
458     {
459     case PTRMEM_CST:
460       *expr_p = cplus_expand_constant (*expr_p);
461       ret = GS_OK;
462       break;
463
464     case AGGR_INIT_EXPR:
465       simplify_aggr_init_expr (expr_p);
466       ret = GS_OK;
467       break;
468
469     case THROW_EXPR:
470       /* FIXME communicate throw type to backend, probably by moving
471          THROW_EXPR into ../tree.def.  */
472       *expr_p = TREE_OPERAND (*expr_p, 0);
473       ret = GS_OK;
474       break;
475
476     case MUST_NOT_THROW_EXPR:
477       gimplify_must_not_throw_expr (expr_p, pre_p);
478       ret = GS_OK;
479       break;
480
481       /* We used to do this for MODIFY_EXPR as well, but that's unsafe; the
482          LHS of an assignment might also be involved in the RHS, as in bug
483          25979.  */
484     case INIT_EXPR:
485       cp_gimplify_init_expr (expr_p, pre_p, post_p);
486       ret = GS_OK;
487       break;
488
489     case EMPTY_CLASS_EXPR:
490       /* We create an empty CONSTRUCTOR with RECORD_TYPE.  */
491       *expr_p = build_constructor (TREE_TYPE (*expr_p), NULL);
492       ret = GS_OK;
493       break;
494
495     case BASELINK:
496       *expr_p = BASELINK_FUNCTIONS (*expr_p);
497       ret = GS_OK;
498       break;
499
500     case TRY_BLOCK:
501       genericize_try_block (expr_p);
502       ret = GS_OK;
503       break;
504
505     case HANDLER:
506       genericize_catch_block (expr_p);
507       ret = GS_OK;
508       break;
509
510     case EH_SPEC_BLOCK:
511       genericize_eh_spec_block (expr_p);
512       ret = GS_OK;
513       break;
514
515     case USING_STMT:
516       /* Just ignore for now.  Eventually we will want to pass this on to
517          the debugger.  */
518       *expr_p = build_empty_stmt ();
519       ret = GS_ALL_DONE;
520       break;
521
522     case IF_STMT:
523       gimplify_if_stmt (expr_p);
524       ret = GS_OK;
525       break;
526
527     case FOR_STMT:
528       gimplify_for_stmt (expr_p, pre_p);
529       ret = GS_ALL_DONE;
530       break;
531
532     case WHILE_STMT:
533       gimplify_while_stmt (expr_p);
534       ret = GS_ALL_DONE;
535       break;
536
537     case DO_STMT:
538       gimplify_do_stmt (expr_p);
539       ret = GS_ALL_DONE;
540       break;
541
542     case SWITCH_STMT:
543       gimplify_switch_stmt (expr_p);
544       ret = GS_ALL_DONE;
545       break;
546
547     case CONTINUE_STMT:
548       *expr_p = build_bc_goto (bc_continue);
549       ret = GS_ALL_DONE;
550       break;
551
552     case BREAK_STMT:
553       *expr_p = build_bc_goto (bc_break);
554       ret = GS_ALL_DONE;
555       break;
556
557     case EXPR_STMT:
558       gimplify_expr_stmt (expr_p);
559       ret = GS_OK;
560       break;
561
562     case UNARY_PLUS_EXPR:
563       {
564         tree arg = TREE_OPERAND (*expr_p, 0);
565         tree type = TREE_TYPE (*expr_p);
566         *expr_p = (TREE_TYPE (arg) != type) ? fold_convert (type, arg)
567                                             : arg;
568         ret = GS_OK;
569       }
570       break;
571
572     default:
573       ret = c_gimplify_expr (expr_p, pre_p, post_p);
574       break;
575     }
576
577   /* Restore saved state.  */
578   if (STATEMENT_CODE_P (code))
579     current_stmt_tree ()->stmts_are_full_exprs_p
580       = saved_stmts_are_full_exprs_p;
581
582   return ret;
583 }
584
585 static inline bool
586 is_invisiref_parm (tree t)
587 {
588   return ((TREE_CODE (t) == PARM_DECL || TREE_CODE (t) == RESULT_DECL)
589           && DECL_BY_REFERENCE (t));
590 }
591
592 /* Return true if the uid in both int tree maps are equal.  */
593
594 int
595 cxx_int_tree_map_eq (const void *va, const void *vb)
596 {
597   const struct cxx_int_tree_map *a = (const struct cxx_int_tree_map *) va;
598   const struct cxx_int_tree_map *b = (const struct cxx_int_tree_map *) vb;
599   return (a->uid == b->uid);
600 }
601
602 /* Hash a UID in a cxx_int_tree_map.  */
603
604 unsigned int
605 cxx_int_tree_map_hash (const void *item)
606 {
607   return ((const struct cxx_int_tree_map *)item)->uid;
608 }
609
610 /* Perform any pre-gimplification lowering of C++ front end trees to
611    GENERIC.  */
612
613 static tree
614 cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
615 {
616   tree stmt = *stmt_p;
617   struct pointer_set_t *p_set = (struct pointer_set_t*) data;
618
619   if (is_invisiref_parm (stmt)
620       /* Don't dereference parms in a thunk, pass the references through. */
621       && !(DECL_THUNK_P (current_function_decl)
622            && TREE_CODE (stmt) == PARM_DECL))
623     {
624       *stmt_p = convert_from_reference (stmt);
625       *walk_subtrees = 0;
626       return NULL;
627     }
628
629   /* Map block scope extern declarations to visible declarations with the
630      same name and type in outer scopes if any.  */
631   if (cp_function_chain->extern_decl_map
632       && (TREE_CODE (stmt) == FUNCTION_DECL || TREE_CODE (stmt) == VAR_DECL)
633       && DECL_EXTERNAL (stmt))
634     {
635       struct cxx_int_tree_map *h, in;
636       in.uid = DECL_UID (stmt);
637       h = (struct cxx_int_tree_map *)
638           htab_find_with_hash (cp_function_chain->extern_decl_map,
639                                &in, in.uid);
640       if (h)
641         {
642           *stmt_p = h->to;
643           *walk_subtrees = 0;
644           return NULL;
645         }
646     }
647
648   /* Other than invisiref parms, don't walk the same tree twice.  */
649   if (pointer_set_contains (p_set, stmt))
650     {
651       *walk_subtrees = 0;
652       return NULL_TREE;
653     }
654
655   if (TREE_CODE (stmt) == ADDR_EXPR
656       && is_invisiref_parm (TREE_OPERAND (stmt, 0)))
657     {
658       *stmt_p = convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
659       *walk_subtrees = 0;
660     }
661   else if (TREE_CODE (stmt) == RETURN_EXPR
662            && TREE_OPERAND (stmt, 0)
663            && is_invisiref_parm (TREE_OPERAND (stmt, 0)))
664     /* Don't dereference an invisiref RESULT_DECL inside a RETURN_EXPR.  */
665     *walk_subtrees = 0;
666   else if (IS_TYPE_OR_DECL_P (stmt))
667     *walk_subtrees = 0;
668
669   /* Due to the way voidify_wrapper_expr is written, we don't get a chance
670      to lower this construct before scanning it, so we need to lower these
671      before doing anything else.  */
672   else if (TREE_CODE (stmt) == CLEANUP_STMT)
673     *stmt_p = build2 (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR
674                                              : TRY_FINALLY_EXPR,
675                       void_type_node,
676                       CLEANUP_BODY (stmt),
677                       CLEANUP_EXPR (stmt));
678
679   pointer_set_insert (p_set, *stmt_p);
680
681   return NULL;
682 }
683
684 void
685 cp_genericize (tree fndecl)
686 {
687   tree t;
688   struct pointer_set_t *p_set;
689
690   /* Fix up the types of parms passed by invisible reference.  */
691   for (t = DECL_ARGUMENTS (fndecl); t; t = TREE_CHAIN (t))
692     if (TREE_ADDRESSABLE (TREE_TYPE (t)))
693       {
694         /* If a function's arguments are copied to create a thunk,
695            then DECL_BY_REFERENCE will be set -- but the type of the
696            argument will be a pointer type, so we will never get
697            here.  */
698         gcc_assert (!DECL_BY_REFERENCE (t));
699         gcc_assert (DECL_ARG_TYPE (t) != TREE_TYPE (t));
700         TREE_TYPE (t) = DECL_ARG_TYPE (t);
701         DECL_BY_REFERENCE (t) = 1;
702         TREE_ADDRESSABLE (t) = 0;
703         relayout_decl (t);
704       }
705
706   /* Do the same for the return value.  */
707   if (TREE_ADDRESSABLE (TREE_TYPE (DECL_RESULT (fndecl))))
708     {
709       t = DECL_RESULT (fndecl);
710       TREE_TYPE (t) = build_reference_type (TREE_TYPE (t));
711       DECL_BY_REFERENCE (t) = 1;
712       TREE_ADDRESSABLE (t) = 0;
713       relayout_decl (t);
714     }
715
716   /* If we're a clone, the body is already GIMPLE.  */
717   if (DECL_CLONED_FUNCTION_P (fndecl))
718     return;
719
720   /* We do want to see every occurrence of the parms, so we can't just use
721      walk_tree's hash functionality.  */
722   p_set = pointer_set_create ();
723   walk_tree (&DECL_SAVED_TREE (fndecl), cp_genericize_r, p_set, NULL);
724   pointer_set_destroy (p_set);
725
726   /* Do everything else.  */
727   push_context ();
728   c_genericize (fndecl);
729   pop_context ();
730 }