c-semantics.c revision 90075
190075Sobrien/* This file contains the definitions and documentation for the common
290075Sobrien   tree codes used in the GNU C and C++ compilers (see c-common.def
390075Sobrien   for the standard codes).
490075Sobrien   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
590075Sobrien   Written by Benjamin Chelf (chelf@codesourcery.com).
690075Sobrien
790075SobrienThis file is part of GCC.
890075Sobrien
990075SobrienGCC is free software; you can redistribute it and/or modify it under
1090075Sobrienthe terms of the GNU General Public License as published by the Free
1190075SobrienSoftware Foundation; either version 2, or (at your option) any later
1290075Sobrienversion.
1390075Sobrien
1490075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1590075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1690075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1790075Sobrienfor more details.
1890075Sobrien
1990075SobrienYou should have received a copy of the GNU General Public License
2090075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
2190075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2290075Sobrien02111-1307, USA.  */
2390075Sobrien
2490075Sobrien#include "config.h"
2590075Sobrien#include "system.h"
2690075Sobrien#include "tree.h"
2790075Sobrien#include "function.h"
2890075Sobrien#include "splay-tree.h"
2990075Sobrien#include "varray.h"
3090075Sobrien#include "c-common.h"
3190075Sobrien#include "except.h"
3290075Sobrien#include "toplev.h"
3390075Sobrien#include "flags.h"
3490075Sobrien#include "ggc.h"
3590075Sobrien#include "rtl.h"
3690075Sobrien#include "expr.h"
3790075Sobrien#include "output.h"
3890075Sobrien#include "timevar.h"
3990075Sobrien
4090075Sobrien/* If non-NULL, the address of a language-specific function for
4190075Sobrien   expanding statements.  */
4290075Sobrienvoid (*lang_expand_stmt) PARAMS ((tree));
4390075Sobrien
4490075Sobrien/* If non-NULL, the address of a language-specific function for
4590075Sobrien   expanding a DECL_STMT.  After the language-independent cases are
4690075Sobrien   handled, this function will be called.  If this function is not
4790075Sobrien   defined, it is assumed that declarations other than those for
4890075Sobrien   variables and labels do not require any RTL generation.  */
4990075Sobrienvoid (*lang_expand_decl_stmt) PARAMS ((tree));
5090075Sobrien
5190075Sobrien/* Create an empty statement tree rooted at T.  */
5290075Sobrien
5390075Sobrienvoid
5490075Sobrienbegin_stmt_tree (t)
5590075Sobrien     tree *t;
5690075Sobrien{
5790075Sobrien  /* We create a trivial EXPR_STMT so that last_tree is never NULL in
5890075Sobrien     what follows.  We remove the extraneous statement in
5990075Sobrien     finish_stmt_tree.  */
6090075Sobrien  *t = build_nt (EXPR_STMT, void_zero_node);
6190075Sobrien  last_tree = *t;
6290075Sobrien  last_expr_type = NULL_TREE;
6390075Sobrien  last_expr_filename = input_filename;
6490075Sobrien}
6590075Sobrien
6690075Sobrien/* T is a statement.  Add it to the statement-tree.  */
6790075Sobrien
6890075Sobrientree
6990075Sobrienadd_stmt (t)
7090075Sobrien     tree t;
7190075Sobrien{
7290075Sobrien  if (input_filename != last_expr_filename)
7390075Sobrien    {
7490075Sobrien      /* If the filename has changed, also add in a FILE_STMT.  Do a string
7590075Sobrien	 compare first, though, as it might be an equivalent string.  */
7690075Sobrien      int add = (strcmp (input_filename, last_expr_filename) != 0);
7790075Sobrien      last_expr_filename = input_filename;
7890075Sobrien      if (add)
7990075Sobrien	{
8090075Sobrien	  tree pos = build_nt (FILE_STMT, get_identifier (input_filename));
8190075Sobrien	  add_stmt (pos);
8290075Sobrien	}
8390075Sobrien    }
8490075Sobrien
8590075Sobrien  /* Add T to the statement-tree.  */
8690075Sobrien  TREE_CHAIN (last_tree) = t;
8790075Sobrien  last_tree = t;
8890075Sobrien
8990075Sobrien  /* When we expand a statement-tree, we must know whether or not the
9090075Sobrien     statements are full-expressions.  We record that fact here.  */
9190075Sobrien  STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p ();
9290075Sobrien
9390075Sobrien  /* Keep track of the number of statements in this function.  */
9490075Sobrien  if (current_function_decl)
9590075Sobrien    ++DECL_NUM_STMTS (current_function_decl);
9690075Sobrien
9790075Sobrien  return t;
9890075Sobrien}
9990075Sobrien
10090075Sobrien/* Create a declaration statement for the declaration given by the
10190075Sobrien   DECL.  */
10290075Sobrien
10390075Sobrienvoid
10490075Sobrienadd_decl_stmt (decl)
10590075Sobrien     tree decl;
10690075Sobrien{
10790075Sobrien  tree decl_stmt;
10890075Sobrien
10990075Sobrien  /* We need the type to last until instantiation time.  */
11090075Sobrien  decl_stmt = build_stmt (DECL_STMT, decl);
11190075Sobrien  add_stmt (decl_stmt);
11290075Sobrien}
11390075Sobrien
11490075Sobrien/* Add a scope-statement to the statement-tree.  BEGIN_P indicates
11590075Sobrien   whether this statements opens or closes a scope.  PARTIAL_P is true
11690075Sobrien   for a partial scope, i.e, the scope that begins after a label when
11790075Sobrien   an object that needs a cleanup is created.  If BEGIN_P is nonzero,
11890075Sobrien   returns a new TREE_LIST representing the top of the SCOPE_STMT
11990075Sobrien   stack.  The TREE_PURPOSE is the new SCOPE_STMT.  If BEGIN_P is
12090075Sobrien   zero, returns a TREE_LIST whose TREE_VALUE is the new SCOPE_STMT,
12190075Sobrien   and whose TREE_PURPOSE is the matching SCOPE_STMT with
12290075Sobrien   SCOPE_BEGIN_P set.  */
12390075Sobrien
12490075Sobrientree
12590075Sobrienadd_scope_stmt (begin_p, partial_p)
12690075Sobrien     int begin_p;
12790075Sobrien     int partial_p;
12890075Sobrien{
12990075Sobrien  tree *stack_ptr = current_scope_stmt_stack ();
13090075Sobrien  tree ss;
13190075Sobrien  tree top = *stack_ptr;
13290075Sobrien
13390075Sobrien  /* Build the statement.  */
13490075Sobrien  ss = build_stmt (SCOPE_STMT, NULL_TREE);
13590075Sobrien  SCOPE_BEGIN_P (ss) = begin_p;
13690075Sobrien  SCOPE_PARTIAL_P (ss) = partial_p;
13790075Sobrien
13890075Sobrien  /* Keep the scope stack up to date.  */
13990075Sobrien  if (begin_p)
14090075Sobrien    {
14190075Sobrien      top = tree_cons (ss, NULL_TREE, top);
14290075Sobrien      *stack_ptr = top;
14390075Sobrien    }
14490075Sobrien  else
14590075Sobrien    {
14690075Sobrien      TREE_VALUE (top) = ss;
14790075Sobrien      *stack_ptr = TREE_CHAIN (top);
14890075Sobrien    }
14990075Sobrien
15090075Sobrien  /* Add the new statement to the statement-tree.  */
15190075Sobrien  add_stmt (ss);
15290075Sobrien
15390075Sobrien  return top;
15490075Sobrien}
15590075Sobrien
15690075Sobrien/* Finish the statement tree rooted at T.  */
15790075Sobrien
15890075Sobrienvoid
15990075Sobrienfinish_stmt_tree (t)
16090075Sobrien     tree *t;
16190075Sobrien{
16290075Sobrien  tree stmt;
16390075Sobrien
16490075Sobrien  /* Remove the fake extra statement added in begin_stmt_tree.  */
16590075Sobrien  stmt = TREE_CHAIN (*t);
16690075Sobrien  *t = stmt;
16790075Sobrien  last_tree = NULL_TREE;
16890075Sobrien
16990075Sobrien  if (cfun && stmt)
17090075Sobrien    {
17190075Sobrien      /* The line-number recorded in the outermost statement in a function
17290075Sobrien	 is the line number of the end of the function.  */
17390075Sobrien      STMT_LINENO (stmt) = lineno;
17490075Sobrien      STMT_LINENO_FOR_FN_P (stmt) = 1;
17590075Sobrien    }
17690075Sobrien}
17790075Sobrien
17890075Sobrien/* Build a generic statement based on the given type of node and
17990075Sobrien   arguments. Similar to `build_nt', except that we set
18090075Sobrien   STMT_LINENO to be the current line number.  */
18190075Sobrien/* ??? This should be obsolete with the lineno_stmt productions
18290075Sobrien   in the grammar.  */
18390075Sobrien
18490075Sobrientree
18590075Sobrienbuild_stmt VPARAMS ((enum tree_code code, ...))
18690075Sobrien{
18790075Sobrien  tree t;
18890075Sobrien  int length;
18990075Sobrien  int i;
19090075Sobrien
19190075Sobrien  VA_OPEN (p, code);
19290075Sobrien  VA_FIXEDARG (p, enum tree_code, code);
19390075Sobrien
19490075Sobrien  t = make_node (code);
19590075Sobrien  length = TREE_CODE_LENGTH (code);
19690075Sobrien  STMT_LINENO (t) = lineno;
19790075Sobrien
19890075Sobrien  for (i = 0; i < length; i++)
19990075Sobrien    TREE_OPERAND (t, i) = va_arg (p, tree);
20090075Sobrien
20190075Sobrien  VA_CLOSE (p);
20290075Sobrien  return t;
20390075Sobrien}
20490075Sobrien
20590075Sobrien/* Some statements, like for-statements or if-statements, require a
20690075Sobrien   condition.  This condition can be a declaration.  If T is such a
20790075Sobrien   declaration it is processed, and an expression appropriate to use
20890075Sobrien   as the condition is returned.  Otherwise, T itself is returned.  */
20990075Sobrien
21090075Sobrientree
21190075Sobrienexpand_cond (t)
21290075Sobrien     tree t;
21390075Sobrien{
21490075Sobrien  if (t && TREE_CODE (t) == TREE_LIST)
21590075Sobrien    {
21690075Sobrien      expand_stmt (TREE_PURPOSE (t));
21790075Sobrien      return TREE_VALUE (t);
21890075Sobrien    }
21990075Sobrien  else
22090075Sobrien    return t;
22190075Sobrien}
22290075Sobrien
22390075Sobrien/* Create RTL for the local static variable DECL.  */
22490075Sobrien
22590075Sobrienvoid
22690075Sobrienmake_rtl_for_local_static (decl)
22790075Sobrien     tree decl;
22890075Sobrien{
22990075Sobrien  const char *asmspec = NULL;
23090075Sobrien
23190075Sobrien  /* If we inlined this variable, we could see it's declaration
23290075Sobrien     again.  */
23390075Sobrien  if (TREE_ASM_WRITTEN (decl))
23490075Sobrien    return;
23590075Sobrien
23690075Sobrien  /* If the DECL_ASSEMBLER_NAME is not the same as the DECL_NAME, then
23790075Sobrien     either we already created RTL for this DECL (and since it was a
23890075Sobrien     local variable, its DECL_ASSEMBLER_NAME got hacked up to prevent
23990075Sobrien     clashes with other local statics with the same name by a previous
24090075Sobrien     call to make_decl_rtl), or the user explicitly requested a
24190075Sobrien     particular assembly name for this variable, using the GNU
24290075Sobrien     extension for this purpose:
24390075Sobrien
24490075Sobrien       int i asm ("j");
24590075Sobrien
24690075Sobrien     There's no way to know which case we're in, here.  But, it turns
24790075Sobrien     out we're safe.  If there's already RTL, then
24890075Sobrien     rest_of_decl_compilation ignores the ASMSPEC parameter, so we
24990075Sobrien     may as well not pass it in.  If there isn't RTL, then we didn't
25090075Sobrien     already create RTL, which means that the modification to
25190075Sobrien     DECL_ASSEMBLER_NAME came only via the explicit extension.  */
25290075Sobrien  if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
25390075Sobrien      && !DECL_RTL_SET_P (decl))
25490075Sobrien    asmspec = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
25590075Sobrien
25690075Sobrien  rest_of_decl_compilation (decl, asmspec, /*top_level=*/0, /*at_end=*/0);
25790075Sobrien}
25890075Sobrien
25990075Sobrien/* Let the back-end know about DECL.  */
26090075Sobrien
26190075Sobrienvoid
26290075Sobrienemit_local_var (decl)
26390075Sobrien     tree decl;
26490075Sobrien{
26590075Sobrien  /* Create RTL for this variable.  */
26690075Sobrien  if (!DECL_RTL_SET_P (decl))
26790075Sobrien    {
26890075Sobrien      if (DECL_C_HARD_REGISTER (decl))
26990075Sobrien	/* The user specified an assembler name for this variable.
27090075Sobrien	   Set that up now.  */
27190075Sobrien	rest_of_decl_compilation
27290075Sobrien	  (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
27390075Sobrien	   /*top_level=*/0, /*at_end=*/0);
27490075Sobrien      else
27590075Sobrien	expand_decl (decl);
27690075Sobrien    }
27790075Sobrien
27890075Sobrien  /* Actually do the initialization.  */
27990075Sobrien  if (stmts_are_full_exprs_p ())
28090075Sobrien    expand_start_target_temps ();
28190075Sobrien
28290075Sobrien  expand_decl_init (decl);
28390075Sobrien
28490075Sobrien  if (stmts_are_full_exprs_p ())
28590075Sobrien    expand_end_target_temps ();
28690075Sobrien}
28790075Sobrien
28890075Sobrien/* Helper for generating the RTL at the beginning of a scope.  */
28990075Sobrien
29090075Sobrienvoid
29190075Sobriengenrtl_do_pushlevel ()
29290075Sobrien{
29390075Sobrien  emit_line_note (input_filename, lineno);
29490075Sobrien  clear_last_expr ();
29590075Sobrien}
29690075Sobrien
29790075Sobrien/* Generate the RTL for DESTINATION, which is a GOTO_STMT.  */
29890075Sobrien
29990075Sobrienvoid
30090075Sobriengenrtl_goto_stmt (destination)
30190075Sobrien     tree destination;
30290075Sobrien{
30390075Sobrien  if (TREE_CODE (destination) == IDENTIFIER_NODE)
30490075Sobrien    abort ();
30590075Sobrien
30690075Sobrien  /* We warn about unused labels with -Wunused.  That means we have to
30790075Sobrien     mark the used labels as used.  */
30890075Sobrien  if (TREE_CODE (destination) == LABEL_DECL)
30990075Sobrien    TREE_USED (destination) = 1;
31090075Sobrien
31190075Sobrien  emit_line_note (input_filename, lineno);
31290075Sobrien
31390075Sobrien  if (TREE_CODE (destination) == LABEL_DECL)
31490075Sobrien    {
31590075Sobrien      label_rtx (destination);
31690075Sobrien      expand_goto (destination);
31790075Sobrien    }
31890075Sobrien  else
31990075Sobrien    expand_computed_goto (destination);
32090075Sobrien}
32190075Sobrien
32290075Sobrien/* Generate the RTL for EXPR, which is an EXPR_STMT.  Provided just
32390075Sobrien   for backward compatibility.  genrtl_expr_stmt_value() should be
32490075Sobrien   used for new code.  */
32590075Sobrien
32690075Sobrienvoid
32790075Sobriengenrtl_expr_stmt (expr)
32890075Sobrien     tree expr;
32990075Sobrien{
33090075Sobrien  genrtl_expr_stmt_value (expr, -1, 1);
33190075Sobrien}
33290075Sobrien
33390075Sobrien/* Generate the RTL for EXPR, which is an EXPR_STMT.  WANT_VALUE tells
33490075Sobrien   whether to (1) save the value of the expression, (0) discard it or
33590075Sobrien   (-1) use expr_stmts_for_value to tell.  The use of -1 is
33690075Sobrien   deprecated, and retained only for backward compatibility.
33790075Sobrien   MAYBE_LAST is non-zero if this EXPR_STMT might be the last statement
33890075Sobrien   in expression statement.  */
33990075Sobrien
34090075Sobrienvoid
34190075Sobriengenrtl_expr_stmt_value (expr, want_value, maybe_last)
34290075Sobrien     tree expr;
34390075Sobrien     int want_value, maybe_last;
34490075Sobrien{
34590075Sobrien  if (expr != NULL_TREE)
34690075Sobrien    {
34790075Sobrien      emit_line_note (input_filename, lineno);
34890075Sobrien
34990075Sobrien      if (stmts_are_full_exprs_p ())
35090075Sobrien	expand_start_target_temps ();
35190075Sobrien
35290075Sobrien      if (expr != error_mark_node)
35390075Sobrien	expand_expr_stmt_value (expr, want_value, maybe_last);
35490075Sobrien
35590075Sobrien      if (stmts_are_full_exprs_p ())
35690075Sobrien	expand_end_target_temps ();
35790075Sobrien    }
35890075Sobrien}
35990075Sobrien
36090075Sobrien/* Generate the RTL for T, which is a DECL_STMT.  */
36190075Sobrien
36290075Sobrienvoid
36390075Sobriengenrtl_decl_stmt (t)
36490075Sobrien     tree t;
36590075Sobrien{
36690075Sobrien  tree decl;
36790075Sobrien  emit_line_note (input_filename, lineno);
36890075Sobrien  decl = DECL_STMT_DECL (t);
36990075Sobrien  /* If this is a declaration for an automatic local
37090075Sobrien     variable, initialize it.  Note that we might also see a
37190075Sobrien     declaration for a namespace-scope object (declared with
37290075Sobrien     `extern').  We don't have to handle the initialization
37390075Sobrien     of those objects here; they can only be declarations,
37490075Sobrien     rather than definitions.  */
37590075Sobrien  if (TREE_CODE (decl) == VAR_DECL
37690075Sobrien      && !TREE_STATIC (decl)
37790075Sobrien      && !DECL_EXTERNAL (decl))
37890075Sobrien    {
37990075Sobrien      /* Let the back-end know about this variable.  */
38090075Sobrien      if (!anon_aggr_type_p (TREE_TYPE (decl)))
38190075Sobrien	emit_local_var (decl);
38290075Sobrien      else
38390075Sobrien	expand_anon_union_decl (decl, NULL_TREE,
38490075Sobrien				DECL_ANON_UNION_ELEMS (decl));
38590075Sobrien    }
38690075Sobrien  else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
38790075Sobrien    make_rtl_for_local_static (decl);
38890075Sobrien  else if (TREE_CODE (decl) == LABEL_DECL
38990075Sobrien	   && C_DECLARED_LABEL_FLAG (decl))
39090075Sobrien    declare_nonlocal_label (decl);
39190075Sobrien  else if (lang_expand_decl_stmt)
39290075Sobrien    (*lang_expand_decl_stmt) (t);
39390075Sobrien}
39490075Sobrien
39590075Sobrien/* Generate the RTL for T, which is an IF_STMT.  */
39690075Sobrien
39790075Sobrienvoid
39890075Sobriengenrtl_if_stmt (t)
39990075Sobrien     tree t;
40090075Sobrien{
40190075Sobrien  tree cond;
40290075Sobrien  genrtl_do_pushlevel ();
40390075Sobrien  cond = expand_cond (IF_COND (t));
40490075Sobrien  emit_line_note (input_filename, lineno);
40590075Sobrien  expand_start_cond (cond, 0);
40690075Sobrien  if (THEN_CLAUSE (t))
40790075Sobrien    expand_stmt (THEN_CLAUSE (t));
40890075Sobrien  if (ELSE_CLAUSE (t))
40990075Sobrien    {
41090075Sobrien      expand_start_else ();
41190075Sobrien      expand_stmt (ELSE_CLAUSE (t));
41290075Sobrien    }
41390075Sobrien  expand_end_cond ();
41490075Sobrien}
41590075Sobrien
41690075Sobrien/* Generate the RTL for T, which is a WHILE_STMT.  */
41790075Sobrien
41890075Sobrienvoid
41990075Sobriengenrtl_while_stmt (t)
42090075Sobrien     tree t;
42190075Sobrien{
42290075Sobrien  tree cond;
42390075Sobrien  emit_nop ();
42490075Sobrien  emit_line_note (input_filename, lineno);
42590075Sobrien  expand_start_loop (1);
42690075Sobrien  genrtl_do_pushlevel ();
42790075Sobrien
42890075Sobrien  cond = expand_cond (WHILE_COND (t));
42990075Sobrien  emit_line_note (input_filename, lineno);
43090075Sobrien  expand_exit_loop_top_cond (0, cond);
43190075Sobrien  genrtl_do_pushlevel ();
43290075Sobrien
43390075Sobrien  expand_stmt (WHILE_BODY (t));
43490075Sobrien
43590075Sobrien  expand_end_loop ();
43690075Sobrien}
43790075Sobrien
43890075Sobrien/* Generate the RTL for T, which is a DO_STMT.  */
43990075Sobrien
44090075Sobrienvoid
44190075Sobriengenrtl_do_stmt (t)
44290075Sobrien     tree t;
44390075Sobrien{
44490075Sobrien  tree cond = DO_COND (t);
44590075Sobrien
44690075Sobrien  /* Recognize the common special-case of do { ... } while (0) and do
44790075Sobrien     not emit the loop widgetry in this case.  In particular this
44890075Sobrien     avoids cluttering the rtl with dummy loop notes, which can affect
44990075Sobrien     alignment of adjacent labels.  */
45090075Sobrien  if (integer_zerop (cond))
45190075Sobrien    {
45290075Sobrien      expand_start_null_loop ();
45390075Sobrien      expand_stmt (DO_BODY (t));
45490075Sobrien      expand_end_null_loop ();
45590075Sobrien    }
45690075Sobrien  else
45790075Sobrien    {
45890075Sobrien      emit_nop ();
45990075Sobrien      emit_line_note (input_filename, lineno);
46090075Sobrien      expand_start_loop_continue_elsewhere (1);
46190075Sobrien
46290075Sobrien      expand_stmt (DO_BODY (t));
46390075Sobrien
46490075Sobrien      expand_loop_continue_here ();
46590075Sobrien      cond = expand_cond (cond);
46690075Sobrien      emit_line_note (input_filename, lineno);
46790075Sobrien      expand_exit_loop_if_false (0, cond);
46890075Sobrien      expand_end_loop ();
46990075Sobrien    }
47090075Sobrien}
47190075Sobrien
47290075Sobrien/* Build the node for a return statement and return it.  */
47390075Sobrien
47490075Sobrientree
47590075Sobrienbuild_return_stmt (expr)
47690075Sobrien     tree expr;
47790075Sobrien{
47890075Sobrien  return (build_stmt (RETURN_STMT, expr));
47990075Sobrien}
48090075Sobrien
48190075Sobrien/* Generate the RTL for STMT, which is a RETURN_STMT.  */
48290075Sobrien
48390075Sobrienvoid
48490075Sobriengenrtl_return_stmt (stmt)
48590075Sobrien     tree stmt;
48690075Sobrien{
48790075Sobrien  tree expr;
48890075Sobrien
48990075Sobrien  expr = RETURN_EXPR (stmt);
49090075Sobrien
49190075Sobrien  emit_line_note (input_filename, lineno);
49290075Sobrien  if (!expr)
49390075Sobrien    expand_null_return ();
49490075Sobrien  else
49590075Sobrien    {
49690075Sobrien      expand_start_target_temps ();
49790075Sobrien      expand_return (expr);
49890075Sobrien      expand_end_target_temps ();
49990075Sobrien    }
50090075Sobrien}
50190075Sobrien
50290075Sobrien/* Generate the RTL for T, which is a FOR_STMT.  */
50390075Sobrien
50490075Sobrienvoid
50590075Sobriengenrtl_for_stmt (t)
50690075Sobrien     tree t;
50790075Sobrien{
50890075Sobrien  tree cond;
50990075Sobrien  const char *saved_filename;
51090075Sobrien  int saved_lineno;
51190075Sobrien
51290075Sobrien  if (NEW_FOR_SCOPE_P (t))
51390075Sobrien    genrtl_do_pushlevel ();
51490075Sobrien
51590075Sobrien  expand_stmt (FOR_INIT_STMT (t));
51690075Sobrien
51790075Sobrien  /* Expand the initialization.  */
51890075Sobrien  emit_nop ();
51990075Sobrien  emit_line_note (input_filename, lineno);
52090075Sobrien  expand_start_loop_continue_elsewhere (1);
52190075Sobrien  genrtl_do_pushlevel ();
52290075Sobrien  cond = expand_cond (FOR_COND (t));
52390075Sobrien
52490075Sobrien  /* Save the filename and line number so that we expand the FOR_EXPR
52590075Sobrien     we can reset them back to the saved values.  */
52690075Sobrien  saved_filename = input_filename;
52790075Sobrien  saved_lineno = lineno;
52890075Sobrien
52990075Sobrien  /* Expand the condition.  */
53090075Sobrien  emit_line_note (input_filename, lineno);
53190075Sobrien  if (cond)
53290075Sobrien    expand_exit_loop_top_cond (0, cond);
53390075Sobrien
53490075Sobrien  /* Expand the body.  */
53590075Sobrien  genrtl_do_pushlevel ();
53690075Sobrien  expand_stmt (FOR_BODY (t));
53790075Sobrien
53890075Sobrien  /* Expand the increment expression.  */
53990075Sobrien  input_filename = saved_filename;
54090075Sobrien  lineno = saved_lineno;
54190075Sobrien  emit_line_note (input_filename, lineno);
54290075Sobrien  expand_loop_continue_here ();
54390075Sobrien  if (FOR_EXPR (t))
54490075Sobrien    genrtl_expr_stmt (FOR_EXPR (t));
54590075Sobrien  expand_end_loop ();
54690075Sobrien}
54790075Sobrien
54890075Sobrien/* Build a break statement node and return it.  */
54990075Sobrien
55090075Sobrientree
55190075Sobrienbuild_break_stmt ()
55290075Sobrien{
55390075Sobrien  return (build_stmt (BREAK_STMT));
55490075Sobrien}
55590075Sobrien
55690075Sobrien/* Generate the RTL for a BREAK_STMT.  */
55790075Sobrien
55890075Sobrienvoid
55990075Sobriengenrtl_break_stmt ()
56090075Sobrien{
56190075Sobrien  emit_line_note (input_filename, lineno);
56290075Sobrien  if ( ! expand_exit_something ())
56390075Sobrien    error ("break statement not within loop or switch");
56490075Sobrien}
56590075Sobrien
56690075Sobrien/* Build a continue statement node and return it.  */
56790075Sobrien
56890075Sobrientree
56990075Sobrienbuild_continue_stmt ()
57090075Sobrien{
57190075Sobrien  return (build_stmt (CONTINUE_STMT));
57290075Sobrien}
57390075Sobrien
57490075Sobrien/* Generate the RTL for a CONTINUE_STMT.  */
57590075Sobrien
57690075Sobrienvoid
57790075Sobriengenrtl_continue_stmt ()
57890075Sobrien{
57990075Sobrien  emit_line_note (input_filename, lineno);
58090075Sobrien  if (! expand_continue_loop (0))
58190075Sobrien    error ("continue statement not within a loop");
58290075Sobrien}
58390075Sobrien
58490075Sobrien/* Generate the RTL for T, which is a SCOPE_STMT.  */
58590075Sobrien
58690075Sobrienvoid
58790075Sobriengenrtl_scope_stmt (t)
58890075Sobrien     tree t;
58990075Sobrien{
59090075Sobrien  tree block = SCOPE_STMT_BLOCK (t);
59190075Sobrien
59290075Sobrien  if (!SCOPE_NO_CLEANUPS_P (t))
59390075Sobrien    {
59490075Sobrien      if (SCOPE_BEGIN_P (t))
59590075Sobrien	expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t), block);
59690075Sobrien      else if (SCOPE_END_P (t))
59790075Sobrien	expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0);
59890075Sobrien    }
59990075Sobrien  else if (!SCOPE_NULLIFIED_P (t))
60090075Sobrien    {
60190075Sobrien      rtx note = emit_note (NULL,
60290075Sobrien			    (SCOPE_BEGIN_P (t)
60390075Sobrien			     ? NOTE_INSN_BLOCK_BEG
60490075Sobrien			     : NOTE_INSN_BLOCK_END));
60590075Sobrien      NOTE_BLOCK (note) = block;
60690075Sobrien    }
60790075Sobrien
60890075Sobrien  /* If we're at the end of a scope that contains inlined nested
60990075Sobrien     functions, we have to decide whether or not to write them out.  */
61090075Sobrien  if (block && SCOPE_END_P (t))
61190075Sobrien    {
61290075Sobrien      tree fn;
61390075Sobrien
61490075Sobrien      for (fn = BLOCK_VARS (block); fn; fn = TREE_CHAIN (fn))
61590075Sobrien	{
61690075Sobrien	  if (TREE_CODE (fn) == FUNCTION_DECL
61790075Sobrien	      && DECL_CONTEXT (fn) == current_function_decl
61890075Sobrien	      && !TREE_ASM_WRITTEN (fn)
61990075Sobrien	      && TREE_ADDRESSABLE (fn))
62090075Sobrien	    {
62190075Sobrien	      push_function_context ();
62290075Sobrien	      output_inline_function (fn);
62390075Sobrien	      pop_function_context ();
62490075Sobrien	    }
62590075Sobrien	}
62690075Sobrien    }
62790075Sobrien}
62890075Sobrien
62990075Sobrien/* Generate the RTL for T, which is a SWITCH_STMT.  */
63090075Sobrien
63190075Sobrienvoid
63290075Sobriengenrtl_switch_stmt (t)
63390075Sobrien     tree t;
63490075Sobrien{
63590075Sobrien  tree cond;
63690075Sobrien  genrtl_do_pushlevel ();
63790075Sobrien
63890075Sobrien  cond = expand_cond (SWITCH_COND (t));
63990075Sobrien  if (cond == error_mark_node)
64090075Sobrien    /* The code is in error, but we don't want expand_end_case to
64190075Sobrien       crash.  */
64290075Sobrien    cond = boolean_false_node;
64390075Sobrien
64490075Sobrien  emit_line_note (input_filename, lineno);
64590075Sobrien  expand_start_case (1, cond, TREE_TYPE (cond), "switch statement");
64690075Sobrien  expand_stmt (SWITCH_BODY (t));
64790075Sobrien  expand_end_case (cond);
64890075Sobrien}
64990075Sobrien
65090075Sobrien/* Create a CASE_LABEL tree node and return it.  */
65190075Sobrien
65290075Sobrientree
65390075Sobrienbuild_case_label (low_value, high_value, label_decl)
65490075Sobrien     tree low_value;
65590075Sobrien     tree high_value;
65690075Sobrien     tree label_decl;
65790075Sobrien{
65890075Sobrien  return build_stmt (CASE_LABEL, low_value, high_value, label_decl);
65990075Sobrien}
66090075Sobrien
66190075Sobrien
66290075Sobrien/* Generate the RTL for a CASE_LABEL.  */
66390075Sobrien
66490075Sobrienvoid
66590075Sobriengenrtl_case_label (case_label)
66690075Sobrien     tree case_label;
66790075Sobrien{
66890075Sobrien  tree duplicate;
66990075Sobrien  tree cleanup;
67090075Sobrien
67190075Sobrien  cleanup = last_cleanup_this_contour ();
67290075Sobrien  if (cleanup)
67390075Sobrien    {
67490075Sobrien      static int explained = 0;
67590075Sobrien      warning_with_decl (TREE_PURPOSE (cleanup),
67690075Sobrien			 "destructor needed for `%#D'");
67790075Sobrien      warning ("where case label appears here");
67890075Sobrien      if (!explained)
67990075Sobrien	{
68090075Sobrien	  warning ("(enclose actions of previous case statements requiring destructors in their own scope.)");
68190075Sobrien	  explained = 1;
68290075Sobrien	}
68390075Sobrien    }
68490075Sobrien
68590075Sobrien  add_case_node (CASE_LOW (case_label), CASE_HIGH (case_label),
68690075Sobrien		 CASE_LABEL_DECL (case_label), &duplicate);
68790075Sobrien}
68890075Sobrien
68990075Sobrien/* Generate the RTL for T, which is a COMPOUND_STMT.  */
69090075Sobrien
69190075Sobrienvoid
69290075Sobriengenrtl_compound_stmt (t)
69390075Sobrien    tree t;
69490075Sobrien{
69590075Sobrien#ifdef ENABLE_CHECKING
69690075Sobrien  struct nesting *n = current_nesting_level ();
69790075Sobrien#endif
69890075Sobrien
69990075Sobrien  expand_stmt (COMPOUND_BODY (t));
70090075Sobrien
70190075Sobrien#ifdef ENABLE_CHECKING
70290075Sobrien  /* Make sure that we've pushed and popped the same number of levels.  */
70390075Sobrien  if (!COMPOUND_STMT_NO_SCOPE (t) && n != current_nesting_level ())
70490075Sobrien    abort ();
70590075Sobrien#endif
70690075Sobrien}
70790075Sobrien
70890075Sobrien/* Generate the RTL for an ASM_STMT.  */
70990075Sobrien
71090075Sobrienvoid
71190075Sobriengenrtl_asm_stmt (cv_qualifier, string, output_operands,
71290075Sobrien		 input_operands, clobbers, asm_input_p)
71390075Sobrien     tree cv_qualifier;
71490075Sobrien     tree string;
71590075Sobrien     tree output_operands;
71690075Sobrien     tree input_operands;
71790075Sobrien     tree clobbers;
71890075Sobrien     int asm_input_p;
71990075Sobrien{
72090075Sobrien  if (cv_qualifier != NULL_TREE
72190075Sobrien      && cv_qualifier != ridpointers[(int) RID_VOLATILE])
72290075Sobrien    {
72390075Sobrien      warning ("%s qualifier ignored on asm",
72490075Sobrien	       IDENTIFIER_POINTER (cv_qualifier));
72590075Sobrien      cv_qualifier = NULL_TREE;
72690075Sobrien    }
72790075Sobrien
72890075Sobrien  emit_line_note (input_filename, lineno);
72990075Sobrien  if (asm_input_p)
73090075Sobrien    expand_asm (string);
73190075Sobrien  else
73290075Sobrien    c_expand_asm_operands (string, output_operands, input_operands,
73390075Sobrien			   clobbers, cv_qualifier != NULL_TREE,
73490075Sobrien			   input_filename, lineno);
73590075Sobrien}
73690075Sobrien
73790075Sobrien/* Generate the RTL for a DECL_CLEANUP.  */
73890075Sobrien
73990075Sobrienvoid
74090075Sobriengenrtl_decl_cleanup (decl, cleanup)
74190075Sobrien     tree decl;
74290075Sobrien     tree cleanup;
74390075Sobrien{
74490075Sobrien  if (!decl || (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node))
74590075Sobrien    expand_decl_cleanup (decl, cleanup);
74690075Sobrien}
74790075Sobrien
74890075Sobrien/* We're about to expand T, a statement.  Set up appropriate context
74990075Sobrien   for the substitution.  */
75090075Sobrien
75190075Sobrienvoid
75290075Sobrienprep_stmt (t)
75390075Sobrien     tree t;
75490075Sobrien{
75590075Sobrien  if (!STMT_LINENO_FOR_FN_P (t))
75690075Sobrien    lineno = STMT_LINENO (t);
75790075Sobrien  current_stmt_tree ()->stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t);
75890075Sobrien}
75990075Sobrien
76090075Sobrien/* Generate the RTL for the statement T, its substatements, and any
76190075Sobrien   other statements at its nesting level.  */
76290075Sobrien
76390075Sobrienvoid
76490075Sobrienexpand_stmt (t)
76590075Sobrien     tree t;
76690075Sobrien{
76790075Sobrien  while (t && t != error_mark_node)
76890075Sobrien    {
76990075Sobrien      int saved_stmts_are_full_exprs_p;
77090075Sobrien
77190075Sobrien      /* Set up context appropriately for handling this statement.  */
77290075Sobrien      saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
77390075Sobrien      prep_stmt (t);
77490075Sobrien
77590075Sobrien      switch (TREE_CODE (t))
77690075Sobrien	{
77790075Sobrien	case FILE_STMT:
77890075Sobrien	  input_filename = FILE_STMT_FILENAME (t);
77990075Sobrien	  break;
78090075Sobrien
78190075Sobrien	case RETURN_STMT:
78290075Sobrien	  genrtl_return_stmt (t);
78390075Sobrien	  break;
78490075Sobrien
78590075Sobrien	case EXPR_STMT:
78690075Sobrien	  genrtl_expr_stmt_value (EXPR_STMT_EXPR (t), TREE_ADDRESSABLE (t),
78790075Sobrien				  TREE_CHAIN (t) == NULL
78890075Sobrien				  || (TREE_CODE (TREE_CHAIN (t)) == SCOPE_STMT
78990075Sobrien				      && TREE_CHAIN (TREE_CHAIN (t)) == NULL));
79090075Sobrien	  break;
79190075Sobrien
79290075Sobrien	case DECL_STMT:
79390075Sobrien	  genrtl_decl_stmt (t);
79490075Sobrien	  break;
79590075Sobrien
79690075Sobrien	case FOR_STMT:
79790075Sobrien	  genrtl_for_stmt (t);
79890075Sobrien	  break;
79990075Sobrien
80090075Sobrien	case WHILE_STMT:
80190075Sobrien	  genrtl_while_stmt (t);
80290075Sobrien	  break;
80390075Sobrien
80490075Sobrien	case DO_STMT:
80590075Sobrien	  genrtl_do_stmt (t);
80690075Sobrien	  break;
80790075Sobrien
80890075Sobrien	case IF_STMT:
80990075Sobrien	  genrtl_if_stmt (t);
81090075Sobrien	  break;
81190075Sobrien
81290075Sobrien	case COMPOUND_STMT:
81390075Sobrien	  genrtl_compound_stmt (t);
81490075Sobrien	  break;
81590075Sobrien
81690075Sobrien	case BREAK_STMT:
81790075Sobrien	  genrtl_break_stmt ();
81890075Sobrien	  break;
81990075Sobrien
82090075Sobrien	case CONTINUE_STMT:
82190075Sobrien	  genrtl_continue_stmt ();
82290075Sobrien	  break;
82390075Sobrien
82490075Sobrien	case SWITCH_STMT:
82590075Sobrien	  genrtl_switch_stmt (t);
82690075Sobrien	  break;
82790075Sobrien
82890075Sobrien	case CASE_LABEL:
82990075Sobrien	  genrtl_case_label (t);
83090075Sobrien	  break;
83190075Sobrien
83290075Sobrien	case LABEL_STMT:
83390075Sobrien	  expand_label (LABEL_STMT_LABEL (t));
83490075Sobrien	  break;
83590075Sobrien
83690075Sobrien	case GOTO_STMT:
83790075Sobrien	  genrtl_goto_stmt (GOTO_DESTINATION (t));
83890075Sobrien	  break;
83990075Sobrien
84090075Sobrien	case ASM_STMT:
84190075Sobrien	  genrtl_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t),
84290075Sobrien			   ASM_OUTPUTS (t), ASM_INPUTS (t),
84390075Sobrien			   ASM_CLOBBERS (t), ASM_INPUT_P (t));
84490075Sobrien	  break;
84590075Sobrien
84690075Sobrien	case SCOPE_STMT:
84790075Sobrien	  genrtl_scope_stmt (t);
84890075Sobrien	  break;
84990075Sobrien
85090075Sobrien	default:
85190075Sobrien	  if (lang_expand_stmt)
85290075Sobrien	    (*lang_expand_stmt) (t);
85390075Sobrien	  else
85490075Sobrien	    abort ();
85590075Sobrien	  break;
85690075Sobrien	}
85790075Sobrien
85890075Sobrien      /* Restore saved state.  */
85990075Sobrien      current_stmt_tree ()->stmts_are_full_exprs_p
86090075Sobrien	= saved_stmts_are_full_exprs_p;
86190075Sobrien
86290075Sobrien      /* Go on to the next statement in this scope.  */
86390075Sobrien      t = TREE_CHAIN (t);
86490075Sobrien    }
86590075Sobrien}
866