building RTL. These routines are used both during actual parsing
and during the instantiation of template functions.
- Copyright (C) 1998 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
Written by Mark Mitchell (mmitchell@usa.net) based on code found
formerly in parse.y and pt.c.
#include "except.h"
#include "lex.h"
#include "toplev.h"
+#include "flags.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
parsing into this file; that will make implementing the new parser
much easier since it will be able to make use of these routines. */
+static tree expand_cond PROTO((tree));
+static tree maybe_convert_cond PROTO((tree));
+
/* When parsing a template, LAST_TREE contains the last statement
parsed. These are chained together through the TREE_CHAIN field,
but often need to be re-organized since the parse is performed
bottom-up. This macro makes LAST_TREE the indicated SUBSTMT of
STMT. */
-#define RECHAIN_STMTS(stmt, substmt, last) \
- do { \
- substmt = last; \
- TREE_CHAIN (stmt) = NULL_TREE; \
- last_tree = stmt; \
+#define RECHAIN_STMTS(stmt, substmt) \
+ do { \
+ substmt = TREE_CHAIN (stmt); \
+ TREE_CHAIN (stmt) = NULL_TREE; \
+ last_tree = stmt; \
+ } while (0)
+
+/* Finish processing the COND, the SUBSTMT condition for STMT. */
+
+#define FINISH_COND(cond, stmt, substmt) \
+ do { \
+ if (last_tree != stmt) \
+ { \
+ RECHAIN_STMTS (stmt, substmt); \
+ if (!processing_template_decl) \
+ { \
+ cond = build_tree_list (substmt, cond); \
+ substmt = cond; \
+ } \
+ } \
+ else \
+ substmt = cond; \
} while (0)
+
+/* T is a statement. Add it to the statement-tree. */
+
+void
+add_tree (t)
+ tree t;
+{
+ /* Add T to the statement-tree. */
+ last_tree = TREE_CHAIN (last_tree) = t;
+
+ /* When we expand a statement-tree, we must know whether or not the
+ statements are full-expresions. We record that fact here. */
+ if (building_stmt_tree ())
+ STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p;
+}
+
+/* COND is the condition-expression for an if, while, etc.,
+ statement. Convert it to a boolean value, if appropriate. */
+
+static tree
+maybe_convert_cond (cond)
+ tree cond;
+{
+ /* Empty conditions remain empty. */
+ if (!cond)
+ return NULL_TREE;
-#define RECHAIN_STMTS_FROM_LAST(stmt, substmt) \
- RECHAIN_STMTS (stmt, substmt, last_tree)
+ /* Wait until we instantiate templates before doing conversion. */
+ if (processing_template_decl)
+ return cond;
-#define RECHAIN_STMTS_FROM_CHAIN(stmt, substmt) \
- RECHAIN_STMTS (stmt, substmt, TREE_CHAIN (stmt))
+ /* Do the conversion. */
+ cond = convert_from_reference (cond);
+ return condition_conversion (cond);
+}
/* Finish an expression-statement, whose EXPRESSION is as indicated. */
{
if (expr != NULL_TREE)
{
- if (!processing_template_decl)
+ if (building_stmt_tree ())
+ add_tree (build_min_nt (EXPR_STMT, expr));
+ else
{
emit_line_note (input_filename, lineno);
/* Do default conversion if safe and possibly important,
in case within ({...}). */
- if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
- && lvalue_p (expr))
- || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
+ if (!stmts_are_full_exprs_p &&
+ ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
+ && lvalue_p (expr))
+ || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE))
expr = default_conversion (expr);
+
+ if (stmts_are_full_exprs_p)
+ expand_start_target_temps ();
+
+ cplus_expand_expr_stmt (expr);
+
+ if (stmts_are_full_exprs_p)
+ {
+ expand_end_target_temps ();
+ clear_momentary ();
+ }
}
-
- cplus_expand_expr_stmt (expr);
- clear_momentary ();
}
finish_stmt ();
+
+ /* This was an expression-statement, so we save the type of the
+ expression. */
+ last_expr_type = expr ? TREE_TYPE (expr) : NULL_TREE;
}
/* Begin an if-statement. Returns a newly created IF_STMT if
{
tree r;
- if (processing_template_decl)
+ do_pushlevel ();
+
+ if (building_stmt_tree ())
{
r = build_min_nt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
add_tree (r);
else
r = NULL_TREE;
- do_pushlevel ();
-
return r;
}
tree cond;
tree if_stmt;
{
- if (processing_template_decl)
- {
- if (last_tree != if_stmt)
- RECHAIN_STMTS_FROM_LAST (if_stmt, IF_COND (if_stmt));
- else
- IF_COND (if_stmt) = cond;
- }
+ cond = maybe_convert_cond (cond);
+
+ if (building_stmt_tree ())
+ FINISH_COND (cond, if_stmt, IF_COND (if_stmt));
else
{
emit_line_note (input_filename, lineno);
- expand_start_cond (condition_conversion (cond), 0);
+ expand_start_cond (cond, 0);
}
}
finish_then_clause (if_stmt)
tree if_stmt;
{
- if (processing_template_decl)
+ if (building_stmt_tree ())
{
- RECHAIN_STMTS_FROM_CHAIN (if_stmt,
- THEN_CLAUSE (if_stmt));
+ RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
last_tree = if_stmt;
return if_stmt;
}
void
begin_else_clause ()
{
- if (!processing_template_decl)
+ if (!building_stmt_tree ())
expand_start_else ();
}
finish_else_clause (if_stmt)
tree if_stmt;
{
- if (processing_template_decl)
- RECHAIN_STMTS_FROM_CHAIN (if_stmt, ELSE_CLAUSE (if_stmt));
+ if (building_stmt_tree ())
+ RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
}
/* Finsh an if-statement. */
void
finish_if_stmt ()
{
- if (!processing_template_decl)
+ if (!building_stmt_tree ())
expand_end_cond ();
do_poplevel ();
{
tree r;
- if (processing_template_decl)
+ if (building_stmt_tree ())
{
r = build_min_nt (WHILE_STMT, NULL_TREE, NULL_TREE);
add_tree (r);
tree cond;
tree while_stmt;
{
- if (processing_template_decl)
- {
- if (last_tree != while_stmt)
- RECHAIN_STMTS_FROM_LAST (while_stmt,
- WHILE_COND (while_stmt));
- else
- TREE_OPERAND (while_stmt, 0) = cond;
- }
+ cond = maybe_convert_cond (cond);
+
+ if (building_stmt_tree ())
+ FINISH_COND (cond, while_stmt, WHILE_COND (while_stmt));
else
{
emit_line_note (input_filename, lineno);
- expand_exit_loop_if_false (0, condition_conversion (cond));
+ expand_exit_loop_if_false (0, cond);
}
/* If COND wasn't a declaration, clear out the
{
do_poplevel ();
- if (processing_template_decl)
- RECHAIN_STMTS_FROM_CHAIN (while_stmt, WHILE_BODY (while_stmt));
+ if (building_stmt_tree ())
+ RECHAIN_STMTS (while_stmt, WHILE_BODY (while_stmt));
else
expand_end_loop ();
finish_stmt ();
tree
begin_do_stmt ()
{
- if (processing_template_decl)
+ if (building_stmt_tree ())
{
tree r = build_min_nt (DO_STMT, NULL_TREE, NULL_TREE);
add_tree (r);
finish_do_body (do_stmt)
tree do_stmt;
{
- if (processing_template_decl)
- RECHAIN_STMTS_FROM_CHAIN (do_stmt, DO_BODY (do_stmt));
+ if (building_stmt_tree ())
+ RECHAIN_STMTS (do_stmt, DO_BODY (do_stmt));
else
expand_loop_continue_here ();
}
tree cond;
tree do_stmt;
{
- if (processing_template_decl)
+ cond = maybe_convert_cond (cond);
+
+ if (building_stmt_tree ())
DO_COND (do_stmt) = cond;
else
{
emit_line_note (input_filename, lineno);
- expand_exit_loop_if_false (0, condition_conversion (cond));
+ expand_exit_loop_if_false (0, cond);
expand_end_loop ();
}
finish_return_stmt (expr)
tree expr;
{
- emit_line_note (input_filename, lineno);
- c_expand_return (expr);
+ if (doing_semantic_analysis_p () && !processing_template_decl)
+ expr = check_return_expr (expr);
+
+ if (doing_semantic_analysis_p () && !processing_template_decl)
+ {
+ if (DECL_CONSTRUCTOR_P (current_function_decl) && ctor_label)
+ {
+ /* Even returns without a value in a constructor must return
+ `this'. We accomplish this by sending all returns in a
+ constructor to the CTOR_LABEL; finish_function emits code to
+ return a value there. When we finally generate the real
+ return statement, CTOR_LABEL is no longer set, and we fall
+ through into the normal return-processing code below. */
+ finish_goto_stmt (ctor_label);
+ return;
+ }
+ else if (DECL_DESTRUCTOR_P (current_function_decl))
+ {
+ /* Similarly, all destructors must run destructors for
+ base-classes before returning. So, all returns in a
+ destructor get sent to the DTOR_LABEL; finsh_function emits
+ code to return a value there. */
+ finish_goto_stmt (dtor_label);
+ return;
+ }
+ }
+
+ if (building_stmt_tree ())
+ add_tree (build_min_nt (RETURN_STMT, expr));
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ c_expand_return (expr);
+ }
+
finish_stmt ();
}
{
tree r;
- if (processing_template_decl)
+ if (building_stmt_tree ())
{
r = build_min_nt (FOR_STMT, NULL_TREE, NULL_TREE,
NULL_TREE, NULL_TREE);
finish_for_init_stmt (for_stmt)
tree for_stmt;
{
- if (processing_template_decl)
+ if (building_stmt_tree ())
{
if (last_tree != for_stmt)
- RECHAIN_STMTS_FROM_CHAIN (for_stmt, FOR_INIT_STMT (for_stmt));
+ RECHAIN_STMTS (for_stmt, FOR_INIT_STMT (for_stmt));
}
else
{
tree cond;
tree for_stmt;
{
- if (processing_template_decl)
- {
- if (last_tree != for_stmt)
- RECHAIN_STMTS_FROM_LAST (for_stmt, FOR_COND (for_stmt));
- else
- FOR_COND (for_stmt) = cond;
- }
+ cond = maybe_convert_cond (cond);
+
+ if (building_stmt_tree ())
+ FINISH_COND (cond, for_stmt, FOR_COND (for_stmt));
else
{
emit_line_note (input_filename, lineno);
if (cond)
- expand_exit_loop_if_false (0, condition_conversion (cond));
+ expand_exit_loop_if_false (0, cond);
}
/* If the cond wasn't a declaration, clear out the
tree expr;
tree for_stmt;
{
- if (processing_template_decl)
+ if (building_stmt_tree ())
FOR_EXPR (for_stmt) = expr;
/* Don't let the tree nodes for EXPR be discarded
/* Pop the scope for the body of the loop. */
do_poplevel ();
- if (processing_template_decl)
- RECHAIN_STMTS_FROM_CHAIN (for_stmt, FOR_BODY (for_stmt));
+ if (building_stmt_tree ())
+ RECHAIN_STMTS (for_stmt, FOR_BODY (for_stmt));
else
{
emit_line_note (input_filename, lineno);
expand_loop_continue_here ();
if (expr)
- cplus_expand_expr_stmt (expr);
+ finish_expr_stmt (expr);
expand_end_loop ();
}
finish_break_stmt ()
{
emit_line_note (input_filename, lineno);
- if (processing_template_decl)
+ if (building_stmt_tree ())
add_tree (build_min_nt (BREAK_STMT));
else if ( ! expand_exit_something ())
cp_error ("break statement not within loop or switch");
finish_continue_stmt ()
{
emit_line_note (input_filename, lineno);
- if (processing_template_decl)
+ if (building_stmt_tree ())
add_tree (build_min_nt (CONTINUE_STMT));
else if (! expand_continue_loop (0))
cp_error ("continue statement not within a loop");
}
-/* Begin a switch-statement. */
-
-void
-begin_switch_stmt ()
-{
- do_pushlevel ();
-}
-
-/* Finish the cond of a switch-statement. Returns a new
- SWITCH_STMT if appropriate. */
+/* Begin a switch-statement. Returns a new SWITCH_STMT if
+ appropriate. */
tree
-finish_switch_cond (cond)
- tree cond;
+begin_switch_stmt ()
{
tree r;
- if (processing_template_decl)
+ if (building_stmt_tree ())
{
- r = build_min_nt (SWITCH_STMT, cond, NULL_TREE);
+ r = build_min_nt (SWITCH_STMT, NULL_TREE, NULL_TREE);
add_tree (r);
}
else
+ r = NULL_TREE;
+
+ do_pushlevel ();
+
+ return r;
+}
+
+/* Finish the cond of a switch-statement. */
+
+void
+finish_switch_cond (cond, switch_stmt)
+ tree cond;
+ tree switch_stmt;
+{
+ if (building_stmt_tree ())
+ FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt));
+ else if (cond != error_mark_node)
{
emit_line_note (input_filename, lineno);
c_expand_start_case (cond);
- r = NULL_TREE;
}
+ else
+ /* The code is in error, but we don't want expand_end_case to
+ crash. */
+ c_expand_start_case (boolean_false_node);
+
push_switch ();
/* Don't let the tree nodes for COND be discarded by
clear_momentary during the parsing of the next stmt. */
push_momentary ();
-
- return r;
}
/* Finish the body of a switch-statement, which may be given by
tree cond;
tree switch_stmt;
{
- if (processing_template_decl)
- RECHAIN_STMTS_FROM_CHAIN (switch_stmt, SWITCH_BODY (switch_stmt));
+ if (building_stmt_tree ())
+ RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt));
else
expand_end_case (cond);
pop_momentary ();
tree low_value;
tree high_value;
{
+ if (building_stmt_tree ())
+ {
+ /* Add a representation for the case label to the statement
+ tree. */
+ add_tree (build_min_nt (CASE_LABEL, low_value, high_value));
+ /* And warn about crossing initializations, etc. */
+ if (!processing_template_decl)
+ define_case_label ();
+ return;
+ }
+
do_case (low_value, high_value);
}
-
/* Finish a goto-statement. */
void
finish_goto_stmt (destination)
tree destination;
{
- if (processing_template_decl)
+ if (TREE_CODE (destination) == IDENTIFIER_NODE)
+ destination = lookup_label (destination);
+
+ /* We warn about unused labels with -Wunused. That means we have to
+ mark the used labels as used. */
+ if (TREE_CODE (destination) == LABEL_DECL)
+ TREE_USED (destination) = 1;
+
+ if (building_stmt_tree ())
add_tree (build_min_nt (GOTO_STMT, destination));
else
{
emit_line_note (input_filename, lineno);
- if (TREE_CODE (destination) == IDENTIFIER_NODE)
+ if (TREE_CODE (destination) == LABEL_DECL)
{
- tree decl = lookup_label (destination);
- TREE_USED (decl) = 1;
- expand_goto (decl);
+ label_rtx (destination);
+ expand_goto (destination);
}
else
expand_computed_goto (destination);
tree
begin_try_block ()
{
- if (processing_template_decl)
+ if (building_stmt_tree ())
{
tree r = build_min_nt (TRY_BLOCK, NULL_TREE,
NULL_TREE);
}
}
+/* Likewise, for a function-try-block. */
+
+tree
+begin_function_try_block ()
+{
+ if (building_stmt_tree ())
+ {
+ tree r = build_min_nt (TRY_BLOCK, NULL_TREE,
+ NULL_TREE);
+ FN_TRY_BLOCK_P (r) = 1;
+ add_tree (r);
+ return r;
+ }
+ else
+ {
+ if (! current_function_parms_stored)
+ store_parm_decls ();
+ expand_start_early_try_stmts ();
+ return NULL_TREE;
+ }
+}
+
/* Finish a try-block, which may be given by TRY_BLOCK. */
void
finish_try_block (try_block)
tree try_block;
{
- if (processing_template_decl)
- RECHAIN_STMTS_FROM_LAST (try_block, TRY_STMTS (try_block));
+ if (building_stmt_tree ())
+ RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
else
+ expand_start_all_catch ();
+}
+
+/* Finish the body of a cleanup try-block, which may be given by
+ TRY_BLOCK. */
+
+void
+finish_cleanup_try_block (try_block)
+ tree try_block;
+{
+ if (building_stmt_tree ())
+ RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
+}
+
+/* Finish an implicitly generated try-block, with a cleanup is given
+ by CLEANUP. */
+
+void
+finish_cleanup (cleanup, try_block)
+ tree cleanup;
+ tree try_block;
+{
+ if (building_stmt_tree ())
{
- expand_start_all_catch ();
+ TRY_HANDLERS (try_block) = cleanup;
+ CLEANUP_P (try_block) = 1;
}
+ else
+ expand_eh_region_end (protect_with_terminate (cleanup));
+}
+
+/* Likewise, for a function-try-block. */
+
+void
+finish_function_try_block (try_block)
+ tree try_block;
+{
+ if (building_stmt_tree ())
+ {
+ if (TREE_CHAIN (try_block)
+ && TREE_CODE (TREE_CHAIN (try_block)) == CTOR_INITIALIZER)
+ {
+ /* Chain the compound statement after the CTOR_INITIALIZER. */
+ TREE_CHAIN (TREE_CHAIN (try_block)) = last_tree;
+ /* And make the CTOR_INITIALIZER the body of the try-block. */
+ RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
+ }
+ else
+ RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
+ }
+ else
+ {
+ end_protect_partials ();
+ expand_start_all_catch ();
+ }
+
+ in_function_try_handler = 1;
}
/* Finish a handler-sequence for a try-block, which may be given by
finish_handler_sequence (try_block)
tree try_block;
{
- if (processing_template_decl)
- RECHAIN_STMTS_FROM_CHAIN (try_block, TRY_HANDLERS (try_block));
+ if (building_stmt_tree ())
+ RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
else
- {
- expand_end_all_catch ();
- }
+ expand_end_all_catch ();
+}
+
+/* Likewise, for a function-try-block. */
+
+void
+finish_function_handler_sequence (try_block)
+ tree try_block;
+{
+ in_function_try_handler = 0;
+
+ if (building_stmt_tree ())
+ RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
+ else
+ expand_end_all_catch ();
}
/* Begin a handler. Returns a HANDLER if appropriate. */
{
tree r;
- if (processing_template_decl)
+ if (building_stmt_tree ())
{
r = build_min_nt (HANDLER, NULL_TREE, NULL_TREE);
add_tree (r);
}
/* Finish the handler-parameters for a handler, which may be given by
- HANDLER. */
+ HANDLER. DECL is the declaration for the catch parameter, or NULL
+ if this is a `catch (...)' clause. */
-void
-finish_handler_parms (handler)
+tree
+finish_handler_parms (decl, handler)
+ tree decl;
tree handler;
{
+ tree blocks = NULL_TREE;
+
if (processing_template_decl)
- RECHAIN_STMTS_FROM_CHAIN (handler, HANDLER_PARMS (handler));
+ {
+ if (decl)
+ {
+ decl = pushdecl (decl);
+ decl = push_template_decl (decl);
+ add_decl_stmt (decl);
+ RECHAIN_STMTS (handler, HANDLER_PARMS (handler));
+ }
+ }
+ else if (building_stmt_tree ())
+ blocks = expand_start_catch_block (decl);
+
+ return blocks;
}
-/* Finish a handler, which may be given by HANDLER. */
+/* Note the beginning of a handler for TYPE. This function is called
+ at the point to which control should be transferred when an
+ appropriately-typed exception is thrown. */
void
-finish_handler (handler)
- tree handler;
+begin_catch_block (type)
+ tree type;
{
- if (processing_template_decl)
- RECHAIN_STMTS_FROM_CHAIN (handler, HANDLER_BODY (handler));
+ if (building_stmt_tree ())
+ add_tree (build (START_CATCH_STMT, type));
else
- expand_end_catch_block ();
+ start_catch_handler (type);
+}
+
+/* Finish a handler, which may be given by HANDLER. The BLOCKs are
+ the return value from the matching call to finish_handler_parms. */
+
+void
+finish_handler (blocks, handler)
+ tree blocks;
+ tree handler;
+{
+ if (!processing_template_decl)
+ {
+ if (building_stmt_tree ())
+ expand_end_catch_block (blocks);
+
+ if (!building_stmt_tree ())
+ {
+ /* Fall to outside the try statement when done executing
+ handler and we fall off end of handler. This is jump
+ Lresume in the documentation. */
+ expand_goto (top_label_entry (&caught_return_label_stack));
+ end_catch_handler ();
+ }
+ }
+
+ if (building_stmt_tree ())
+ RECHAIN_STMTS (handler, HANDLER_BODY (handler));
do_poplevel ();
}
{
tree r;
- if (processing_template_decl)
+ if (building_stmt_tree ())
{
r = build_min_nt (COMPOUND_STMT, NULL_TREE);
add_tree (r);
else
r = NULL_TREE;
+ last_expr_type = NULL_TREE;
+
if (!has_no_scope)
do_pushlevel ();
+ else
+ /* Normally, we try hard to keep the BLOCK for a
+ statement-expression. But, if it's a statement-expression with
+ a scopeless block, there's nothing to keep, and we don't want
+ to accidentally keep a block *inside* the scopeless block. */
+ keep_next_level (0);
+
+ /* If this is the outermost block of the function, declare the
+ variables __FUNCTION__, __PRETTY_FUNCTION__, and so forth. */
+ if (!current_function_name_declared
+ && !processing_template_decl
+ && !has_no_scope)
+ {
+ declare_function_name ();
+ current_function_name_declared = 1;
+ }
return r;
}
tree compound_stmt;
{
tree r;
+ tree t;
if (!has_no_scope)
r = do_poplevel ();
else
r = NULL_TREE;
- if (processing_template_decl)
- RECHAIN_STMTS_FROM_CHAIN (compound_stmt,
- COMPOUND_BODY (compound_stmt));
+ if (building_stmt_tree ())
+ RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_stmt));
+ /* When we call finish_stmt we will lose LAST_EXPR_TYPE. But, since
+ the precise purpose of that variable is store the type of the
+ last expression statement within the last compound statement, we
+ preserve the value. */
+ t = last_expr_type;
finish_stmt ();
+ last_expr_type = t;
return r;
}
void
finish_asm_stmt (cv_qualifier, string, output_operands,
- input_operands, clobbers)
+ input_operands, clobbers)
tree cv_qualifier;
tree string;
tree output_operands;
tree clobbers;
{
if (TREE_CHAIN (string))
- string = combine_strings (string);
+ {
+ if (building_stmt_tree ())
+ /* We need to build the combined string on the permanent
+ obstack so that we can use it during instantiations. */
+ push_permanent_obstack ();
- if (processing_template_decl)
+ string = combine_strings (string);
+
+ if (building_stmt_tree ())
+ pop_obstacks ();
+ }
+
+ if (cv_qualifier != NULL_TREE
+ && cv_qualifier != ridpointers[(int) RID_VOLATILE])
+ {
+ cp_warning ("%s qualifier ignored on asm",
+ IDENTIFIER_POINTER (cv_qualifier));
+ cv_qualifier = NULL_TREE;
+ }
+
+ if (building_stmt_tree ())
{
tree r = build_min_nt (ASM_STMT, cv_qualifier, string,
output_operands, input_operands,
{
emit_line_note (input_filename, lineno);
if (output_operands != NULL_TREE || input_operands != NULL_TREE
- || clobbers != NULL_TREE)
+ || clobbers != NULL_TREE)
{
- if (cv_qualifier != NULL_TREE
- && cv_qualifier != ridpointers[(int) RID_VOLATILE])
- cp_warning ("%s qualifier ignored on asm",
- IDENTIFIER_POINTER (cv_qualifier));
-
+ tree t;
+
+ for (t = input_operands; t; t = TREE_CHAIN (t))
+ TREE_VALUE (t) = decay_conversion (TREE_VALUE (t));
+
c_expand_asm_operands (string, output_operands,
input_operands,
clobbers,
- cv_qualifier
- == ridpointers[(int) RID_VOLATILE],
+ cv_qualifier != NULL_TREE,
input_filename, lineno);
}
else
+ expand_asm (string);
+
+ finish_stmt ();
+ }
+}
+
+/* Finish a label with the indicated NAME. */
+
+void
+finish_label_stmt (name)
+ tree name;
+{
+ tree decl = define_label (input_filename, lineno, name);
+
+ if (building_stmt_tree ())
+ add_tree (build_min_nt (LABEL_STMT, decl));
+ else if (decl)
+ expand_label (decl);
+}
+
+/* Finish a series of declarations for local labels. G++ allows users
+ to declare "local" labels, i.e., labels with scope. This extension
+ is useful when writing code involving statement-expressions. */
+
+void
+finish_label_decl (name)
+ tree name;
+{
+ tree decl = declare_local_label (name);
+ if (building_stmt_tree ())
+ add_decl_stmt (decl);
+}
+
+/* Create a declaration statement for the declaration given by the
+ DECL. */
+
+void
+add_decl_stmt (decl)
+ tree decl;
+{
+ tree decl_stmt;
+
+ /* We need the type to last until instantiation time. */
+ decl_stmt = build_min_nt (DECL_STMT, decl);
+ add_tree (decl_stmt);
+}
+
+/* We're in a constructor, and have just constructed a a subobject of
+ *THIS. CLEANUP is code to run if an exception is thrown before the
+ end of the current function is reached. */
+
+void
+finish_subobject (cleanup)
+ tree cleanup;
+{
+ if (building_stmt_tree ())
+ {
+ tree r = build_min_nt (SUBOBJECT, cleanup);
+ add_tree (r);
+ }
+ else
+ add_partial_entry (cleanup);
+}
+
+/* When DECL goes out of scope, make sure that CLEANUP is executed. */
+
+void
+finish_decl_cleanup (decl, cleanup)
+ tree decl;
+ tree cleanup;
+{
+ if (building_stmt_tree ())
+ add_tree (build_min_nt (CLEANUP_STMT, decl, cleanup));
+ else if (!decl
+ || (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node))
+ expand_decl_cleanup (decl, cleanup);
+}
+
+/* Bind a name and initialization to the return value of
+ the current function. */
+
+void
+finish_named_return_value (return_id, init)
+ tree return_id, init;
+{
+ tree decl = DECL_RESULT (current_function_decl);
+
+ if (pedantic)
+ /* Give this error as many times as there are occurrences,
+ so that users can use Emacs compilation buffers to find
+ and fix all such places. */
+ pedwarn ("ANSI C++ does not permit named return values");
+
+ if (return_id != NULL_TREE)
+ {
+ if (DECL_NAME (decl) == NULL_TREE)
+ {
+ DECL_NAME (decl) = return_id;
+ DECL_ASSEMBLER_NAME (decl) = return_id;
+ }
+ else
{
- if (cv_qualifier != NULL_TREE)
- cp_warning ("%s qualifier ignored on asm",
- IDENTIFIER_POINTER (cv_qualifier));
- expand_asm (string);
+ cp_error ("return identifier `%D' already in place", return_id);
+ return;
}
+ }
- finish_stmt ();
+ /* Can't let this happen for constructors. */
+ if (DECL_CONSTRUCTOR_P (current_function_decl))
+ {
+ error ("can't redefine default return value for constructors");
+ return;
+ }
+
+ /* If we have a named return value, put that in our scope as well. */
+ if (DECL_NAME (decl) != NULL_TREE)
+ {
+ /* Let `cp_finish_decl' know that this initializer is ok. */
+ DECL_INITIAL (decl) = init;
+ if (doing_semantic_analysis_p ())
+ pushdecl (decl);
+
+ if (building_stmt_tree ())
+ add_tree (build_min_nt (RETURN_INIT, return_id, init));
+ else
+ {
+ cp_finish_decl (decl, init, NULL_TREE, 0, 0);
+ store_return_init (decl);
+ }
}
}
+/* Cache the value of this class's main virtual function table pointer
+ in a register variable. This will save one indirection if a
+ more than one virtual function call is made this function. */
+
+void
+setup_vtbl_ptr ()
+{
+ my_friendly_assert (doing_semantic_analysis_p (), 19990919);
+
+ /* If we've already done this, there's no need to do it again. */
+ if (vtbls_set_up_p)
+ return;
+
+ if (DECL_CONSTRUCTOR_P (current_function_decl))
+ {
+ if (processing_template_decl)
+ add_tree (build_min_nt
+ (CTOR_INITIALIZER,
+ current_member_init_list, current_base_init_list));
+ else
+ finish_expr_stmt (emit_base_init (current_class_type));
+ }
+ else if (DECL_DESTRUCTOR_P (current_function_decl)
+ && !processing_template_decl)
+ {
+ tree binfo = TYPE_BINFO (current_class_type);
+ tree if_stmt;
+ tree compound_stmt;
+
+ /* If the dtor is empty, and we know there is not possible way we
+ could use any vtable entries, before they are possibly set by
+ a base class dtor, we don't have to setup the vtables, as we
+ know that any base class dtoring will set up any vtables it
+ needs. We avoid MI, because one base class dtor can do a
+ virtual dispatch to an overridden function that would need to
+ have a non-related vtable set up, we cannot avoid setting up
+ vtables in that case. We could change this to see if there is
+ just one vtable. */
+ if_stmt = begin_if_stmt ();
+
+ /* If it is not safe to avoid setting up the vtables, then
+ someone will change the condition to be boolean_true_node.
+ (Actually, for now, we do not have code to set the condition
+ appropriate, so we just assume that we always need to
+ initialize the vtables.) */
+ finish_if_stmt_cond (boolean_true_node, if_stmt);
+ current_vcalls_possible_p = &IF_COND (if_stmt);
+ compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
+
+ /* Make all virtual function table pointers in non-virtual base
+ classes point to CURRENT_CLASS_TYPE's virtual function
+ tables. */
+ expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr);
+
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ expand_indirect_vtbls_init (binfo, current_class_ref,
+ current_class_ptr);
+
+ finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
+ finish_then_clause (if_stmt);
+ finish_if_stmt ();
+ }
+
+ /* Always keep the BLOCK node associated with the outermost pair of
+ curly braces of a function. These are needed for correct
+ operation of dwarfout.c. */
+ keep_next_level (1);
+
+ /* The virtual function tables are set up now. */
+ vtbls_set_up_p = 1;
+}
+
+/* Begin a new scope. */
+
+void
+do_pushlevel ()
+{
+ if (!building_stmt_tree ())
+ {
+ emit_line_note (input_filename, lineno);
+ clear_last_expr ();
+ }
+ push_momentary ();
+ if (stmts_are_full_exprs_p)
+ {
+ pushlevel (0);
+ if (!building_stmt_tree ()
+ && !current_function->x_whole_function_mode_p)
+ expand_start_bindings (0);
+ else if (building_stmt_tree () && !processing_template_decl)
+ {
+ tree ss = build_min_nt (SCOPE_STMT);
+ SCOPE_BEGIN_P (ss) = 1;
+ add_tree (ss);
+ current_scope_stmt_stack
+ = tree_cons (NULL_TREE, ss, current_scope_stmt_stack);
+ }
+ }
+}
+
+/* Finish a scope. */
+
+tree
+do_poplevel ()
+{
+ tree t = NULL_TREE;
+
+ if (stmts_are_full_exprs_p)
+ {
+ if (!building_stmt_tree ()
+ && !current_function->x_whole_function_mode_p)
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ else if (building_stmt_tree () && !processing_template_decl)
+ {
+ tree ss = build_min_nt (SCOPE_STMT);
+ SCOPE_NULLIFIED_P (ss) = !kept_level_p ();
+ SCOPE_NULLIFIED_P (TREE_VALUE (current_scope_stmt_stack))
+ = SCOPE_NULLIFIED_P (ss);
+ add_tree (ss);
+ current_scope_stmt_stack = TREE_CHAIN (current_scope_stmt_stack);
+
+ /* When not in function-at-a-time mode, expand_end_bindings
+ will warn about unused variables. But, in
+ function-at-a-time mode expand_end_bindings is not passed
+ the list of variables in the current scope, and therefore
+ no warning is emitted. So, we explicitly warn here. */
+ warn_about_unused_variables (getdecls ());
+ }
+
+ t = poplevel (kept_level_p (), 1, 0);
+ }
+ pop_momentary ();
+ return t;
+}
+
/* Finish a parenthesized expression EXPR. */
tree
tree
begin_stmt_expr ()
{
- keep_next_level ();
- /* If we're processing_template_decl, then the upcoming compound
+ keep_next_level (1);
+ /* If we're building a statement tree, then the upcoming compound
statement will be chained onto the tree structure, starting at
last_tree. We return last_tree so that we can later unhook the
compound statement. */
- return processing_template_decl ? last_tree : expand_start_stmt_expr();
+ return building_stmt_tree () ? last_tree : expand_start_stmt_expr();
}
/* Finish a statement-expression. RTL_EXPR should be the value
statement-expression. */
tree
-finish_stmt_expr (rtl_expr, expr)
+finish_stmt_expr (rtl_expr)
tree rtl_expr;
- tree expr;
{
tree result;
- if (!processing_template_decl)
+ if (!building_stmt_tree ())
{
rtl_expr = expand_end_stmt_expr (rtl_expr);
- /* The statements have side effects, so the group does. */
+ /* The statements have side effects, so the group does too. */
TREE_SIDE_EFFECTS (rtl_expr) = 1;
}
- if (TREE_CODE (expr) == BLOCK)
+ if (building_stmt_tree ())
{
- /* Make a BIND_EXPR for the BLOCK already made. */
- if (processing_template_decl)
- result = build (BIND_EXPR, NULL_TREE,
- NULL_TREE, last_tree, expr);
- else
- result = build (BIND_EXPR, TREE_TYPE (rtl_expr),
- NULL_TREE, rtl_expr, expr);
+ /* If the last thing in the statement-expression was not an
+ expression-statement, then it has type `void'. */
+ if (!last_expr_type)
+ last_expr_type = void_type_node;
+ result = build_min (STMT_EXPR, last_expr_type, last_tree);
+ TREE_SIDE_EFFECTS (result) = 1;
- /* Remove the block from the tree at this point.
- It gets put back at the proper place
- when the BIND_EXPR is expanded. */
- delete_block (expr);
- }
- else
- result = expr;
-
- if (processing_template_decl)
- {
/* Remove the compound statement from the tree structure; it is
- now saved in the BIND_EXPR. */
+ now saved in the STMT_EXPR. */
last_tree = rtl_expr;
TREE_CHAIN (last_tree) = NULL_TREE;
}
-
+ else
+ result = rtl_expr;
+
return result;
}
result = build_x_function_call (fn, args, current_class_ref);
if (TREE_CODE (result) == CALL_EXPR
- && TREE_TYPE (result) != void_type_node)
+ && (! TREE_TYPE (result)
+ || TREE_CODE (TREE_TYPE (result)) != VOID_TYPE))
result = require_complete_type (result);
return result;
tree object;
tree args;
{
- if (IS_SIGNATURE (TREE_OPERAND (fn, 0)))
- {
- warning ("signature name in scope resolution ignored");
- return finish_object_call_expr (TREE_OPERAND (fn, 1), object, args);
- }
- else
- return build_scoped_method_call (object, TREE_OPERAND (fn, 0),
- TREE_OPERAND (fn, 1), args);
+ return build_scoped_method_call (object, TREE_OPERAND (fn, 0),
+ TREE_OPERAND (fn, 1), args);
}
/* Finish a pseudo-destructor call expression of OBJECT, with SCOPE
tree scope;
tree destructor;
{
+ if (processing_template_decl)
+ return build_min_nt (PSEUDO_DTOR_EXPR, object, scope, destructor);
+
if (scope && scope != destructor)
cp_error ("destructor specifier `%T::~%T()' must have matching names",
scope, destructor);
tree args;
{
if (processing_template_decl)
- return build_min_nt (CALL_EXPR, copy_to_permanent (fn), args,
- NULL_TREE);
+ return build_min_nt (CALL_EXPR, fn, args, NULL_TREE);
else
return build_member_call (TREE_OPERAND (fn, 0),
TREE_OPERAND (fn, 1),
tree specs;
tree attrs;
split_specs_attrs (decl_specs, &specs, &attrs);
- if (!start_function (specs, declarator, attrs, 0))
+ if (!start_function (specs, declarator, attrs, SF_DEFAULT))
return 0;
reinit_parse_for_function ();
{
/* In case there were missing closebraces,
get us back to the global binding level. */
- while (! toplevel_bindings_p ())
- poplevel (0, 0, 0);
+ pop_everything ();
while (current_namespace != global_namespace)
pop_namespace ();
finish_file ();
tree aggr;
tree identifier;
{
- if (aggr == signature_type_node)
- sorry ("signature as template type parameter");
- else if (aggr != class_type_node)
+ if (aggr != class_type_node)
{
pedwarn ("template type parameters must use the keyword `class' or `typename'");
aggr = class_type_node;
begin_class_definition (t)
tree t;
{
- push_obstacks_nochange ();
- end_temporary_allocation ();
-
+ push_permanent_obstack ();
+
if (t == error_mark_node
|| ! IS_AGGR_TYPE (t))
{
implicit typename, a TYPENAME_TYPE with a type. */
if (TREE_CODE (t) == TYPENAME_TYPE)
t = TREE_TYPE (t);
+
+ /* If we generated a partial instantiation of this type, but now
+ we're seeing a real definition, we're actually looking at a
+ partial specialization. Consider:
+
+ template <class T, class U>
+ struct Y {};
+
+ template <class T>
+ struct X {};
+
+ template <class T, class U>
+ void f()
+ {
+ typename X<Y<T, U> >::A a;
+ }
+
+ template <class T, class U>
+ struct X<Y<T, U> >
+ {
+ };
+
+ We have to undo the effects of the previous partial
+ instantiation. */
+ if (PARTIAL_INSTANTIATION_P (t))
+ {
+ if (!pedantic)
+ {
+ /* Unfortunately, when we're not in pedantic mode, we
+ attempt to actually fill in some of the fields of the
+ partial instantiation, in order to support the implicit
+ typename extension. Clear those fields now, in
+ preparation for the definition here. The fields cleared
+ here must match those set in instantiate_class_template.
+ Look for a comment mentioning begin_class_definition
+ there. */
+ TYPE_BINFO_BASETYPES (t) = NULL_TREE;
+ TYPE_FIELDS (t) = NULL_TREE;
+ TYPE_METHODS (t) = NULL_TREE;
+ CLASSTYPE_TAGS (t) = NULL_TREE;
+ TYPE_SIZE (t) = NULL_TREE;
+ }
- if (TYPE_SIZE (t))
+ /* This isn't a partial instantiation any more. */
+ PARTIAL_INSTANTIATION_P (t) = 0;
+ }
+ /* If this type was already complete, and we see another definition,
+ that's an error. */
+ else if (TYPE_SIZE (t))
duplicate_tag_error (t);
- if (TYPE_SIZE (t) || TYPE_BEING_DEFINED (t))
+
+ /* Update the location of the decl. */
+ DECL_SOURCE_FILE (TYPE_NAME (t)) = input_filename;
+ DECL_SOURCE_LINE (TYPE_NAME (t)) = lineno;
+
+ if (TYPE_BEING_DEFINED (t))
{
t = make_lang_type (TREE_CODE (t));
pushtag (TYPE_IDENTIFIER (t), t, 0);
}
- if (processing_template_decl && TYPE_CONTEXT (t)
- && TREE_CODE (TYPE_CONTEXT (t)) != NAMESPACE_DECL
- && ! current_class_type)
- push_template_decl (TYPE_STUB_DECL (t));
maybe_process_partial_specialization (t);
- pushclass (t, 0);
+ pushclass (t, 1);
TYPE_BEING_DEFINED (t) = 1;
/* Reset the interface data, at the earliest possible
moment, as it might have been set via a class foo;
before. */
- /* Don't change signatures. */
- if (! IS_SIGNATURE (t))
- {
- int needs_writing;
- tree name = TYPE_IDENTIFIER (t);
-
- if (! ANON_AGGRNAME_P (name))
- {
- CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
- SET_CLASSTYPE_INTERFACE_UNKNOWN_X
- (t, interface_unknown);
- }
-
- /* Record how to set the access of this class's
- virtual functions. If write_virtuals == 3, then
- inline virtuals are ``extern inline''. */
- if (write_virtuals == 3)
- needs_writing = ! CLASSTYPE_INTERFACE_ONLY (t)
- && CLASSTYPE_INTERFACE_KNOWN (t);
- else
- needs_writing = 1;
- CLASSTYPE_VTABLE_NEEDS_WRITING (t) = needs_writing;
- }
+ {
+ tree name = TYPE_IDENTIFIER (t);
+
+ if (! ANON_AGGRNAME_P (name))
+ {
+ CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
+ SET_CLASSTYPE_INTERFACE_UNKNOWN_X
+ (t, interface_unknown);
+ }
+
+ /* Only leave this bit clear if we know this
+ class is part of an interface-only specification. */
+ if (! CLASSTYPE_INTERFACE_KNOWN (t)
+ || ! CLASSTYPE_INTERFACE_ONLY (t))
+ CLASSTYPE_VTABLE_NEEDS_WRITING (t) = 1;
+ }
#if 0
tmp = TYPE_IDENTIFIER ($<ttype>0);
if (tmp && IDENTIFIER_TEMPLATE (tmp))
that we can get it back later. */
begin_tree ();
+ /* Make a declaration for this class in its own scope. */
+ build_self_reference ();
+
return t;
}
-/* Finish a class definition T, with the indicated COMPONENTS, and
- with the indicate ATTRIBUTES. If SEMI, the definition is
- immediately followed by a semicolon. Returns the type. */
+/* Finish the member declaration given by DECL. */
+
+void
+finish_member_declaration (decl)
+ tree decl;
+{
+ if (decl == error_mark_node || decl == NULL_TREE)
+ return;
+
+ if (decl == void_type_node)
+ /* The COMPONENT was a friend, not a member, and so there's
+ nothing for us to do. */
+ return;
+
+ /* We should see only one DECL at a time. */
+ my_friendly_assert (TREE_CHAIN (decl) == NULL_TREE, 0);
+
+ /* Set up access control for DECL. */
+ TREE_PRIVATE (decl)
+ = (current_access_specifier == access_private_node);
+ TREE_PROTECTED (decl)
+ = (current_access_specifier == access_protected_node);
+ if (TREE_CODE (decl) == TEMPLATE_DECL)
+ {
+ TREE_PRIVATE (DECL_RESULT (decl)) = TREE_PRIVATE (decl);
+ TREE_PROTECTED (DECL_RESULT (decl)) = TREE_PROTECTED (decl);
+ }
+
+ /* Mark the DECL as a member of the current class. */
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ || DECL_FUNCTION_TEMPLATE_P (decl))
+ /* Historically, DECL_CONTEXT was not set for a FUNCTION_DECL in
+ finish_struct. Presumably it is already set as the function is
+ parsed. Perhaps DECL_CLASS_CONTEXT is already set, too? */
+ DECL_CLASS_CONTEXT (decl) = current_class_type;
+ else
+ DECL_CONTEXT (decl) = current_class_type;
+
+ /* Put functions on the TYPE_METHODS list and everything else on the
+ TYPE_FIELDS list. Note that these are built up in reverse order.
+ We reverse them (to obtain declaration order) in finish_struct. */
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ || DECL_FUNCTION_TEMPLATE_P (decl))
+ {
+ /* We also need to add this function to the
+ CLASSTYPE_METHOD_VEC. */
+ add_method (current_class_type, 0, decl);
+
+ TREE_CHAIN (decl) = TYPE_METHODS (current_class_type);
+ TYPE_METHODS (current_class_type) = decl;
+ }
+ else
+ {
+ /* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields
+ go at the beginning. The reason is that lookup_field_1
+ searches the list in order, and we want a field name to
+ override a type name so that the "struct stat hack" will
+ work. In particular:
+
+ struct S { enum E { }; int E } s;
+ s.E = 3;
+
+ is legal. In addition, the FIELD_DECLs must be maintained in
+ declaration order so that class layout works as expected.
+ However, we don't need that order until class layout, so we
+ save a little time by putting FIELD_DECLs on in reverse order
+ here, and then reversing them in finish_struct_1. (We could
+ also keep a pointer to the correct insertion points in the
+ list.) */
+
+ if (TREE_CODE (decl) == TYPE_DECL)
+ TYPE_FIELDS (current_class_type)
+ = chainon (TYPE_FIELDS (current_class_type), decl);
+ else
+ {
+ TREE_CHAIN (decl) = TYPE_FIELDS (current_class_type);
+ TYPE_FIELDS (current_class_type) = decl;
+ }
+
+ /* Enter the DECL into the scope of the class. */
+ if (TREE_CODE (decl) != USING_DECL)
+ pushdecl_class_level (decl);
+ }
+}
+
+/* Finish a class definition T with the indicate ATTRIBUTES. If SEMI,
+ the definition is immediately followed by a semicolon. Returns the
+ type. */
tree
-finish_class_definition (t, components, attributes, semi)
+finish_class_definition (t, attributes, semi, pop_scope_p)
tree t;
- tree components;
tree attributes;
int semi;
+ int pop_scope_p;
{
-#if 0
- /* Need to rework class nesting in the presence of nested classes,
- etc. */
- shadow_tag (CLASSTYPE_AS_LIST (t)); */
-#endif
-
/* finish_struct nukes this anyway; if finish_exception does too,
then it can go. */
if (semi)
;
else
{
- t = finish_struct (t, components, attributes, semi);
+ t = finish_struct (t, attributes);
if (semi)
note_got_semicolon (t);
}
if (! semi)
check_for_missing_semicolon (t);
+ if (pop_scope_p)
+ pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (t)));
if (current_scope () == current_function_decl)
do_pending_defargs ();
the processing of a class definition. */
void
-finish_default_args ()
+begin_inline_definitions ()
{
if (pending_inlines
&& current_scope () == current_function_decl)
processing of a class definition. */
void
-begin_inline_definitions ()
+finish_inline_definitions ()
{
if (current_class_type == NULL_TREE)
clear_inline_text_obstack ();
TYPES whose template parameters are given by PARMS. */
tree
-finish_member_class_template (parms, types)
- tree parms;
+finish_member_class_template (types)
tree types;
{
tree t;
maybe_process_partial_specialization (TREE_VALUE (t));
note_list_got_semicolon (types);
- grok_x_components (types, NULL_TREE);
+ grok_x_components (types);
if (TYPE_CONTEXT (TREE_VALUE (types)) != current_class_type)
/* The component was in fact a friend declaration. We avoid
finish_member_template_decl performing certain checks by
unsetting TYPES. */
types = NULL_TREE;
- finish_member_template_decl (parms, types);
+
+ finish_member_template_decl (types);
+
/* As with other component type declarations, we do
not store the new DECL on the list of
component_decls. */
access_{default,public,protected_private}[_virtual]_node.*/
tree
-finish_base_specifier (access_specifier, base_class,
- current_aggr_is_signature)
+finish_base_specifier (access_specifier, base_class)
tree access_specifier;
tree base_class;
- int current_aggr_is_signature;
{
tree type;
tree result;
}
else
type = TREE_TYPE (base_class);
- if (current_aggr_is_signature && access_specifier)
- error ("access and source specifiers not allowed in signature");
+
if (! is_aggr_type (type, 1))
result = NULL_TREE;
- else if (current_aggr_is_signature
- && (! type) && (! IS_SIGNATURE (type)))
+ else
+ result = build_tree_list (access_specifier, type);
+
+ return result;
+}
+
+/* Called when multiple declarators are processed. If that is not
+ premitted in this context, an error is issued. */
+
+void
+check_multiple_declarators ()
+{
+ /* [temp]
+
+ In a template-declaration, explicit specialization, or explicit
+ instantiation the init-declarator-list in the declaration shall
+ contain at most one declarator.
+
+ We don't just use PROCESSING_TEMPLATE_DECL for the first
+ condition since that would disallow the perfectly legal code,
+ like `template <class T> struct S { int i, j; };'. */
+ tree scope = current_scope ();
+
+ if (scope && TREE_CODE (scope) == FUNCTION_DECL)
+ /* It's OK to write `template <class T> void f() { int i, j;}'. */
+ return;
+
+ if (PROCESSING_REAL_TEMPLATE_DECL_P ()
+ || processing_explicit_instantiation
+ || processing_specialization)
+ cp_error ("multiple declarators in template declaration");
+}
+
+tree
+finish_typeof (expr)
+ tree expr;
+{
+ if (processing_template_decl)
{
- error ("class name not allowed as base signature");
- result = NULL_TREE;
+ tree t;
+
+ push_permanent_obstack ();
+ t = make_lang_type (TYPEOF_TYPE);
+ TYPE_FIELDS (t) = expr;
+ pop_obstacks ();
+
+ return t;
}
- else if (current_aggr_is_signature)
+
+ return TREE_TYPE (expr);
+}
+
+/* Create an empty statement tree for FN. */
+
+void
+begin_stmt_tree (fn)
+ tree fn;
+{
+ /* We create a trivial EXPR_STMT so that last_tree is never NULL in
+ what follows. We remove the extraneous statement in
+ finish_stmt_tree. */
+ DECL_SAVED_TREE (fn) = build_nt (EXPR_STMT, void_zero_node);
+ last_tree = DECL_SAVED_TREE (fn);
+ last_expr_type = NULL_TREE;
+}
+
+/* Finish the statement tree for FN. */
+
+void
+finish_stmt_tree (fn)
+ tree fn;
+{
+ tree stmt;
+
+ /* Remove the fake extra statement added in begin_stmt_tree. */
+ stmt = TREE_CHAIN (DECL_SAVED_TREE (fn));
+ DECL_SAVED_TREE (fn) = stmt;
+
+ /* The line-number recorded in the outermost statement in a function
+ is the line number of the end of the function. */
+ STMT_LINENO (stmt) = lineno;
+ STMT_LINENO_FOR_FN_P (stmt) = 1;
+}
+
+/* We're about to expand T, a statement. Set up appropriate context
+ for the substitution. */
+
+void
+prep_stmt (t)
+ tree t;
+{
+ if (!STMT_LINENO_FOR_FN_P (t))
+ lineno = STMT_LINENO (t);
+ stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t);
+}
+
+/* Some statements, like for-statements or if-statements, require a
+ condition. This condition can be a declaration. If T is such a
+ declaration it is processed, and an expression appropriate to use
+ as the condition is returned. Otherwise, T itself is returned. */
+
+static tree
+expand_cond (t)
+ tree t;
+{
+ if (t && TREE_CODE (t) == TREE_LIST)
{
- sorry ("signature inheritance, base type `%s' ignored",
- IDENTIFIER_POINTER (access_specifier));
- result = build_tree_list (access_public_node, type);
+ expand_stmt (TREE_PURPOSE (t));
+ return TREE_VALUE (t);
}
- else if (type && IS_SIGNATURE (type))
+ else
+ return t;
+}
+
+/* Generate RTL for the statement T, and its substatements, and any
+ other statements at its nesting level. */
+
+tree
+expand_stmt (t)
+ tree t;
+{
+ tree rval = NULL_TREE;
+
+ while (t && t != error_mark_node)
{
- error ("signature name not allowed as base class");
- result = NULL_TREE;
+ int saved_stmts_are_full_exprs_p;
+
+ /* Assume we'll have nothing to return. */
+ rval = NULL_TREE;
+
+ /* Set up context appropriately for handling this statement. */
+ saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p;
+ prep_stmt (t);
+
+ switch (TREE_CODE (t))
+ {
+ case RETURN_STMT:
+ finish_return_stmt (RETURN_EXPR (t));
+ break;
+
+ case EXPR_STMT:
+ finish_expr_stmt (EXPR_STMT_EXPR (t));
+ break;
+
+ case DECL_STMT:
+ {
+ tree decl;
+ int i = suspend_momentary ();
+
+ emit_line_note (input_filename, lineno);
+ decl = DECL_STMT_DECL (t);
+ /* If this is a declaration for an automatic local
+ variable, initialize it. Note that we might also see a
+ declaration for a namespace-scope object (declared with
+ `extern'). We don't have to handle the initialization
+ of those objects here; they can only be declarations,
+ rather than definitions. */
+ if (TREE_CODE (decl) == VAR_DECL
+ && !TREE_STATIC (decl)
+ && !DECL_EXTERNAL (decl))
+ {
+ /* Let the back-end know about this variable. */
+ if (!ANON_AGGR_TYPE_P (TREE_TYPE (decl)))
+ emit_local_var (decl);
+ else
+ expand_anon_union_decl (decl, NULL_TREE,
+ DECL_ANON_UNION_ELEMS (decl));
+ }
+ else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
+ rest_of_decl_compilation
+ (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+ /*top_level=*/0, /*at_end=*/0);
+
+ resume_momentary (i);
+ }
+ break;
+
+ case CLEANUP_STMT:
+ finish_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
+ break;
+
+ case START_CATCH_STMT:
+ begin_catch_block (TREE_TYPE (t));
+ break;
+
+ case FOR_STMT:
+ {
+ tree tmp;
+
+ begin_for_stmt ();
+ expand_stmt (FOR_INIT_STMT (t));
+ finish_for_init_stmt (NULL_TREE);
+ finish_for_cond (expand_cond (FOR_COND (t)), NULL_TREE);
+ tmp = FOR_EXPR (t);
+ finish_for_expr (tmp, NULL_TREE);
+ expand_stmt (FOR_BODY (t));
+ finish_for_stmt (tmp, NULL_TREE);
+ }
+ break;
+
+ case WHILE_STMT:
+ {
+ begin_while_stmt ();
+ finish_while_stmt_cond (expand_cond (WHILE_COND (t)), NULL_TREE);
+ expand_stmt (WHILE_BODY (t));
+ finish_while_stmt (NULL_TREE);
+ }
+ break;
+
+ case DO_STMT:
+ {
+ begin_do_stmt ();
+ expand_stmt (DO_BODY (t));
+ finish_do_body (NULL_TREE);
+ finish_do_stmt (DO_COND (t), NULL_TREE);
+ }
+ break;
+
+ case IF_STMT:
+ begin_if_stmt ();
+ finish_if_stmt_cond (expand_cond (IF_COND (t)), NULL_TREE);
+ if (THEN_CLAUSE (t))
+ {
+ expand_stmt (THEN_CLAUSE (t));
+ finish_then_clause (NULL_TREE);
+ }
+ if (ELSE_CLAUSE (t))
+ {
+ begin_else_clause ();
+ expand_stmt (ELSE_CLAUSE (t));
+ finish_else_clause (NULL_TREE);
+ }
+ finish_if_stmt ();
+ break;
+
+ case COMPOUND_STMT:
+ begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
+ expand_stmt (COMPOUND_BODY (t));
+ rval = finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t),
+ NULL_TREE);
+ break;
+
+ case BREAK_STMT:
+ finish_break_stmt ();
+ break;
+
+ case CONTINUE_STMT:
+ finish_continue_stmt ();
+ break;
+
+ case SWITCH_STMT:
+ {
+ tree cond;
+
+ begin_switch_stmt ();
+ cond = expand_cond (SWITCH_COND (t));
+ finish_switch_cond (cond, NULL_TREE);
+ expand_stmt (SWITCH_BODY (t));
+ finish_switch_stmt (cond, NULL_TREE);
+ }
+ break;
+
+ case CASE_LABEL:
+ finish_case_label (CASE_LOW (t), CASE_HIGH (t));
+ break;
+
+ case LABEL_STMT:
+ expand_label (LABEL_STMT_LABEL (t));
+ break;
+
+ case GOTO_STMT:
+ finish_goto_stmt (GOTO_DESTINATION (t));
+ break;
+
+ case ASM_STMT:
+ finish_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t), ASM_OUTPUTS
+ (t), ASM_INPUTS (t), ASM_CLOBBERS (t));
+ break;
+
+ case TRY_BLOCK:
+ if (CLEANUP_P (t))
+ {
+ expand_eh_region_start ();
+ expand_stmt (TRY_STMTS (t));
+ finish_cleanup_try_block (NULL_TREE);
+ finish_cleanup (TRY_HANDLERS (t), NULL_TREE);
+ }
+ else
+ {
+ if (FN_TRY_BLOCK_P (t))
+ begin_function_try_block ();
+ else
+ begin_try_block ();
+
+ expand_stmt (TRY_STMTS (t));
+
+ if (FN_TRY_BLOCK_P (t))
+ {
+ finish_function_try_block (NULL_TREE);
+ expand_stmt (TRY_HANDLERS (t));
+ finish_function_handler_sequence (NULL_TREE);
+ }
+ else
+ {
+ finish_try_block (NULL_TREE);
+ expand_stmt (TRY_HANDLERS (t));
+ finish_handler_sequence (NULL_TREE);
+ }
+ }
+ break;
+
+ case HANDLER:
+ begin_handler ();
+ expand_stmt (HANDLER_BODY (t));
+ finish_handler (NULL_TREE, NULL_TREE);
+ break;
+
+ case SUBOBJECT:
+ finish_subobject (SUBOBJECT_CLEANUP (t));
+ break;
+
+ case SCOPE_STMT:
+ if (SCOPE_BEGIN_P (t))
+ expand_start_bindings (2 * SCOPE_NULLIFIED_P (t));
+ else if (SCOPE_END_P (t))
+ expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0);
+ break;
+
+ case RETURN_INIT:
+ /* Clear this out so that finish_named_return_value can set it
+ again. */
+ DECL_NAME (DECL_RESULT (current_function_decl)) = NULL_TREE;
+ finish_named_return_value (TREE_OPERAND (t, 0),
+ TREE_OPERAND (t, 1));
+ break;
+
+ default:
+ my_friendly_abort (19990810);
+ break;
+ }
+
+ /* Restore saved state. */
+ stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
+
+ /* Go on to the next statement in this scope. */
+ t = TREE_CHAIN (t);
}
- else
- result = build_tree_list (access_specifier, type);
- return result;
+ return rval;
+}
+
+/* Generate RTL for FN. */
+
+void
+expand_body (fn)
+ tree fn;
+{
+ int saved_lineno;
+ char *saved_input_filename;
+
+ /* When the parser calls us after finishing the body of a template
+ function, we don't really want to expand the body. When we're
+ processing an in-class definition of an inline function,
+ PROCESSING_TEMPLATE_DECL will no longer be set here, so we have
+ to look at the function itself. */
+ if (processing_template_decl
+ || (DECL_LANG_SPECIFIC (fn)
+ && DECL_TEMPLATE_INFO (fn)
+ && uses_template_parms (DECL_TI_ARGS (fn))))
+ return;
+
+ /* There's no reason to do any of the work here if we're only doing
+ semantic analysis; this code just generates RTL. */
+ if (flag_syntax_only)
+ return;
+
+ /* Save the current file name and line number. When we expand the
+ body of the function, we'll set LINENO and INPUT_FILENAME so that
+ error-mesages come out in the right places. */
+ saved_lineno = lineno;
+ saved_input_filename = input_filename;
+ lineno = DECL_SOURCE_LINE (fn);
+ input_filename = DECL_SOURCE_FILE (fn);
+
+ start_function (NULL_TREE, fn, NULL_TREE, SF_PRE_PARSED | SF_EXPAND);
+ store_parm_decls ();
+
+ /* We don't need to redeclare __FUNCTION__, __PRETTY_FUNCTION__, or
+ any of the other magic variables we set up when starting a
+ function body. */
+ current_function_name_declared = 1;
+
+ /* Expand the body. */
+ expand_stmt (DECL_SAVED_TREE (fn));
+
+ /* Statements should always be full-expressions at the outermost set
+ of curly braces for a function. */
+ my_friendly_assert (stmts_are_full_exprs_p, 19990831);
+
+ /* The outermost statement for a function contains the line number
+ recorded when we finished processing the function. */
+ lineno = STMT_LINENO (DECL_SAVED_TREE (fn));
+
+ /* Generate code for the function. */
+ finish_function (lineno, 0);
+
+ /* And restore the current source position. */
+ lineno = saved_lineno;
+ input_filename = saved_input_filename;
}