summaryrefslogtreecommitdiff
path: root/gcc/cp/semantics.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/semantics.c')
-rwxr-xr-xgcc/cp/semantics.c1678
1 files changed, 1678 insertions, 0 deletions
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
new file mode 100755
index 0000000..fd6f3d0
--- /dev/null
+++ b/gcc/cp/semantics.c
@@ -0,0 +1,1678 @@
+/* Perform the semantic phase of parsing, i.e., the process of
+ building tree structure, checking semantic consistency, and
+ building RTL. These routines are used both during actual parsing
+ and during the instantiation of template functions.
+
+ 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.
+
+ This file is part of GNU CC.
+
+ GNU CC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU CC is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU CC; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "except.h"
+#include "lex.h"
+#include "toplev.h"
+
+/* There routines provide a modular interface to perform many parsing
+ operations. They may therefore be used during actual parsing, or
+ during template instantiation, which may be regarded as a
+ degenerate form of parsing. Since the current g++ parser is
+ lacking in several respects, and will be reimplemented, we are
+ attempting to move most code that is not directly related to
+ parsing into this file; that will make implementing the new parser
+ much easier since it will be able to make use of these routines. */
+
+/* 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; \
+ } while (0)
+
+#define RECHAIN_STMTS_FROM_LAST(stmt, substmt) \
+ RECHAIN_STMTS (stmt, substmt, last_tree)
+
+#define RECHAIN_STMTS_FROM_CHAIN(stmt, substmt) \
+ RECHAIN_STMTS (stmt, substmt, TREE_CHAIN (stmt))
+
+/* Finish an expression-statement, whose EXPRESSION is as indicated. */
+
+void
+finish_expr_stmt (expr)
+ tree expr;
+{
+ if (expr != NULL_TREE)
+ {
+ if (!processing_template_decl)
+ {
+ 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)
+ expr = default_conversion (expr);
+ }
+
+ cplus_expand_expr_stmt (expr);
+ clear_momentary ();
+ }
+
+ finish_stmt ();
+}
+
+/* Begin an if-statement. Returns a newly created IF_STMT if
+ appropriate. */
+
+tree
+begin_if_stmt ()
+{
+ tree r;
+
+ if (processing_template_decl)
+ {
+ r = build_min_nt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
+ add_tree (r);
+ }
+ else
+ r = NULL_TREE;
+
+ do_pushlevel ();
+
+ return r;
+}
+
+/* Process the COND of an if-statement, which may be given by
+ IF_STMT. */
+
+void
+finish_if_stmt_cond (cond, if_stmt)
+ 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;
+ }
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ expand_start_cond (condition_conversion (cond), 0);
+ }
+}
+
+/* Finish the then-clause of an if-statement, which may be given by
+ IF_STMT. */
+
+tree
+finish_then_clause (if_stmt)
+ tree if_stmt;
+{
+ if (processing_template_decl)
+ {
+ RECHAIN_STMTS_FROM_CHAIN (if_stmt,
+ THEN_CLAUSE (if_stmt));
+ last_tree = if_stmt;
+ return if_stmt;
+ }
+ else
+ return NULL_TREE;
+}
+
+/* Begin the else-clause of an if-statement. */
+
+void
+begin_else_clause ()
+{
+ if (!processing_template_decl)
+ expand_start_else ();
+}
+
+/* Finish the else-clause of an if-statement, which may be given by
+ IF_STMT. */
+
+void
+finish_else_clause (if_stmt)
+ tree if_stmt;
+{
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (if_stmt, ELSE_CLAUSE (if_stmt));
+}
+
+/* Finsh an if-statement. */
+
+void
+finish_if_stmt ()
+{
+ if (!processing_template_decl)
+ expand_end_cond ();
+
+ do_poplevel ();
+ finish_stmt ();
+}
+
+/* Begin a while-statement. Returns a newly created WHILE_STMT if
+ appropriate. */
+
+tree
+begin_while_stmt ()
+{
+ tree r;
+
+ if (processing_template_decl)
+ {
+ r = build_min_nt (WHILE_STMT, NULL_TREE, NULL_TREE);
+ add_tree (r);
+ }
+ else
+ {
+ emit_nop ();
+ emit_line_note (input_filename, lineno);
+ expand_start_loop (1);
+ r = NULL_TREE;
+ }
+
+ do_pushlevel ();
+
+ return r;
+}
+
+/* Process the COND of an if-statement, which may be given by
+ WHILE_STMT. */
+
+void
+finish_while_stmt_cond (cond, while_stmt)
+ 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;
+ }
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ expand_exit_loop_if_false (0, condition_conversion (cond));
+ }
+
+ /* If COND wasn't a declaration, clear out the
+ block we made for it and start a new one here so the
+ optimization in expand_end_loop will work. */
+ if (getdecls () == NULL_TREE)
+ {
+ do_poplevel ();
+ do_pushlevel ();
+ }
+}
+
+/* Finish a while-statement, which may be given by WHILE_STMT. */
+
+void
+finish_while_stmt (while_stmt)
+ tree while_stmt;
+{
+ do_poplevel ();
+
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (while_stmt, WHILE_BODY (while_stmt));
+ else
+ expand_end_loop ();
+ finish_stmt ();
+}
+
+/* Begin a do-statement. Returns a newly created DO_STMT if
+ appropriate. */
+
+tree
+begin_do_stmt ()
+{
+ if (processing_template_decl)
+ {
+ tree r = build_min_nt (DO_STMT, NULL_TREE, NULL_TREE);
+ add_tree (r);
+ return r;
+ }
+ else
+ {
+ emit_nop ();
+ emit_line_note (input_filename, lineno);
+ expand_start_loop_continue_elsewhere (1);
+ return NULL_TREE;
+ }
+}
+
+/* Finish the body of a do-statement, which may be given by DO_STMT. */
+
+void
+finish_do_body (do_stmt)
+ tree do_stmt;
+{
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (do_stmt, DO_BODY (do_stmt));
+ else
+ expand_loop_continue_here ();
+}
+
+/* Finish a do-statement, which may be given by DO_STMT, and whose
+ COND is as indicated. */
+
+void
+finish_do_stmt (cond, do_stmt)
+ tree cond;
+ tree do_stmt;
+{
+ if (processing_template_decl)
+ DO_COND (do_stmt) = cond;
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ expand_exit_loop_if_false (0, condition_conversion (cond));
+ expand_end_loop ();
+ }
+
+ clear_momentary ();
+ finish_stmt ();
+}
+
+/* Finish a return-statement. The EXPRESSION returned, if any, is as
+ indicated. */
+
+void
+finish_return_stmt (expr)
+ tree expr;
+{
+ emit_line_note (input_filename, lineno);
+ c_expand_return (expr);
+ finish_stmt ();
+}
+
+/* Begin a for-statement. Returns a new FOR_STMT if appropriate. */
+
+tree
+begin_for_stmt ()
+{
+ tree r;
+
+ if (processing_template_decl)
+ {
+ r = build_min_nt (FOR_STMT, NULL_TREE, NULL_TREE,
+ NULL_TREE, NULL_TREE);
+ add_tree (r);
+ }
+ else
+ r = NULL_TREE;
+
+ if (flag_new_for_scope > 0)
+ {
+ do_pushlevel ();
+ note_level_for_for ();
+ }
+
+ return r;
+}
+
+/* Finish the for-init-statement of a for-statement, which may be
+ given by FOR_STMT. */
+
+void
+finish_for_init_stmt (for_stmt)
+ tree for_stmt;
+{
+ if (processing_template_decl)
+ {
+ if (last_tree != for_stmt)
+ RECHAIN_STMTS_FROM_CHAIN (for_stmt, FOR_INIT_STMT (for_stmt));
+ }
+ else
+ {
+ emit_nop ();
+ emit_line_note (input_filename, lineno);
+ expand_start_loop_continue_elsewhere (1);
+ }
+
+ do_pushlevel ();
+}
+
+/* Finish the COND of a for-statement, which may be given by
+ FOR_STMT. */
+
+void
+finish_for_cond (cond, for_stmt)
+ 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;
+ }
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ if (cond)
+ expand_exit_loop_if_false (0, condition_conversion (cond));
+ }
+
+ /* If the cond wasn't a declaration, clear out the
+ block we made for it and start a new one here so the
+ optimization in expand_end_loop will work. */
+ if (getdecls () == NULL_TREE)
+ {
+ do_poplevel ();
+ do_pushlevel ();
+ }
+}
+
+/* Finish the increment-EXPRESSION in a for-statement, which may be
+ given by FOR_STMT. */
+
+void
+finish_for_expr (expr, for_stmt)
+ tree expr;
+ tree for_stmt;
+{
+ if (processing_template_decl)
+ FOR_EXPR (for_stmt) = expr;
+
+ /* Don't let the tree nodes for EXPR be discarded
+ by clear_momentary during the parsing of the next stmt. */
+ push_momentary ();
+}
+
+/* Finish the body of a for-statement, which may be given by
+ FOR_STMT. The increment-EXPR for the loop must be
+ provided. */
+
+void
+finish_for_stmt (expr, for_stmt)
+ tree expr;
+ tree for_stmt;
+{
+ /* 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));
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ expand_loop_continue_here ();
+ if (expr)
+ cplus_expand_expr_stmt (expr);
+ expand_end_loop ();
+ }
+
+ pop_momentary ();
+
+ if (flag_new_for_scope > 0)
+ do_poplevel ();
+
+ finish_stmt ();
+}
+
+/* Finish a break-statement. */
+
+void
+finish_break_stmt ()
+{
+ emit_line_note (input_filename, lineno);
+ if (processing_template_decl)
+ add_tree (build_min_nt (BREAK_STMT));
+ else if ( ! expand_exit_something ())
+ cp_error ("break statement not within loop or switch");
+}
+
+/* Finish a continue-statement. */
+
+void
+finish_continue_stmt ()
+{
+ emit_line_note (input_filename, lineno);
+ if (processing_template_decl)
+ 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. */
+
+tree
+finish_switch_cond (cond)
+ tree cond;
+{
+ tree r;
+
+ if (processing_template_decl)
+ {
+ r = build_min_nt (SWITCH_STMT, cond, NULL_TREE);
+ add_tree (r);
+ }
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ c_expand_start_case (cond);
+ r = NULL_TREE;
+ }
+ 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
+ SWITCH_STMT. The COND to switch on is indicated. */
+
+void
+finish_switch_stmt (cond, switch_stmt)
+ tree cond;
+ tree switch_stmt;
+{
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (switch_stmt, SWITCH_BODY (switch_stmt));
+ else
+ expand_end_case (cond);
+ pop_momentary ();
+ pop_switch ();
+ do_poplevel ();
+ finish_stmt ();
+}
+
+/* Finish a case-label. */
+
+void
+finish_case_label (low_value, high_value)
+ tree low_value;
+ tree high_value;
+{
+ do_case (low_value, high_value);
+}
+
+
+/* Finish a goto-statement. */
+
+void
+finish_goto_stmt (destination)
+ tree destination;
+{
+ if (processing_template_decl)
+ add_tree (build_min_nt (GOTO_STMT, destination));
+ else
+ {
+ emit_line_note (input_filename, lineno);
+
+ if (TREE_CODE (destination) == IDENTIFIER_NODE)
+ {
+ tree decl = lookup_label (destination);
+ TREE_USED (decl) = 1;
+ expand_goto (decl);
+ }
+ else
+ expand_computed_goto (destination);
+ }
+}
+
+/* Begin a try-block. Returns a newly-created TRY_BLOCK if
+ appropriate. */
+
+tree
+begin_try_block ()
+{
+ if (processing_template_decl)
+ {
+ tree r = build_min_nt (TRY_BLOCK, NULL_TREE,
+ NULL_TREE);
+ add_tree (r);
+ return r;
+ }
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ expand_start_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));
+ else
+ {
+ expand_start_all_catch ();
+ }
+}
+
+/* Finish a handler-sequence for a try-block, which may be given by
+ TRY_BLOCK. */
+
+void
+finish_handler_sequence (try_block)
+ tree try_block;
+{
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (try_block, TRY_HANDLERS (try_block));
+ else
+ {
+ expand_end_all_catch ();
+ }
+}
+
+/* Begin a handler. Returns a HANDLER if appropriate. */
+
+tree
+begin_handler ()
+{
+ tree r;
+
+ if (processing_template_decl)
+ {
+ r = build_min_nt (HANDLER, NULL_TREE, NULL_TREE);
+ add_tree (r);
+ }
+ else
+ r = NULL_TREE;
+
+ do_pushlevel ();
+
+ return r;
+}
+
+/* Finish the handler-parameters for a handler, which may be given by
+ HANDLER. */
+
+void
+finish_handler_parms (handler)
+ tree handler;
+{
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (handler, HANDLER_PARMS (handler));
+}
+
+/* Finish a handler, which may be given by HANDLER. */
+
+void
+finish_handler (handler)
+ tree handler;
+{
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (handler, HANDLER_BODY (handler));
+ else
+ expand_end_catch_block ();
+
+ do_poplevel ();
+}
+
+/* Begin a compound-statement. If HAS_NO_SCOPE is non-zero, the
+ compound-statement does not define a scope. Returns a new
+ COMPOUND_STMT if appropriate. */
+
+tree
+begin_compound_stmt (has_no_scope)
+ int has_no_scope;
+{
+ tree r;
+
+ if (processing_template_decl)
+ {
+ r = build_min_nt (COMPOUND_STMT, NULL_TREE);
+ add_tree (r);
+ if (has_no_scope)
+ COMPOUND_STMT_NO_SCOPE (r) = 1;
+ }
+ else
+ r = NULL_TREE;
+
+ if (!has_no_scope)
+ do_pushlevel ();
+
+ return r;
+}
+
+
+/* Finish a compound-statement, which may be given by COMPOUND_STMT.
+ If HAS_NO_SCOPE is non-zero, the compound statement does not define
+ a scope. */
+
+tree
+finish_compound_stmt (has_no_scope, compound_stmt)
+ int has_no_scope;
+ tree compound_stmt;
+{
+ tree r;
+
+ 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));
+
+ finish_stmt ();
+
+ return r;
+}
+
+/* Finish an asm-statement, whose components are a CV_QUALIFIER, a
+ STRING, some OUTPUT_OPERANDS, some INPUT_OPERANDS, and some
+ CLOBBERS. */
+
+void
+finish_asm_stmt (cv_qualifier, string, output_operands,
+ input_operands, clobbers)
+ tree cv_qualifier;
+ tree string;
+ tree output_operands;
+ tree input_operands;
+ tree clobbers;
+{
+ if (TREE_CHAIN (string))
+ string = combine_strings (string);
+
+ if (processing_template_decl)
+ {
+ tree r = build_min_nt (ASM_STMT, cv_qualifier, string,
+ output_operands, input_operands,
+ clobbers);
+ add_tree (r);
+ }
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ if (output_operands != NULL_TREE || input_operands != 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));
+
+ c_expand_asm_operands (string, output_operands,
+ input_operands,
+ clobbers,
+ cv_qualifier
+ == ridpointers[(int) RID_VOLATILE],
+ input_filename, lineno);
+ }
+ else
+ {
+ /* Don't warn about redundant specification of 'volatile' here. */
+ if (cv_qualifier != NULL_TREE
+ && cv_qualifier != ridpointers[(int) RID_VOLATILE])
+ cp_warning ("%s qualifier ignored on asm",
+ IDENTIFIER_POINTER (cv_qualifier));
+ expand_asm (string);
+ }
+
+ finish_stmt ();
+ }
+}
+
+/* Finish a parenthesized expression EXPR. */
+
+tree
+finish_parenthesized_expr (expr)
+ tree expr;
+{
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expr))))
+ /* This inhibits warnings in truthvalue_conversion. */
+ C_SET_EXP_ORIGINAL_CODE (expr, ERROR_MARK);
+
+ return expr;
+}
+
+/* Begin a statement-expression. The value returned must be passed to
+ finish_stmt_expr. */
+
+tree
+begin_stmt_expr ()
+{
+ keep_next_level ();
+ /* If we're processing_template_decl, 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();
+}
+
+/* Finish a statement-expression. RTL_EXPR should be the value
+ returned by the previous begin_stmt_expr; EXPR is the
+ statement-expression. Returns an expression representing the
+ statement-expression. */
+
+tree
+finish_stmt_expr (rtl_expr, expr)
+ tree rtl_expr;
+ tree expr;
+{
+ tree result;
+
+ if (!processing_template_decl)
+ {
+ rtl_expr = expand_end_stmt_expr (rtl_expr);
+ /* The statements have side effects, so the group does. */
+ TREE_SIDE_EFFECTS (rtl_expr) = 1;
+ }
+
+ if (TREE_CODE (expr) == BLOCK)
+ {
+ /* Make a BIND_EXPR for the BLOCK already made. */
+ if (processing_template_decl)
+ result = build_min_nt (BIND_EXPR, NULL_TREE, last_tree,
+ NULL_TREE);
+ else
+ result = build (BIND_EXPR, TREE_TYPE (rtl_expr),
+ NULL_TREE, rtl_expr, expr);
+
+ /* 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. */
+ last_tree = rtl_expr;
+ TREE_CHAIN (last_tree) = NULL_TREE;
+ }
+
+ return result;
+}
+
+/* Finish a call to FN with ARGS. Returns a representation of the
+ call. */
+
+tree
+finish_call_expr (fn, args, koenig)
+ tree fn;
+ tree args;
+ int koenig;
+{
+ tree result;
+
+ if (koenig)
+ {
+ if (TREE_CODE (fn) == BIT_NOT_EXPR)
+ fn = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND (fn, 0));
+ else if (TREE_CODE (fn) != TEMPLATE_ID_EXPR)
+ fn = do_identifier (fn, 2, args);
+ }
+ result = build_x_function_call (fn, args, current_class_ref);
+
+ if (TREE_CODE (result) == CALL_EXPR
+ && TREE_TYPE (result) != void_type_node)
+ result = require_complete_type (result);
+
+ return result;
+}
+
+/* Finish a call to a postfix increment or decrement or EXPR. (Which
+ is indicated by CODE, which should be POSTINCREMENT_EXPR or
+ POSTDECREMENT_EXPR.) */
+
+tree
+finish_increment_expr (expr, code)
+ tree expr;
+ enum tree_code code;
+{
+ /* If we get an OFFSET_REF, turn it into what it really means (e.g.,
+ a COMPONENT_REF). This way if we've got, say, a reference to a
+ static member that's being operated on, we don't end up trying to
+ find a member operator for the class it's in. */
+
+ if (TREE_CODE (expr) == OFFSET_REF)
+ expr = resolve_offset_ref (expr);
+ return build_x_unary_op (code, expr);
+}
+
+/* Finish a use of `this'. Returns an expression for `this'. */
+
+tree
+finish_this_expr ()
+{
+ tree result;
+
+ if (current_class_ptr)
+ {
+#ifdef WARNING_ABOUT_CCD
+ TREE_USED (current_class_ptr) = 1;
+#endif
+ result = current_class_ptr;
+ }
+ else if (current_function_decl
+ && DECL_STATIC_FUNCTION_P (current_function_decl))
+ {
+ error ("`this' is unavailable for static member functions");
+ result = error_mark_node;
+ }
+ else
+ {
+ if (current_function_decl)
+ error ("invalid use of `this' in non-member function");
+ else
+ error ("invalid use of `this' at top level");
+ result = error_mark_node;
+ }
+
+ return result;
+}
+
+/* Finish a member function call using OBJECT and ARGS as arguments to
+ FN. Returns an expression for the call. */
+
+tree
+finish_object_call_expr (fn, object, args)
+ tree fn;
+ tree object;
+ tree args;
+{
+#if 0
+ /* This is a future direction of this code, but because
+ build_x_function_call cannot always undo what is done in
+ build_component_ref entirely yet, we cannot do this. */
+
+ tree real_fn = build_component_ref (object, fn, NULL_TREE, 1);
+ return finish_call_expr (real_fn, args);
+#else
+ if (TREE_CODE (fn) == TYPE_DECL)
+ {
+ if (processing_template_decl)
+ /* This can happen on code like:
+
+ class X;
+ template <class T> void f(T t) {
+ t.X();
+ }
+
+ We just grab the underlying IDENTIFIER. */
+ fn = DECL_NAME (fn);
+ else
+ {
+ cp_error ("calling type `%T' like a method", fn);
+ return error_mark_node;
+ }
+ }
+
+ return build_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
+#endif
+}
+
+/* Finish a qualified member function call using OBJECT and ARGS as
+ arguments to FN. Returns an expressino for the call. */
+
+tree
+finish_qualified_object_call_expr (fn, object, args)
+ tree fn;
+ 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);
+}
+
+/* Finish a pseudo-destructor call expression of OBJECT, with SCOPE
+ being the scope, if any, of DESTRUCTOR. Returns an expression for
+ the call. */
+
+tree
+finish_pseudo_destructor_call_expr (object, scope, destructor)
+ tree object;
+ tree scope;
+ tree destructor;
+{
+ if (scope && scope != destructor)
+ cp_error ("destructor specifier `%T::~%T()' must have matching names",
+ scope, destructor);
+
+ if ((scope == NULL_TREE || IDENTIFIER_GLOBAL_VALUE (destructor))
+ && (TREE_CODE (TREE_TYPE (object)) !=
+ TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (destructor)))))
+ cp_error ("`%E' is not of type `%T'", object, destructor);
+
+ return cp_convert (void_type_node, object);
+}
+
+/* Finish a call to a globally qualified member function FN using
+ ARGS. Returns an expression for the call. */
+
+tree
+finish_qualified_call_expr (fn, args)
+ tree fn;
+ tree args;
+{
+ if (processing_template_decl)
+ return build_min_nt (CALL_EXPR, copy_to_permanent (fn), args,
+ NULL_TREE);
+ else
+ return build_member_call (TREE_OPERAND (fn, 0),
+ TREE_OPERAND (fn, 1),
+ args);
+}
+
+/* Finish an expression taking the address of LABEL. Returns an
+ expression for the address. */
+
+tree
+finish_label_address_expr (label)
+ tree label;
+{
+ tree result;
+
+ label = lookup_label (label);
+ if (label == NULL_TREE)
+ result = null_pointer_node;
+ else
+ {
+ TREE_USED (label) = 1;
+ result = build1 (ADDR_EXPR, ptr_type_node, label);
+ TREE_CONSTANT (result) = 1;
+ }
+
+ return result;
+}
+
+/* Finish an expression of the form CODE EXPR. */
+
+tree
+finish_unary_op_expr (code, expr)
+ enum tree_code code;
+ tree expr;
+{
+ tree result = build_x_unary_op (code, expr);
+ if (code == NEGATE_EXPR && TREE_CODE (expr) == INTEGER_CST)
+ TREE_NEGATED_INT (result) = 1;
+ overflow_warning (result);
+ return result;
+}
+
+/* Finish an id-expression. */
+
+tree
+finish_id_expr (expr)
+ tree expr;
+{
+ if (TREE_CODE (expr) == IDENTIFIER_NODE)
+ expr = do_identifier (expr, 1, NULL_TREE);
+
+ return expr;
+}
+
+/* Begin a new-placement. */
+
+int
+begin_new_placement ()
+{
+ /* The arguments to a placement new might be passed to a
+ deallocation function, in the event that the allocation throws an
+ exception. Since we don't expand exception handlers until the
+ end of a function, we must make sure the arguments stay around
+ that long. */
+ return suspend_momentary ();
+}
+
+/* Finish a new-placement. The ARGS are the placement arguments. The
+ COOKIE is the value returned by the previous call to
+ begin_new_placement. */
+
+tree
+finish_new_placement (args, cookie)
+ tree args;
+ int cookie;
+{
+ resume_momentary (cookie);
+ return args;
+}
+
+/* Begin a function defniition declared with DECL_SPECS and
+ DECLARATOR. Returns non-zero if the function-declaration is
+ legal. */
+
+int
+begin_function_definition (decl_specs, declarator)
+ tree decl_specs;
+ tree declarator;
+{
+ tree specs;
+ tree attrs;
+ split_specs_attrs (decl_specs, &specs, &attrs);
+ if (!start_function (specs, declarator, attrs, 0))
+ return 0;
+
+ reinit_parse_for_function ();
+ /* The things we're about to see are not directly qualified by any
+ template headers we've seen thus far. */
+ reset_specialization ();
+
+ return 1;
+}
+
+/* Begin a constructor declarator of the form `SCOPE::NAME'. Returns
+ a SCOPE_REF. */
+
+tree
+begin_constructor_declarator (scope, name)
+ tree scope;
+ tree name;
+{
+ tree result = build_parse_node (SCOPE_REF, scope, name);
+ enter_scope_of (result);
+ return result;
+}
+
+/* Finish an init-declarator. Returns a DECL. */
+
+tree
+finish_declarator (declarator, declspecs, attributes,
+ prefix_attributes, initialized)
+ tree declarator;
+ tree declspecs;
+ tree attributes;
+ tree prefix_attributes;
+ int initialized;
+{
+ return start_decl (declarator, declspecs, initialized, attributes,
+ prefix_attributes);
+}
+
+/* Finish a translation unit. */
+
+void
+finish_translation_unit ()
+{
+ /* In case there were missing closebraces,
+ get us back to the global binding level. */
+ while (! toplevel_bindings_p ())
+ poplevel (0, 0, 0);
+ while (current_namespace != global_namespace)
+ pop_namespace ();
+ finish_file ();
+}
+
+/* Finish a template type parameter, specified as AGGR IDENTIFIER.
+ Returns the parameter. */
+
+tree
+finish_template_type_parm (aggr, identifier)
+ tree aggr;
+ tree identifier;
+{
+ if (aggr == signature_type_node)
+ sorry ("signature as template type parameter");
+ else if (aggr != class_type_node)
+ {
+ pedwarn ("template type parameters must use the keyword `class' or `typename'");
+ aggr = class_type_node;
+ }
+
+ return build_tree_list (aggr, identifier);
+}
+
+/* Finish a template template parameter, specified as AGGR IDENTIFIER.
+ Returns the parameter. */
+
+tree
+finish_template_template_parm (aggr, identifier)
+ tree aggr;
+ tree identifier;
+{
+ tree decl = build_decl (TYPE_DECL, identifier, NULL_TREE);
+ tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE);
+ DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
+ DECL_TEMPLATE_RESULT (tmpl) = decl;
+ SET_DECL_ARTIFICIAL (decl);
+ end_template_decl ();
+
+ return finish_template_type_parm (aggr, tmpl);
+}
+
+/* Finish a parameter list, indicated by PARMS. If ELLIPSIS is
+ non-zero, the parameter list was terminated by a `...'. */
+
+tree
+finish_parmlist (parms, ellipsis)
+ tree parms;
+ int ellipsis;
+{
+ if (!ellipsis)
+ chainon (parms, void_list_node);
+ /* We mark the PARMS as a parmlist so that declarator processing can
+ disambiguate certain constructs. */
+ if (parms != NULL_TREE)
+ TREE_PARMLIST (parms) = 1;
+
+ return parms;
+}
+
+/* Begin a class definition, as indicated by T. */
+
+tree
+begin_class_definition (t)
+ tree t;
+{
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ if (t == error_mark_node
+ || ! IS_AGGR_TYPE (t))
+ {
+ t = make_lang_type (RECORD_TYPE);
+ pushtag (make_anon_name (), t, 0);
+ }
+
+ /* In a definition of a member class template, we will get here with an
+ 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;
+ }
+
+ /* 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_BEING_DEFINED (t))
+ {
+ t = make_lang_type (TREE_CODE (t));
+ pushtag (TYPE_IDENTIFIER (t), t, 0);
+ }
+ maybe_process_partial_specialization (t);
+ if (processing_template_decl
+ && ! CLASSTYPE_TEMPLATE_SPECIALIZATION (t)
+ && TYPE_CONTEXT (t) && TYPE_P (TYPE_CONTEXT (t))
+ && ! current_class_type)
+ push_template_decl (TYPE_STUB_DECL (t));
+ pushclass (t, 0);
+ 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;
+ }
+#if 0
+ tmp = TYPE_IDENTIFIER ($<ttype>0);
+ if (tmp && IDENTIFIER_TEMPLATE (tmp))
+ overload_template_name (tmp, 1);
+#endif
+ reset_specialization();
+
+ /* In case this is a local class within a template
+ function, we save the current tree structure so
+ that we can get it back later. */
+ begin_tree ();
+
+ return t;
+}
+
+/* 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 if (TREE_CODE (decl) == TYPE_DECL)
+ /* Historically, DECL_CONTEXT was not set for a TYPE_DECL in
+ finish_struct, so we do not do it here either. Perhaps we
+ should, though. */
+ ;
+ 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;
+ }
+ }
+}
+
+/* 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, attributes, semi)
+ tree t;
+ tree attributes;
+ int semi;
+{
+#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)
+ note_got_semicolon (t);
+
+ /* If we got any attributes in class_head, xref_tag will stick them in
+ TREE_TYPE of the type. Grab them now. */
+ attributes = chainon (TREE_TYPE (t), attributes);
+ TREE_TYPE (t) = NULL_TREE;
+
+ if (TREE_CODE (t) == ENUMERAL_TYPE)
+ ;
+ else
+ {
+ t = finish_struct (t, attributes, semi);
+ if (semi)
+ note_got_semicolon (t);
+ }
+
+ pop_obstacks ();
+
+ if (! semi)
+ check_for_missing_semicolon (t);
+ if (current_scope () == current_function_decl)
+ do_pending_defargs ();
+
+ return t;
+}
+
+/* Finish processing the default argument expressions cached during
+ the processing of a class definition. */
+
+void
+finish_default_args ()
+{
+ if (pending_inlines
+ && current_scope () == current_function_decl)
+ do_pending_inlines ();
+}
+
+/* Finish processing the inline function definitions cached during the
+ processing of a class definition. */
+
+void
+begin_inline_definitions ()
+{
+ if (current_class_type == NULL_TREE)
+ clear_inline_text_obstack ();
+
+ /* Undo the begin_tree in begin_class_definition. */
+ end_tree ();
+}
+
+/* Finish processing the declaration of a member class template
+ TYPES whose template parameters are given by PARMS. */
+
+tree
+finish_member_class_template (types)
+ tree types;
+{
+ tree t;
+
+ /* If there are declared, but undefined, partial specializations
+ mixed in with the typespecs they will not yet have passed through
+ maybe_process_partial_specialization, so we do that here. */
+ for (t = types; t != NULL_TREE; t = TREE_CHAIN (t))
+ if (IS_AGGR_TYPE_CODE (TREE_CODE (TREE_VALUE (t))))
+ maybe_process_partial_specialization (TREE_VALUE (t));
+
+ note_list_got_semicolon (types);
+ 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 (types);
+
+ /* As with other component type declarations, we do
+ not store the new DECL on the list of
+ component_decls. */
+ return NULL_TREE;
+}
+
+/* Finish processsing a complete template declaration. The PARMS are
+ the template parameters. */
+
+void
+finish_template_decl (parms)
+ tree parms;
+{
+ if (parms)
+ end_template_decl ();
+ else
+ end_specialization ();
+}
+
+/* Finish processing a a template-id (which names a type) of the form
+ NAME < ARGS >. Return the TYPE_DECL for the type named by the
+ template-id. If ENTERING_SCOPE is non-zero we are about to enter
+ the scope of template-id indicated. */
+
+tree
+finish_template_type (name, args, entering_scope)
+ tree name;
+ tree args;
+ int entering_scope;
+{
+ tree decl;
+
+ decl = lookup_template_class (name, args,
+ NULL_TREE, NULL_TREE, entering_scope);
+ if (decl != error_mark_node)
+ decl = TYPE_STUB_DECL (decl);
+
+ return decl;
+}
+
+/* SR is a SCOPE_REF node. Enter the scope of SR, whether it is a
+ namespace scope or a class scope. */
+
+void
+enter_scope_of (sr)
+ tree sr;
+{
+ tree scope = TREE_OPERAND (sr, 0);
+
+ if (TREE_CODE (scope) == NAMESPACE_DECL)
+ {
+ push_decl_namespace (scope);
+ TREE_COMPLEXITY (sr) = -1;
+ }
+ else if (scope != current_class_type)
+ {
+ if (TREE_CODE (scope) == TYPENAME_TYPE)
+ {
+ /* In a declarator for a template class member, the scope will
+ get here as an implicit typename, a TYPENAME_TYPE with a type. */
+ scope = TREE_TYPE (scope);
+ TREE_OPERAND (sr, 0) = scope;
+ }
+ push_nested_class (scope, 3);
+ TREE_COMPLEXITY (sr) = current_class_depth;
+ }
+}
+
+/* Finish processing a BASE_CLASS with the indicated ACCESS_SPECIFIER.
+ Return a TREE_LIST containing the ACCESS_SPECIFIER and the
+ BASE_CLASS, or NULL_TREE if an error occurred. The
+ ACCESSS_SPECIFIER is one of
+ access_{default,public,protected_private}[_virtual]_node.*/
+
+tree
+finish_base_specifier (access_specifier, base_class,
+ current_aggr_is_signature)
+ tree access_specifier;
+ tree base_class;
+ int current_aggr_is_signature;
+{
+ tree type;
+ tree result;
+
+ if (base_class == NULL_TREE)
+ {
+ error ("invalid base class");
+ type = error_mark_node;
+ }
+ 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)))
+ {
+ error ("class name not allowed as base signature");
+ result = NULL_TREE;
+ }
+ else if (current_aggr_is_signature)
+ {
+ sorry ("signature inheritance, base type `%s' ignored",
+ IDENTIFIER_POINTER (access_specifier));
+ result = build_tree_list (access_public_node, type);
+ }
+ else if (type && IS_SIGNATURE (type))
+ {
+ error ("signature name not allowed as base class");
+ result = NULL_TREE;
+ }
+ 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)
+ {
+ tree t;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ t = make_lang_type (TYPEOF_TYPE);
+ TYPE_FIELDS (t) = expr;
+
+ pop_obstacks ();
+
+ return t;
+ }
+
+ return TREE_TYPE (expr);
+}