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
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along with GCC; see the file COPYING.  If not, write to the Free
20Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2102110-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
38enum bc_t { bc_break = 0, bc_continue = 1 };
39
40static 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
47static void
48push_context (void)
49{
50  gcc_assert (!ctxp);
51  ctxp = ((struct cp_gimplify_ctx *)
52	  xcalloc (1, sizeof (struct cp_gimplify_ctx)));
53}
54
55static void
56pop_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
70static tree
71begin_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
86static tree
87finish_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
110static tree
111build_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
132static void
133genericize_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
150static void
151genericize_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
165static void
166genericize_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
180static void
181gimplify_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
211static tree
212gimplify_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
287static void
288gimplify_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
301static void
302gimplify_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
311static void
312gimplify_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
321static void
322gimplify_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
344static void
345gimplify_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
379static void
380cp_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
420static void
421gimplify_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
443int
444cp_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
585static inline bool
586is_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
594int
595cxx_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
604unsigned int
605cxx_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
613static tree
614cp_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
684void
685cp_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}
731