Create startup files from the GCC sources and drop our versions.
[dragonfly.git] / contrib / gcc-4.0 / 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 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, 59 Temple Place - Suite 330, Boston, MA
21 02111-1307, 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
35 /* Genericize a TRY_BLOCK.  */
36
37 static void
38 genericize_try_block (tree *stmt_p)
39 {
40   tree body = TRY_STMTS (*stmt_p);
41   tree cleanup = TRY_HANDLERS (*stmt_p);
42
43   gimplify_stmt (&body);
44
45   if (CLEANUP_P (*stmt_p))
46     /* A cleanup is an expression, so it doesn't need to be genericized.  */;
47   else
48     gimplify_stmt (&cleanup);
49
50   *stmt_p = build2 (TRY_CATCH_EXPR, void_type_node, body, cleanup);
51 }
52
53 /* Genericize a HANDLER by converting to a CATCH_EXPR.  */
54
55 static void
56 genericize_catch_block (tree *stmt_p)
57 {
58   tree type = HANDLER_TYPE (*stmt_p);
59   tree body = HANDLER_BODY (*stmt_p);
60
61   gimplify_stmt (&body);
62
63   /* FIXME should the caught type go in TREE_TYPE?  */
64   *stmt_p = build2 (CATCH_EXPR, void_type_node, type, body);
65 }
66
67 /* Genericize an EH_SPEC_BLOCK by converting it to a
68    TRY_CATCH_EXPR/EH_FILTER_EXPR pair.  */
69
70 static void
71 genericize_eh_spec_block (tree *stmt_p)
72 {
73   tree body = EH_SPEC_STMTS (*stmt_p);
74   tree allowed = EH_SPEC_RAISES (*stmt_p);
75   tree failure = build_call (call_unexpected_node,
76                              tree_cons (NULL_TREE, build_exc_ptr (),
77                                         NULL_TREE));
78   gimplify_stmt (&body);
79
80   *stmt_p = gimple_build_eh_filter (body, allowed, failure);
81 }
82
83 /* Genericize an IF_STMT by turning it into a COND_EXPR.  */
84
85 static void
86 gimplify_if_stmt (tree *stmt_p)
87 {
88   tree stmt, cond, then_, else_;
89
90   stmt = *stmt_p;
91   cond = IF_COND (stmt);
92   then_ = THEN_CLAUSE (stmt);
93   else_ = ELSE_CLAUSE (stmt);
94
95   if (!then_)
96     then_ = build_empty_stmt ();
97   if (!else_)
98     else_ = build_empty_stmt ();
99
100   if (integer_nonzerop (cond) && !TREE_SIDE_EFFECTS (else_))
101     stmt = then_;
102   else if (integer_zerop (cond) && !TREE_SIDE_EFFECTS (then_))
103     stmt = else_;
104   else
105     stmt = build3 (COND_EXPR, void_type_node, cond, then_, else_);
106   *stmt_p = stmt;
107 }
108
109 /* Gimplify initialization from an AGGR_INIT_EXPR.  */
110
111 static void
112 cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p)
113 {
114   tree from = TREE_OPERAND (*expr_p, 1);
115   tree to = TREE_OPERAND (*expr_p, 0);
116   tree sub;
117
118   /* If we are initializing something from a TARGET_EXPR, strip the
119      TARGET_EXPR and initialize it directly.  */
120   /* What about code that pulls out the temp and uses it elsewhere?  I
121      think that such code never uses the TARGET_EXPR as an initializer.  If
122      I'm wrong, we'll abort because the temp won't have any RTL.  In that
123      case, I guess we'll need to replace references somehow.  */
124   if (TREE_CODE (from) == TARGET_EXPR)
125     from = TARGET_EXPR_INITIAL (from);
126   if (TREE_CODE (from) == CLEANUP_POINT_EXPR)
127     from = TREE_OPERAND (from, 0);
128
129   /* Look through any COMPOUND_EXPRs.  */
130   sub = expr_last (from);
131
132   /* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and
133      replace the slot operand with our target.
134
135      Should we add a target parm to gimplify_expr instead?  No, as in this
136      case we want to replace the INIT_EXPR.  */
137   if (TREE_CODE (sub) == AGGR_INIT_EXPR)
138     {
139       gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
140       TREE_OPERAND (sub, 2) = to;
141       *expr_p = from;
142
143       /* The initialization is now a side-effect, so the container can
144          become void.  */
145       if (from != sub)
146         TREE_TYPE (from) = void_type_node;
147     }
148 }
149
150 /* Gimplify a MUST_NOT_THROW_EXPR.  */
151
152 static void
153 gimplify_must_not_throw_expr (tree *expr_p, tree *pre_p)
154 {
155   tree stmt = *expr_p;
156   tree temp = voidify_wrapper_expr (stmt, NULL);
157   tree body = TREE_OPERAND (stmt, 0);
158
159   gimplify_stmt (&body);
160
161   stmt = gimple_build_eh_filter (body, NULL_TREE,
162                                  build_call (terminate_node, NULL_TREE));
163
164   if (temp)
165     {
166       append_to_statement_list (stmt, pre_p);
167       *expr_p = temp;
168     }
169   else
170     *expr_p = stmt;
171 }
172
173 /* Do C++-specific gimplification.  Args are as for gimplify_expr.  */
174
175 int
176 cp_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p)
177 {
178   int saved_stmts_are_full_exprs_p = 0;
179   enum tree_code code = TREE_CODE (*expr_p);
180   enum gimplify_status ret;
181
182   if (STATEMENT_CODE_P (code))
183     {
184       saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
185       current_stmt_tree ()->stmts_are_full_exprs_p
186         = STMT_IS_FULL_EXPR_P (*expr_p);
187     }
188
189   switch (code)
190     {
191     case PTRMEM_CST:
192       *expr_p = cplus_expand_constant (*expr_p);
193       ret = GS_OK;
194       break;
195
196     case AGGR_INIT_EXPR:
197       simplify_aggr_init_expr (expr_p);
198       ret = GS_OK;
199       break;
200
201     case THROW_EXPR:
202       /* FIXME communicate throw type to backend, probably by moving
203          THROW_EXPR into ../tree.def.  */
204       *expr_p = TREE_OPERAND (*expr_p, 0);
205       ret = GS_OK;
206       break;
207
208     case MUST_NOT_THROW_EXPR:
209       gimplify_must_not_throw_expr (expr_p, pre_p);
210       ret = GS_OK;
211       break;
212
213     case INIT_EXPR:
214     case MODIFY_EXPR:
215       cp_gimplify_init_expr (expr_p, pre_p, post_p);
216       ret = GS_OK;
217       break;
218
219     case EMPTY_CLASS_EXPR:
220       /* We create an INTEGER_CST with RECORD_TYPE and value zero.  */
221       *expr_p = build_int_cst (TREE_TYPE (*expr_p), 0);
222       ret = GS_OK;
223       break;
224
225     case BASELINK:
226       *expr_p = BASELINK_FUNCTIONS (*expr_p);
227       ret = GS_OK;
228       break;
229
230     case TRY_BLOCK:
231       genericize_try_block (expr_p);
232       ret = GS_OK;
233       break;
234
235     case HANDLER:
236       genericize_catch_block (expr_p);
237       ret = GS_OK;
238       break;
239
240     case EH_SPEC_BLOCK:
241       genericize_eh_spec_block (expr_p);
242       ret = GS_OK;
243       break;
244
245     case USING_STMT:
246       /* Just ignore for now.  Eventually we will want to pass this on to
247          the debugger.  */
248       *expr_p = build_empty_stmt ();
249       ret = GS_ALL_DONE;
250       break;
251
252     case IF_STMT:
253       gimplify_if_stmt (expr_p);
254       ret = GS_OK;
255       break;
256
257     default:
258       ret = c_gimplify_expr (expr_p, pre_p, post_p);
259       break;
260     }
261
262   /* Restore saved state.  */
263   if (STATEMENT_CODE_P (code))
264     current_stmt_tree ()->stmts_are_full_exprs_p
265       = saved_stmts_are_full_exprs_p;
266
267   return ret;
268 }
269
270 static inline bool
271 is_invisiref_parm (tree t)
272 {
273   return ((TREE_CODE (t) == PARM_DECL || TREE_CODE (t) == RESULT_DECL)
274           && DECL_BY_REFERENCE (t));
275 }
276
277 /* Perform any pre-gimplification lowering of C++ front end trees to
278    GENERIC.  */
279
280 static tree
281 cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
282 {
283   tree stmt = *stmt_p;
284   struct pointer_set_t *p_set = (struct pointer_set_t*) data;
285
286   if (is_invisiref_parm (stmt))
287     {
288       *stmt_p = convert_from_reference (stmt);
289       *walk_subtrees = 0;
290       return NULL;
291     }
292
293   /* Other than invisiref parms, don't walk the same tree twice.  */
294   if (pointer_set_contains (p_set, stmt))
295     {
296       *walk_subtrees = 0;
297       return NULL_TREE;
298     }
299
300   if (TREE_CODE (stmt) == ADDR_EXPR
301       && is_invisiref_parm (TREE_OPERAND (stmt, 0)))
302     {
303       *stmt_p = convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
304       *walk_subtrees = 0;
305     }
306   else if (TREE_CODE (stmt) == RETURN_EXPR
307            && TREE_OPERAND (stmt, 0)
308            && is_invisiref_parm (TREE_OPERAND (stmt, 0)))
309     /* Don't dereference an invisiref RESULT_DECL inside a RETURN_EXPR.  */
310     *walk_subtrees = 0;
311   else if (IS_TYPE_OR_DECL_P (stmt))
312     *walk_subtrees = 0;
313
314   /* Due to the way voidify_wrapper_expr is written, we don't get a chance
315      to lower this construct before scanning it, so we need to lower these
316      before doing anything else.  */
317   else if (TREE_CODE (stmt) == CLEANUP_STMT)
318     *stmt_p = build2 (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR
319                                              : TRY_FINALLY_EXPR,
320                       void_type_node,
321                       CLEANUP_BODY (stmt),
322                       CLEANUP_EXPR (stmt));
323
324   pointer_set_insert (p_set, *stmt_p);
325   
326   return NULL;
327 }
328
329 void
330 cp_genericize (tree fndecl)
331 {
332   tree t;
333   struct pointer_set_t *p_set;
334
335   /* Fix up the types of parms passed by invisible reference.  */
336   for (t = DECL_ARGUMENTS (fndecl); t; t = TREE_CHAIN (t))
337     if (TREE_ADDRESSABLE (TREE_TYPE (t)))
338       {
339         /* If a function's arguments are copied to create a thunk,
340            then DECL_BY_REFERENCE will be set -- but the type of the
341            argument will be a pointer type, so we will never get
342            here.  */
343         gcc_assert (!DECL_BY_REFERENCE (t));
344         gcc_assert (DECL_ARG_TYPE (t) != TREE_TYPE (t));
345         TREE_TYPE (t) = DECL_ARG_TYPE (t);
346         DECL_BY_REFERENCE (t) = 1;
347         TREE_ADDRESSABLE (t) = 0;
348         relayout_decl (t);
349       }
350
351   /* Do the same for the return value.  */
352   if (TREE_ADDRESSABLE (TREE_TYPE (DECL_RESULT (fndecl))))
353     {
354       t = DECL_RESULT (fndecl);
355       TREE_TYPE (t) = build_reference_type (TREE_TYPE (t));
356       DECL_BY_REFERENCE (t) = 1;
357       TREE_ADDRESSABLE (t) = 0;
358       relayout_decl (t);
359     }
360
361   /* If we're a clone, the body is already GIMPLE.  */
362   if (DECL_CLONED_FUNCTION_P (fndecl))
363     return;
364
365   /* We do want to see every occurrence of the parms, so we can't just use
366      walk_tree's hash functionality.  */
367   p_set = pointer_set_create ();
368   walk_tree (&DECL_SAVED_TREE (fndecl), cp_genericize_r, p_set, NULL);
369   pointer_set_destroy (p_set);
370
371   /* Do everything else.  */
372   c_genericize (fndecl);
373 }