summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/cp/semantics.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc/cp/semantics.c')
-rw-r--r--contrib/gcc/cp/semantics.c2558
1 files changed, 1475 insertions, 1083 deletions
diff --git a/contrib/gcc/cp/semantics.c b/contrib/gcc/cp/semantics.c
index 110eb3a..966b004 100644
--- a/contrib/gcc/cp/semantics.c
+++ b/contrib/gcc/cp/semantics.c
@@ -3,29 +3,32 @@
building RTL. These routines are used both during actual parsing
and during the instantiation of template functions.
- Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002,
+ 2003, 2004 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.
+ This file is part of GCC.
- GNU CC is free software; you can redistribute it and/or modify it
+ GCC 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
+ GCC 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
+ along with GCC; 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 "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "cp-tree.h"
#include "tree-inline.h"
@@ -33,12 +36,12 @@
#include "lex.h"
#include "toplev.h"
#include "flags.h"
-#include "ggc.h"
#include "rtl.h"
#include "expr.h"
#include "output.h"
#include "timevar.h"
#include "debug.h"
+#include "cgraph.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
@@ -49,18 +52,14 @@
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 maybe_convert_cond PARAMS ((tree));
-static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
-static void deferred_type_access_control PARAMS ((void));
-static void emit_associated_thunks PARAMS ((tree));
-static void genrtl_try_block PARAMS ((tree));
-static void genrtl_eh_spec_block PARAMS ((tree));
-static void genrtl_handler PARAMS ((tree));
-static void genrtl_named_return_value PARAMS ((void));
-static void cp_expand_stmt PARAMS ((tree));
-static void genrtl_start_function PARAMS ((tree));
-static void genrtl_finish_function PARAMS ((tree));
-static tree clear_decl_rtl PARAMS ((tree *, int *, void *));
+static tree maybe_convert_cond (tree);
+static tree simplify_aggr_init_exprs_r (tree *, int *, void *);
+static void emit_associated_thunks (tree);
+static void genrtl_try_block (tree);
+static void genrtl_eh_spec_block (tree);
+static void genrtl_handler (tree);
+static void cp_expand_stmt (tree);
+
/* Finish processing the COND, the SUBSTMT condition for STMT. */
@@ -79,12 +78,233 @@ static tree clear_decl_rtl PARAMS ((tree *, int *, void *));
(SUBSTMT) = (COND); \
} while (0)
+/* Deferred Access Checking Overview
+ ---------------------------------
+
+ Most C++ expressions and declarations require access checking
+ to be performed during parsing. However, in several cases,
+ this has to be treated differently.
+
+ For member declarations, access checking has to be deferred
+ until more information about the declaration is known. For
+ example:
+
+ class A {
+ typedef int X;
+ public:
+ X f();
+ };
+
+ A::X A::f();
+ A::X g();
+
+ When we are parsing the function return type `A::X', we don't
+ really know if this is allowed until we parse the function name.
+
+ Furthermore, some contexts require that access checking is
+ never performed at all. These include class heads, and template
+ instantiations.
+
+ Typical use of access checking functions is described here:
+
+ 1. When we enter a context that requires certain access checking
+ mode, the function `push_deferring_access_checks' is called with
+ DEFERRING argument specifying the desired mode. Access checking
+ may be performed immediately (dk_no_deferred), deferred
+ (dk_deferred), or not performed (dk_no_check).
+
+ 2. When a declaration such as a type, or a variable, is encountered,
+ the function `perform_or_defer_access_check' is called. It
+ maintains a TREE_LIST of all deferred checks.
+
+ 3. The global `current_class_type' or `current_function_decl' is then
+ setup by the parser. `enforce_access' relies on these information
+ to check access.
+
+ 4. Upon exiting the context mentioned in step 1,
+ `perform_deferred_access_checks' is called to check all declaration
+ stored in the TREE_LIST. `pop_deferring_access_checks' is then
+ called to restore the previous access checking mode.
+
+ In case of parsing error, we simply call `pop_deferring_access_checks'
+ without `perform_deferred_access_checks'. */
+
+/* Data for deferred access checking. */
+static GTY(()) deferred_access *deferred_access_stack;
+static GTY(()) deferred_access *deferred_access_free_list;
+
+/* Save the current deferred access states and start deferred
+ access checking iff DEFER_P is true. */
+
+void
+push_deferring_access_checks (deferring_kind deferring)
+{
+ deferred_access *d;
+
+ /* For context like template instantiation, access checking
+ disabling applies to all nested context. */
+ if (deferred_access_stack
+ && deferred_access_stack->deferring_access_checks_kind == dk_no_check)
+ deferring = dk_no_check;
+
+ /* Recycle previously used free store if available. */
+ if (deferred_access_free_list)
+ {
+ d = deferred_access_free_list;
+ deferred_access_free_list = d->next;
+ }
+ else
+ d = ggc_alloc (sizeof (deferred_access));
+
+ d->next = deferred_access_stack;
+ d->deferred_access_checks = NULL_TREE;
+ d->deferring_access_checks_kind = deferring;
+ deferred_access_stack = d;
+}
+
+/* Resume deferring access checks again after we stopped doing
+ this previously. */
+
+void
+resume_deferring_access_checks (void)
+{
+ if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred)
+ deferred_access_stack->deferring_access_checks_kind = dk_deferred;
+}
+
+/* Stop deferring access checks. */
+
+void
+stop_deferring_access_checks (void)
+{
+ if (deferred_access_stack->deferring_access_checks_kind == dk_deferred)
+ deferred_access_stack->deferring_access_checks_kind = dk_no_deferred;
+}
+
+/* Discard the current deferred access checks and restore the
+ previous states. */
+
+void
+pop_deferring_access_checks (void)
+{
+ deferred_access *d = deferred_access_stack;
+ deferred_access_stack = d->next;
+
+ /* Remove references to access checks TREE_LIST. */
+ d->deferred_access_checks = NULL_TREE;
+
+ /* Store in free list for later use. */
+ d->next = deferred_access_free_list;
+ deferred_access_free_list = d;
+}
+
+/* Returns a TREE_LIST representing the deferred checks.
+ The TREE_PURPOSE of each node is the type through which the
+ access occurred; the TREE_VALUE is the declaration named.
+ */
+
+tree
+get_deferred_access_checks (void)
+{
+ return deferred_access_stack->deferred_access_checks;
+}
+
+/* Take current deferred checks and combine with the
+ previous states if we also defer checks previously.
+ Otherwise perform checks now. */
+
+void
+pop_to_parent_deferring_access_checks (void)
+{
+ tree deferred_check = get_deferred_access_checks ();
+ deferred_access *d1 = deferred_access_stack;
+ deferred_access *d2 = deferred_access_stack->next;
+ deferred_access *d3 = deferred_access_stack->next->next;
+
+ /* Temporary swap the order of the top two states, just to make
+ sure the garbage collector will not reclaim the memory during
+ processing below. */
+ deferred_access_stack = d2;
+ d2->next = d1;
+ d1->next = d3;
+
+ for ( ; deferred_check; deferred_check = TREE_CHAIN (deferred_check))
+ /* Perform deferred check if required. */
+ perform_or_defer_access_check (TREE_PURPOSE (deferred_check),
+ TREE_VALUE (deferred_check));
+
+ deferred_access_stack = d1;
+ d1->next = d2;
+ d2->next = d3;
+ pop_deferring_access_checks ();
+}
+
+/* Perform the deferred access checks.
+
+ After performing the checks, we still have to keep the list
+ `deferred_access_stack->deferred_access_checks' since we may want
+ to check access for them again later in a different context.
+ For example:
+
+ class A {
+ typedef int X;
+ static X a;
+ };
+ A::X A::a, x; // No error for `A::a', error for `x'
+
+ We have to perform deferred access of `A::X', first with `A::a',
+ next with `x'. */
+
+void
+perform_deferred_access_checks (void)
+{
+ tree deferred_check;
+ for (deferred_check = deferred_access_stack->deferred_access_checks;
+ deferred_check;
+ deferred_check = TREE_CHAIN (deferred_check))
+ /* Check access. */
+ enforce_access (TREE_PURPOSE (deferred_check),
+ TREE_VALUE (deferred_check));
+}
+
+/* Defer checking the accessibility of DECL, when looked up in
+ BINFO. */
+
+void
+perform_or_defer_access_check (tree binfo, tree decl)
+{
+ tree check;
+
+ my_friendly_assert (TREE_CODE (binfo) == TREE_VEC, 20030623);
+
+ /* If we are not supposed to defer access checks, just check now. */
+ if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred)
+ {
+ enforce_access (binfo, decl);
+ return;
+ }
+ /* Exit if we are in a context that no access checking is performed. */
+ else if (deferred_access_stack->deferring_access_checks_kind == dk_no_check)
+ return;
+
+ /* See if we are already going to perform this check. */
+ for (check = deferred_access_stack->deferred_access_checks;
+ check;
+ check = TREE_CHAIN (check))
+ if (TREE_VALUE (check) == decl && TREE_PURPOSE (check) == binfo)
+ return;
+ /* If not, record the check. */
+ deferred_access_stack->deferred_access_checks
+ = tree_cons (binfo, decl,
+ deferred_access_stack->deferred_access_checks);
+}
+
/* Returns nonzero if the current statement is a full expression,
i.e. temporaries created during that statement should be destroyed
at the end of the statement. */
int
-stmts_are_full_exprs_p ()
+stmts_are_full_exprs_p (void)
{
return current_stmt_tree ()->stmts_are_full_exprs_p;
}
@@ -94,7 +314,7 @@ stmts_are_full_exprs_p ()
returned. */
stmt_tree
-current_stmt_tree ()
+current_stmt_tree (void)
{
return (cfun
? &cfun->language->base.x_stmt_tree
@@ -106,8 +326,7 @@ current_stmt_tree ()
declared is not an anonymous union" [class.union]. */
int
-anon_aggr_type_p (node)
- tree node;
+anon_aggr_type_p (tree node)
{
return ANON_AGGR_TYPE_P (node);
}
@@ -115,7 +334,7 @@ anon_aggr_type_p (node)
/* Finish a scope. */
tree
-do_poplevel ()
+do_poplevel (void)
{
tree block = NULL_TREE;
@@ -123,14 +342,17 @@ do_poplevel ()
{
tree scope_stmts = NULL_TREE;
- if (!processing_template_decl)
- scope_stmts = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
-
block = poplevel (kept_level_p (), 1, 0);
- if (block && !processing_template_decl)
+ if (!processing_template_decl)
{
- SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block;
- SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block;
+ /* This needs to come after the poplevel so that partial scopes
+ are properly nested. */
+ scope_stmts = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
+ if (block)
+ {
+ SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block;
+ SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block;
+ }
}
}
@@ -140,21 +362,20 @@ do_poplevel ()
/* Begin a new scope. */
void
-do_pushlevel ()
+do_pushlevel (scope_kind sk)
{
if (stmts_are_full_exprs_p ())
{
- pushlevel (0);
if (!processing_template_decl)
add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
+ begin_scope (sk, NULL);
}
}
/* Finish a goto-statement. */
tree
-finish_goto_stmt (destination)
- tree destination;
+finish_goto_stmt (tree destination)
{
if (TREE_CODE (destination) == IDENTIFIER_NODE)
destination = lookup_label (destination);
@@ -163,13 +384,17 @@ finish_goto_stmt (destination)
mark the used labels as used. */
if (TREE_CODE (destination) == LABEL_DECL)
TREE_USED (destination) = 1;
-
- if (TREE_CODE (destination) != LABEL_DECL)
- /* We don't inline calls to functions with computed gotos.
- Those functions are typically up to some funny business,
- and may be depending on the labels being at particular
- addresses, or some such. */
- DECL_UNINLINABLE (current_function_decl) = 1;
+ else
+ {
+ /* The DESTINATION is being used as an rvalue. */
+ if (!processing_template_decl)
+ destination = decay_conversion (destination);
+ /* We don't inline calls to functions with computed gotos.
+ Those functions are typically up to some funny business,
+ and may be depending on the labels being at particular
+ addresses, or some such. */
+ DECL_UNINLINABLE (current_function_decl) = 1;
+ }
check_goto (destination);
@@ -179,9 +404,8 @@ finish_goto_stmt (destination)
/* COND is the condition-expression for an if, while, etc.,
statement. Convert it to a boolean value, if appropriate. */
-tree
-maybe_convert_cond (cond)
- tree cond;
+static tree
+maybe_convert_cond (tree cond)
{
/* Empty conditions remain empty. */
if (!cond)
@@ -199,36 +423,22 @@ maybe_convert_cond (cond)
/* Finish an expression-statement, whose EXPRESSION is as indicated. */
tree
-finish_expr_stmt (expr)
- tree expr;
+finish_expr_stmt (tree expr)
{
tree r = NULL_TREE;
- tree expr_type = NULL_TREE;;
if (expr != NULL_TREE)
{
- if (!processing_template_decl
- && !(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);
-
- /* Remember the type of the expression. */
- expr_type = TREE_TYPE (expr);
-
- if (stmts_are_full_exprs_p ())
+ if (!processing_template_decl)
expr = convert_to_void (expr, "statement");
+ else if (!type_dependent_expression_p (expr))
+ convert_to_void (build_non_dependent_expr (expr), "statement");
r = add_stmt (build_stmt (EXPR_STMT, expr));
}
finish_stmt ();
- /* This was an expression-statement, so we save the type of the
- expression. */
- last_expr_type = expr_type;
-
return r;
}
@@ -237,10 +447,10 @@ finish_expr_stmt (expr)
appropriate. */
tree
-begin_if_stmt ()
+begin_if_stmt (void)
{
tree r;
- do_pushlevel ();
+ do_pushlevel (sk_block);
r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
add_stmt (r);
return r;
@@ -250,9 +460,7 @@ begin_if_stmt ()
IF_STMT. */
void
-finish_if_stmt_cond (cond, if_stmt)
- tree cond;
- tree if_stmt;
+finish_if_stmt_cond (tree cond, tree if_stmt)
{
cond = maybe_convert_cond (cond);
FINISH_COND (cond, if_stmt, IF_COND (if_stmt));
@@ -262,8 +470,7 @@ finish_if_stmt_cond (cond, if_stmt)
IF_STMT. */
tree
-finish_then_clause (if_stmt)
- tree if_stmt;
+finish_then_clause (tree if_stmt)
{
RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
return if_stmt;
@@ -272,7 +479,7 @@ finish_then_clause (if_stmt)
/* Begin the else-clause of an if-statement. */
void
-begin_else_clause ()
+begin_else_clause (void)
{
}
@@ -280,8 +487,7 @@ begin_else_clause ()
IF_STMT. */
void
-finish_else_clause (if_stmt)
- tree if_stmt;
+finish_else_clause (tree if_stmt)
{
RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
}
@@ -289,7 +495,7 @@ finish_else_clause (if_stmt)
/* Finish an if-statement. */
void
-finish_if_stmt ()
+finish_if_stmt (void)
{
finish_stmt ();
do_poplevel ();
@@ -299,12 +505,12 @@ finish_if_stmt ()
appropriate. */
tree
-begin_while_stmt ()
+begin_while_stmt (void)
{
tree r;
r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
add_stmt (r);
- do_pushlevel ();
+ do_pushlevel (sk_block);
return r;
}
@@ -312,9 +518,7 @@ begin_while_stmt ()
WHILE_STMT. */
void
-finish_while_stmt_cond (cond, while_stmt)
- tree cond;
- tree while_stmt;
+finish_while_stmt_cond (tree cond, tree while_stmt)
{
cond = maybe_convert_cond (cond);
if (processing_template_decl)
@@ -345,8 +549,7 @@ finish_while_stmt_cond (cond, while_stmt)
/* Finish a while-statement, which may be given by WHILE_STMT. */
void
-finish_while_stmt (while_stmt)
- tree while_stmt;
+finish_while_stmt (tree while_stmt)
{
do_poplevel ();
RECHAIN_STMTS (while_stmt, WHILE_BODY (while_stmt));
@@ -357,7 +560,7 @@ finish_while_stmt (while_stmt)
appropriate. */
tree
-begin_do_stmt ()
+begin_do_stmt (void)
{
tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE);
add_stmt (r);
@@ -367,8 +570,7 @@ begin_do_stmt ()
/* Finish the body of a do-statement, which may be given by DO_STMT. */
void
-finish_do_body (do_stmt)
- tree do_stmt;
+finish_do_body (tree do_stmt)
{
RECHAIN_STMTS (do_stmt, DO_BODY (do_stmt));
}
@@ -377,9 +579,7 @@ finish_do_body (do_stmt)
COND is as indicated. */
void
-finish_do_stmt (cond, do_stmt)
- tree cond;
- tree do_stmt;
+finish_do_stmt (tree cond, tree do_stmt)
{
cond = maybe_convert_cond (cond);
DO_COND (do_stmt) = cond;
@@ -390,13 +590,11 @@ finish_do_stmt (cond, do_stmt)
indicated. */
tree
-finish_return_stmt (expr)
- tree expr;
+finish_return_stmt (tree expr)
{
tree r;
- if (!processing_template_decl)
- expr = check_return_expr (expr);
+ expr = check_return_expr (expr);
if (!processing_template_decl)
{
if (DECL_DESTRUCTOR_P (current_function_decl))
@@ -417,7 +615,7 @@ finish_return_stmt (expr)
/* Begin a for-statement. Returns a new FOR_STMT if appropriate. */
tree
-begin_for_stmt ()
+begin_for_stmt (void)
{
tree r;
@@ -425,10 +623,7 @@ begin_for_stmt ()
NULL_TREE, NULL_TREE);
NEW_FOR_SCOPE_P (r) = flag_new_for_scope > 0;
if (NEW_FOR_SCOPE_P (r))
- {
- do_pushlevel ();
- note_level_for_for ();
- }
+ do_pushlevel (sk_for);
add_stmt (r);
return r;
@@ -438,21 +633,18 @@ begin_for_stmt ()
given by FOR_STMT. */
void
-finish_for_init_stmt (for_stmt)
- tree for_stmt;
+finish_for_init_stmt (tree for_stmt)
{
if (last_tree != for_stmt)
RECHAIN_STMTS (for_stmt, FOR_INIT_STMT (for_stmt));
- do_pushlevel ();
+ do_pushlevel (sk_block);
}
/* 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;
+finish_for_cond (tree cond, tree for_stmt)
{
cond = maybe_convert_cond (cond);
if (processing_template_decl)
@@ -484,10 +676,15 @@ finish_for_cond (cond, for_stmt)
given by FOR_STMT. */
void
-finish_for_expr (expr, for_stmt)
- tree expr;
- tree for_stmt;
+finish_for_expr (tree expr, tree for_stmt)
{
+ /* If EXPR is an overloaded function, issue an error; there is no
+ context available to use to perform overload resolution. */
+ if (expr && type_unknown_p (expr))
+ {
+ cxx_incomplete_type_error (expr, TREE_TYPE (expr));
+ expr = error_mark_node;
+ }
FOR_EXPR (for_stmt) = expr;
}
@@ -496,8 +693,7 @@ finish_for_expr (expr, for_stmt)
provided. */
void
-finish_for_stmt (for_stmt)
- tree for_stmt;
+finish_for_stmt (tree for_stmt)
{
/* Pop the scope for the body of the loop. */
do_poplevel ();
@@ -510,7 +706,7 @@ finish_for_stmt (for_stmt)
/* Finish a break-statement. */
tree
-finish_break_stmt ()
+finish_break_stmt (void)
{
return add_stmt (build_break_stmt ());
}
@@ -518,7 +714,7 @@ finish_break_stmt ()
/* Finish a continue-statement. */
tree
-finish_continue_stmt ()
+finish_continue_stmt (void)
{
return add_stmt (build_continue_stmt ());
}
@@ -527,10 +723,10 @@ finish_continue_stmt ()
appropriate. */
tree
-begin_switch_stmt ()
+begin_switch_stmt (void)
{
tree r;
- do_pushlevel ();
+ do_pushlevel (sk_block);
r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
add_stmt (r);
return r;
@@ -539,9 +735,7 @@ begin_switch_stmt ()
/* Finish the cond of a switch-statement. */
void
-finish_switch_cond (cond, switch_stmt)
- tree cond;
- tree switch_stmt;
+finish_switch_cond (tree cond, tree switch_stmt)
{
tree orig_type = NULL;
if (!processing_template_decl)
@@ -549,7 +743,7 @@ finish_switch_cond (cond, switch_stmt)
tree index;
/* Convert the condition to an integer or enumeration type. */
- cond = build_expr_type_conversion (WANT_INT | WANT_ENUM, cond, 1);
+ cond = build_expr_type_conversion (WANT_INT | WANT_ENUM, cond, true);
if (cond == NULL_TREE)
{
error ("switch quantity not an integer");
@@ -558,7 +752,10 @@ finish_switch_cond (cond, switch_stmt)
orig_type = TREE_TYPE (cond);
if (cond != error_mark_node)
{
- cond = default_conversion (cond);
+ /* [stmt.switch]
+
+ Integral promotions are performed. */
+ cond = perform_integral_promotions (cond);
cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond));
}
@@ -583,8 +780,7 @@ finish_switch_cond (cond, switch_stmt)
SWITCH_STMT. The COND to switch on is indicated. */
void
-finish_switch_stmt (switch_stmt)
- tree switch_stmt;
+finish_switch_stmt (tree switch_stmt)
{
RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt));
pop_switch ();
@@ -595,8 +791,7 @@ finish_switch_stmt (switch_stmt)
/* Generate the RTL for T, which is a TRY_BLOCK. */
static void
-genrtl_try_block (t)
- tree t;
+genrtl_try_block (tree t)
{
if (CLEANUP_P (t))
{
@@ -607,7 +802,7 @@ genrtl_try_block (t)
else
{
if (!FN_TRY_BLOCK_P (t))
- emit_line_note (input_filename, lineno);
+ emit_line_note (input_location);
expand_eh_region_start ();
expand_stmt (TRY_STMTS (t));
@@ -632,8 +827,7 @@ genrtl_try_block (t)
/* Generate the RTL for T, which is an EH_SPEC_BLOCK. */
static void
-genrtl_eh_spec_block (t)
- tree t;
+genrtl_eh_spec_block (tree t)
{
expand_eh_region_start ();
expand_stmt (EH_SPEC_STMTS (t));
@@ -648,7 +842,7 @@ genrtl_eh_spec_block (t)
appropriate. */
tree
-begin_try_block ()
+begin_try_block (void)
{
tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
add_stmt (r);
@@ -658,7 +852,7 @@ begin_try_block ()
/* Likewise, for a function-try-block. */
tree
-begin_function_try_block ()
+begin_function_try_block (void)
{
tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
FN_TRY_BLOCK_P (r) = 1;
@@ -669,8 +863,7 @@ begin_function_try_block ()
/* Finish a try-block, which may be given by TRY_BLOCK. */
void
-finish_try_block (try_block)
- tree try_block;
+finish_try_block (tree try_block)
{
RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
}
@@ -679,8 +872,7 @@ finish_try_block (try_block)
TRY_BLOCK. */
void
-finish_cleanup_try_block (try_block)
- tree try_block;
+finish_cleanup_try_block (tree try_block)
{
RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
}
@@ -689,9 +881,7 @@ finish_cleanup_try_block (try_block)
by CLEANUP. */
void
-finish_cleanup (cleanup, try_block)
- tree cleanup;
- tree try_block;
+finish_cleanup (tree cleanup, tree try_block)
{
TRY_HANDLERS (try_block) = cleanup;
CLEANUP_P (try_block) = 1;
@@ -700,8 +890,7 @@ finish_cleanup (cleanup, try_block)
/* Likewise, for a function-try-block. */
void
-finish_function_try_block (try_block)
- tree try_block;
+finish_function_try_block (tree try_block)
{
if (TREE_CHAIN (try_block)
&& TREE_CODE (TREE_CHAIN (try_block)) == CTOR_INITIALIZER)
@@ -720,8 +909,7 @@ finish_function_try_block (try_block)
TRY_BLOCK. */
void
-finish_handler_sequence (try_block)
- tree try_block;
+finish_handler_sequence (tree try_block)
{
RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
check_handlers (TRY_HANDLERS (try_block));
@@ -730,8 +918,7 @@ finish_handler_sequence (try_block)
/* Likewise, for a function-try-block. */
void
-finish_function_handler_sequence (try_block)
- tree try_block;
+finish_function_handler_sequence (tree try_block)
{
in_function_try_handler = 0;
RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
@@ -741,8 +928,7 @@ finish_function_handler_sequence (try_block)
/* Generate the RTL for T, which is a HANDLER. */
static void
-genrtl_handler (t)
- tree t;
+genrtl_handler (tree t)
{
genrtl_do_pushlevel ();
if (!processing_template_decl)
@@ -755,15 +941,14 @@ genrtl_handler (t)
/* Begin a handler. Returns a HANDLER if appropriate. */
tree
-begin_handler ()
+begin_handler (void)
{
tree r;
r = build_stmt (HANDLER, NULL_TREE, NULL_TREE);
add_stmt (r);
/* Create a binding level for the eh_info and the exception object
cleanup. */
- do_pushlevel ();
- note_level_for_catch ();
+ do_pushlevel (sk_catch);
return r;
}
@@ -772,9 +957,7 @@ begin_handler ()
if this is a `catch (...)' clause. */
void
-finish_handler_parms (decl, handler)
- tree decl;
- tree handler;
+finish_handler_parms (tree decl, tree handler)
{
tree type = NULL_TREE;
if (processing_template_decl)
@@ -792,14 +975,15 @@ finish_handler_parms (decl, handler)
type = expand_start_catch_block (decl);
HANDLER_TYPE (handler) = type;
+ if (!processing_template_decl && type)
+ mark_used (eh_type_info (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 (handler)
- tree handler;
+finish_handler (tree handler)
{
if (!processing_template_decl)
expand_end_catch_block ();
@@ -807,13 +991,12 @@ finish_handler (handler)
RECHAIN_STMTS (handler, HANDLER_BODY (handler));
}
-/* Begin a compound-statement. If HAS_NO_SCOPE is nonzero, the
+/* Begin a compound-statement. If HAS_NO_SCOPE is true, the
compound-statement does not define a scope. Returns a new
- COMPOUND_STMT if appropriate. */
+ COMPOUND_STMT. */
tree
-begin_compound_stmt (has_no_scope)
- int has_no_scope;
+begin_compound_stmt (bool has_no_scope)
{
tree r;
int is_try = 0;
@@ -830,37 +1013,29 @@ begin_compound_stmt (has_no_scope)
last_expr_type = NULL_TREE;
if (!has_no_scope)
- {
- do_pushlevel ();
- if (is_try)
- note_level_for_try ();
- }
+ do_pushlevel (is_try ? sk_try : sk_block);
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);
+ keep_next_level (false);
return r;
}
-/* Finish a compound-statement, which may be given by COMPOUND_STMT.
- If HAS_NO_SCOPE is nonzero, the compound statement does not define
- a scope. */
+/* Finish a compound-statement, which is given by COMPOUND_STMT. */
tree
-finish_compound_stmt (has_no_scope, compound_stmt)
- int has_no_scope;
- tree compound_stmt;
+finish_compound_stmt (tree compound_stmt)
{
tree r;
tree t;
- if (!has_no_scope)
- r = do_poplevel ();
- else
+ if (COMPOUND_STMT_NO_SCOPE (compound_stmt))
r = NULL_TREE;
+ else
+ r = do_poplevel ();
RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_stmt));
@@ -880,13 +1055,11 @@ finish_compound_stmt (has_no_scope, compound_stmt)
CLOBBERS. */
tree
-finish_asm_stmt (cv_qualifier, string, output_operands,
- input_operands, clobbers)
- tree cv_qualifier;
- tree string;
- tree output_operands;
- tree input_operands;
- tree clobbers;
+finish_asm_stmt (tree cv_qualifier,
+ tree string,
+ tree output_operands,
+ tree input_operands,
+ tree clobbers)
{
tree r;
tree t;
@@ -943,9 +1116,9 @@ finish_asm_stmt (cv_qualifier, string, output_operands,
&allows_reg,
&is_inout))
{
- /* By marking the type as erroneous, we will not try to
- process this operand again in expand_asm_operands. */
- TREE_TYPE (operand) = error_mark_node;
+ /* By marking this operand as erroneous, we will not try
+ to process this operand again in expand_asm_operands. */
+ TREE_VALUE (t) = error_mark_node;
continue;
}
@@ -968,12 +1141,11 @@ finish_asm_stmt (cv_qualifier, string, output_operands,
/* Finish a label with the indicated NAME. */
-void
-finish_label_stmt (name)
- tree name;
+tree
+finish_label_stmt (tree name)
{
- tree decl = define_label (input_filename, lineno, name);
- add_stmt (build_stmt (LABEL_STMT, decl));
+ tree decl = define_label (input_location, name);
+ return add_stmt (build_stmt (LABEL_STMT, decl));
}
/* Finish a series of declarations for local labels. G++ allows users
@@ -981,8 +1153,7 @@ finish_label_stmt (name)
is useful when writing code involving statement-expressions. */
void
-finish_label_decl (name)
- tree name;
+finish_label_decl (tree name)
{
tree decl = declare_local_label (name);
add_decl_stmt (decl);
@@ -991,9 +1162,7 @@ finish_label_decl (name)
/* When DECL goes out of scope, make sure that CLEANUP is executed. */
void
-finish_decl_cleanup (decl, cleanup)
- tree decl;
- tree cleanup;
+finish_decl_cleanup (tree decl, tree cleanup)
{
add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
}
@@ -1001,105 +1170,13 @@ finish_decl_cleanup (decl, cleanup)
/* If the current scope exits with an exception, run CLEANUP. */
void
-finish_eh_cleanup (cleanup)
- tree cleanup;
+finish_eh_cleanup (tree cleanup)
{
tree r = build_stmt (CLEANUP_STMT, NULL_TREE, cleanup);
CLEANUP_EH_ONLY (r) = 1;
add_stmt (r);
}
-/* Generate the RTL for a RETURN_INIT. */
-
-static void
-genrtl_named_return_value ()
-{
- tree decl = DECL_RESULT (current_function_decl);
-
- /* If this named return value comes in a register, put it in a
- pseudo-register. */
- if (DECL_REGISTER (decl))
- {
- /* Note that the mode of the old DECL_RTL may be wider than the
- mode of DECL_RESULT, depending on the calling conventions for
- the processor. For example, on the Alpha, a 32-bit integer
- is returned in a DImode register -- the DECL_RESULT has
- SImode but the DECL_RTL for the DECL_RESULT has DImode. So,
- here, we use the mode the back-end has already assigned for
- the return value. */
- SET_DECL_RTL (decl, gen_reg_rtx (GET_MODE (DECL_RTL (decl))));
- if (TREE_ADDRESSABLE (decl))
- put_var_into_stack (decl, /*rescan=*/true);
- }
-
- emit_local_var (decl);
-}
-
-/* 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);
-
- /* 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. */
- if (pedantic)
- pedwarn ("ISO C++ does not permit named return values");
- cp_deprecated ("the named return value extension");
-
- if (return_id != NULL_TREE)
- {
- if (DECL_NAME (decl) == NULL_TREE)
- DECL_NAME (decl) = return_id;
- else
- {
- error ("return identifier `%D' already in place", return_id);
- return;
- }
- }
-
- /* 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 (!processing_template_decl)
- {
- cp_finish_decl (decl, init, NULL_TREE, 0);
- add_stmt (build_stmt (RETURN_INIT, NULL_TREE, NULL_TREE));
- }
- else
- add_stmt (build_stmt (RETURN_INIT, return_id, init));
- }
-
- /* Don't use tree-inlining for functions with named return values.
- That doesn't work properly because we don't do any translation of
- the RETURN_INITs when they are copied. */
- DECL_UNINLINABLE (current_function_decl) = 1;
-}
-
-/* Begin processing a mem-initializer-list. */
-
-void
-begin_mem_initializers ()
-{
- if (! DECL_CONSTRUCTOR_P (current_function_decl))
- error ("only constructors take base initializers");
-}
-
/* The MEM_INITS is a list of mem-initializers, in reverse of the
order they were written by the user. Each node is as for
emit_mem_initializers. */
@@ -1120,7 +1197,7 @@ finish_mem_initializers (tree mem_inits)
/* Returns the stack of SCOPE_STMTs for the current function. */
tree *
-current_scope_stmt_stack ()
+current_scope_stmt_stack (void)
{
return &cfun->language->base.x_scope_stmt_stack;
}
@@ -1128,8 +1205,7 @@ current_scope_stmt_stack ()
/* Finish a parenthesized expression EXPR. */
tree
-finish_parenthesized_expr (expr)
- tree expr;
+finish_parenthesized_expr (tree expr)
{
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expr))))
/* This inhibits warnings in c_common_truthvalue_conversion. */
@@ -1142,11 +1218,209 @@ finish_parenthesized_expr (expr)
return expr;
}
+/* Finish a reference to a non-static data member (DECL) that is not
+ preceded by `.' or `->'. */
+
+tree
+finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
+{
+ my_friendly_assert (TREE_CODE (decl) == FIELD_DECL, 20020909);
+
+ if (!object)
+ {
+ if (current_function_decl
+ && DECL_STATIC_FUNCTION_P (current_function_decl))
+ cp_error_at ("invalid use of member `%D' in static member function",
+ decl);
+ else
+ cp_error_at ("invalid use of non-static data member `%D'", decl);
+ error ("from this location");
+
+ return error_mark_node;
+ }
+ TREE_USED (current_class_ptr) = 1;
+ if (processing_template_decl && !qualifying_scope)
+ {
+ tree type = TREE_TYPE (decl);
+
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+ else
+ {
+ /* Set the cv qualifiers. */
+ int quals = cp_type_quals (TREE_TYPE (current_class_ref));
+
+ if (DECL_MUTABLE_P (decl))
+ quals &= ~TYPE_QUAL_CONST;
+
+ quals |= cp_type_quals (TREE_TYPE (decl));
+ type = cp_build_qualified_type (type, quals);
+ }
+
+ return build_min (COMPONENT_REF, type, object, decl);
+ }
+ else
+ {
+ tree access_type = TREE_TYPE (object);
+ tree lookup_context = context_for_name_lookup (decl);
+
+ while (!DERIVED_FROM_P (lookup_context, access_type))
+ {
+ access_type = TYPE_CONTEXT (access_type);
+ while (access_type && DECL_P (access_type))
+ access_type = DECL_CONTEXT (access_type);
+
+ if (!access_type)
+ {
+ cp_error_at ("object missing in reference to `%D'", decl);
+ error ("from this location");
+ return error_mark_node;
+ }
+ }
+
+ /* If PROCESSING_TEMPLATE_DECL is nonzero here, then
+ QUALIFYING_SCOPE is also non-null. Wrap this in a SCOPE_REF
+ for now. */
+ if (processing_template_decl)
+ return build_min (SCOPE_REF, TREE_TYPE (decl),
+ qualifying_scope, DECL_NAME (decl));
+
+ perform_or_defer_access_check (TYPE_BINFO (access_type), decl);
+
+ /* If the data member was named `C::M', convert `*this' to `C'
+ first. */
+ if (qualifying_scope)
+ {
+ tree binfo = NULL_TREE;
+ object = build_scoped_ref (object, qualifying_scope,
+ &binfo);
+ }
+
+ return build_class_member_access_expr (object, decl,
+ /*access_path=*/NULL_TREE,
+ /*preserve_reference=*/false);
+ }
+}
+
+/* DECL was the declaration to which a qualified-id resolved. Issue
+ an error message if it is not accessible. If OBJECT_TYPE is
+ non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the
+ type of `*x', or `x', respectively. If the DECL was named as
+ `A::B' then NESTED_NAME_SPECIFIER is `A'. */
+
+void
+check_accessibility_of_qualified_id (tree decl,
+ tree object_type,
+ tree nested_name_specifier)
+{
+ tree scope;
+ tree qualifying_type = NULL_TREE;
+
+ /* Determine the SCOPE of DECL. */
+ scope = context_for_name_lookup (decl);
+ /* If the SCOPE is not a type, then DECL is not a member. */
+ if (!TYPE_P (scope))
+ return;
+ /* Compute the scope through which DECL is being accessed. */
+ if (object_type
+ /* OBJECT_TYPE might not be a class type; consider:
+
+ class A { typedef int I; };
+ I *p;
+ p->A::I::~I();
+
+ In this case, we will have "A::I" as the DECL, but "I" as the
+ OBJECT_TYPE. */
+ && CLASS_TYPE_P (object_type)
+ && DERIVED_FROM_P (scope, object_type))
+ /* If we are processing a `->' or `.' expression, use the type of the
+ left-hand side. */
+ qualifying_type = object_type;
+ else if (nested_name_specifier)
+ {
+ /* If the reference is to a non-static member of the
+ current class, treat it as if it were referenced through
+ `this'. */
+ if (DECL_NONSTATIC_MEMBER_P (decl)
+ && current_class_ptr
+ && DERIVED_FROM_P (scope, current_class_type))
+ qualifying_type = current_class_type;
+ /* Otherwise, use the type indicated by the
+ nested-name-specifier. */
+ else
+ qualifying_type = nested_name_specifier;
+ }
+ else
+ /* Otherwise, the name must be from the current class or one of
+ its bases. */
+ qualifying_type = currently_open_derived_class (scope);
+
+ if (qualifying_type)
+ perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl);
+}
+
+/* EXPR is the result of a qualified-id. The QUALIFYING_CLASS was the
+ class named to the left of the "::" operator. DONE is true if this
+ expression is a complete postfix-expression; it is false if this
+ expression is followed by '->', '[', '(', etc. ADDRESS_P is true
+ iff this expression is the operand of '&'. */
+
+tree
+finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
+ bool address_p)
+{
+ if (error_operand_p (expr))
+ return error_mark_node;
+
+ /* If EXPR occurs as the operand of '&', use special handling that
+ permits a pointer-to-member. */
+ if (address_p && done)
+ {
+ if (TREE_CODE (expr) == SCOPE_REF)
+ expr = TREE_OPERAND (expr, 1);
+ expr = build_offset_ref (qualifying_class, expr,
+ /*address_p=*/true);
+ return expr;
+ }
+
+ if (TREE_CODE (expr) == FIELD_DECL)
+ expr = finish_non_static_data_member (expr, current_class_ref,
+ qualifying_class);
+ else if (BASELINK_P (expr) && !processing_template_decl)
+ {
+ tree fn;
+ tree fns;
+
+ /* See if any of the functions are non-static members. */
+ fns = BASELINK_FUNCTIONS (expr);
+ if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
+ fns = TREE_OPERAND (fns, 0);
+ for (fn = fns; fn; fn = OVL_NEXT (fn))
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
+ break;
+ /* If so, the expression may be relative to the current
+ class. */
+ if (fn && current_class_type
+ && DERIVED_FROM_P (qualifying_class, current_class_type))
+ expr = (build_class_member_access_expr
+ (maybe_dummy_object (qualifying_class, NULL),
+ expr,
+ BASELINK_ACCESS_BINFO (expr),
+ /*preserve_reference=*/false));
+ else if (done)
+ /* The expression is a qualified name whose address is not
+ being taken. */
+ expr = build_offset_ref (qualifying_class, expr, /*address_p=*/false);
+ }
+
+ return expr;
+}
+
/* Begin a statement-expression. The value returned must be passed to
finish_stmt_expr. */
tree
-begin_stmt_expr ()
+begin_stmt_expr (void)
{
/* If we're outside a function, we won't have a statement-tree to
work with. But, if we see a statement-expression we need to
@@ -1154,61 +1428,102 @@ begin_stmt_expr ()
if (! cfun && !last_tree)
begin_stmt_tree (&scope_chain->x_saved_tree);
- 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. */
+ last_expr_type = NULL_TREE;
+
+ keep_next_level (true);
+
return last_tree;
}
-/* Used when beginning a statement-expression outside function scope.
- For example, when handling a file-scope initializer, we use this
- function. */
+/* Process the final expression of a statement expression. EXPR can be
+ NULL, if the final expression is empty. Build up a TARGET_EXPR so
+ that the result value can be safely returned to the enclosing
+ expression. */
tree
-begin_global_stmt_expr ()
+finish_stmt_expr_expr (tree expr)
{
- if (! cfun && !last_tree)
- begin_stmt_tree (&scope_chain->x_saved_tree);
-
- keep_next_level (1);
-
- return last_tree ? last_tree : expand_start_stmt_expr(/*has_scope=*/1);
-}
+ tree result = NULL_TREE;
+ tree type = void_type_node;
-/* Finish the STMT_EXPR last begun with begin_global_stmt_expr. */
+ if (expr)
+ {
+ type = TREE_TYPE (expr);
+
+ if (!processing_template_decl && !VOID_TYPE_P (TREE_TYPE (expr)))
+ {
+ if (TREE_CODE (type) == ARRAY_TYPE
+ || TREE_CODE (type) == FUNCTION_TYPE)
+ expr = decay_conversion (expr);
+
+ expr = convert_from_reference (expr);
+ expr = require_complete_type (expr);
+
+ /* Build a TARGET_EXPR for this aggregate. finish_stmt_expr
+ will then pull it apart so the lifetime of the target is
+ within the scope of the expression containing this statement
+ expression. */
+ if (TREE_CODE (expr) == TARGET_EXPR)
+ ;
+ else if (!IS_AGGR_TYPE (type) || TYPE_HAS_TRIVIAL_INIT_REF (type))
+ expr = build_target_expr_with_type (expr, type);
+ else
+ {
+ /* Copy construct. */
+ expr = build_special_member_call
+ (NULL_TREE, complete_ctor_identifier,
+ build_tree_list (NULL_TREE, expr),
+ TYPE_BINFO (type), LOOKUP_NORMAL);
+ expr = build_cplus_new (type, expr);
+ my_friendly_assert (TREE_CODE (expr) == TARGET_EXPR, 20030729);
+ }
+ }
-tree
-finish_global_stmt_expr (stmt_expr)
- tree stmt_expr;
-{
- stmt_expr = expand_end_stmt_expr (stmt_expr);
+ if (expr != error_mark_node)
+ {
+ result = build_stmt (EXPR_STMT, expr);
+ add_stmt (result);
+ }
+ }
- if (! cfun
- && TREE_CHAIN (scope_chain->x_saved_tree) == NULL_TREE)
- finish_stmt_tree (&scope_chain->x_saved_tree);
+ finish_stmt ();
- return stmt_expr;
+ /* Remember the last expression so that finish_stmt_expr can pull it
+ apart. */
+ last_expr_type = result ? result : void_type_node;
+
+ return result;
}
-/* 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. */
+/* Finish a statement-expression. EXPR should be the value returned
+ by the previous begin_stmt_expr. Returns an expression
+ representing the statement-expression. */
tree
-finish_stmt_expr (rtl_expr)
- tree rtl_expr;
+finish_stmt_expr (tree rtl_expr, bool has_no_scope)
{
tree result;
-
- /* If the last thing in the statement-expression was not an
- expression-statement, then it has type `void'. */
+ tree result_stmt = last_expr_type;
+ tree type;
+
if (!last_expr_type)
- last_expr_type = void_type_node;
- result = build_min (STMT_EXPR, last_expr_type, last_tree);
+ type = void_type_node;
+ else
+ {
+ if (result_stmt == void_type_node)
+ {
+ type = void_type_node;
+ result_stmt = NULL_TREE;
+ }
+ else
+ type = TREE_TYPE (EXPR_STMT_EXPR (result_stmt));
+ }
+
+ result = build_min (STMT_EXPR, type, last_tree);
TREE_SIDE_EFFECTS (result) = 1;
+ STMT_EXPR_NO_SCOPE (result) = has_no_scope;
+
+ last_expr_type = NULL_TREE;
/* Remove the compound statement from the tree structure; it is
now saved in the STMT_EXPR. */
@@ -1221,9 +1536,67 @@ finish_stmt_expr (rtl_expr)
&& TREE_CHAIN (scope_chain->x_saved_tree) == NULL_TREE)
finish_stmt_tree (&scope_chain->x_saved_tree);
+ if (processing_template_decl)
+ return result;
+
+ if (!VOID_TYPE_P (type))
+ {
+ /* Pull out the TARGET_EXPR that is the final expression. Put
+ the target's init_expr as the final expression and then put
+ the statement expression itself as the target's init
+ expr. Finally, return the target expression. */
+ tree last_expr = EXPR_STMT_EXPR (result_stmt);
+
+ my_friendly_assert (TREE_CODE (last_expr) == TARGET_EXPR, 20030729);
+ EXPR_STMT_EXPR (result_stmt) = TREE_OPERAND (last_expr, 1);
+ TREE_OPERAND (last_expr, 1) = result;
+ result = last_expr;
+ }
return result;
}
+/* Perform Koenig lookup. FN is the postfix-expression representing
+ the function (or functions) to call; ARGS are the arguments to the
+ call. Returns the functions to be considered by overload
+ resolution. */
+
+tree
+perform_koenig_lookup (tree fn, tree args)
+{
+ tree identifier = NULL_TREE;
+ tree functions = NULL_TREE;
+
+ /* Find the name of the overloaded function. */
+ if (TREE_CODE (fn) == IDENTIFIER_NODE)
+ identifier = fn;
+ else if (is_overloaded_fn (fn))
+ {
+ functions = fn;
+ identifier = DECL_NAME (get_first_fn (functions));
+ }
+ else if (DECL_P (fn))
+ {
+ functions = fn;
+ identifier = DECL_NAME (fn);
+ }
+
+ /* A call to a namespace-scope function using an unqualified name.
+
+ Do Koenig lookup -- unless any of the arguments are
+ type-dependent. */
+ if (!any_type_dependent_arguments_p (args))
+ {
+ fn = lookup_arg_dependent (identifier, functions, args);
+ if (!fn)
+ /* The unqualified name could not be resolved. */
+ fn = unqualified_fn_lookup_error (identifier);
+ }
+ else
+ fn = identifier;
+
+ return fn;
+}
+
/* Generate an expression for `FN (ARGS)'.
If DISALLOW_VIRTUAL is true, the call to FN will be not generated
@@ -1235,18 +1608,60 @@ finish_stmt_expr (rtl_expr)
Returns code for the call. */
tree
-finish_call_expr (tree fn, tree args, bool disallow_virtual)
+finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
{
+ tree result;
+ tree orig_fn;
+ tree orig_args;
+
if (fn == error_mark_node || args == error_mark_node)
return error_mark_node;
- if (processing_template_decl)
- return build_nt (CALL_EXPR, fn, args, NULL_TREE);
-
/* ARGS should be a list of arguments. */
my_friendly_assert (!args || TREE_CODE (args) == TREE_LIST,
20020712);
+ orig_fn = fn;
+ orig_args = args;
+
+ if (processing_template_decl)
+ {
+ if (type_dependent_expression_p (fn)
+ || any_type_dependent_arguments_p (args))
+ {
+ result = build_nt (CALL_EXPR, fn, args);
+ KOENIG_LOOKUP_P (result) = koenig_p;
+ return result;
+ }
+ if (!BASELINK_P (fn)
+ && TREE_CODE (fn) != PSEUDO_DTOR_EXPR
+ && TREE_TYPE (fn) != unknown_type_node)
+ fn = build_non_dependent_expr (fn);
+ args = build_non_dependent_args (orig_args);
+ }
+
+ /* A reference to a member function will appear as an overloaded
+ function (rather than a BASELINK) if an unqualified name was used
+ to refer to it. */
+ if (!BASELINK_P (fn) && is_overloaded_fn (fn))
+ {
+ tree f = fn;
+
+ if (TREE_CODE (f) == TEMPLATE_ID_EXPR)
+ f = TREE_OPERAND (f, 0);
+ f = get_first_fn (f);
+ if (DECL_FUNCTION_MEMBER_P (f))
+ {
+ tree type = currently_open_derived_class (DECL_CONTEXT (f));
+ if (!type)
+ type = DECL_CONTEXT (f);
+ fn = build_baselink (TYPE_BINFO (type),
+ TYPE_BINFO (type),
+ fn, /*optype=*/NULL_TREE);
+ }
+ }
+
+ result = NULL_TREE;
if (BASELINK_P (fn))
{
tree object;
@@ -1286,25 +1701,46 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual)
object = build_dummy_object (DECL_CONTEXT (representative_fn));
}
- return build_new_method_call (object, fn, args, NULL_TREE,
- (disallow_virtual
- ? LOOKUP_NONVIRTUAL : 0));
+ if (processing_template_decl)
+ {
+ if (type_dependent_expression_p (object))
+ return build_nt (CALL_EXPR, orig_fn, orig_args);
+ object = build_non_dependent_expr (object);
+ }
+
+ result = build_new_method_call (object, fn, args, NULL_TREE,
+ (disallow_virtual
+ ? LOOKUP_NONVIRTUAL : 0));
}
else if (is_overloaded_fn (fn))
/* A call to a namespace-scope function. */
- return build_new_function_call (fn, args);
- else if (CLASS_TYPE_P (TREE_TYPE (fn)))
+ result = build_new_function_call (fn, args);
+ else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
{
- /* If the "function" is really an object of class type, it might
- have an overloaded `operator ()'. */
- tree result;
- result = build_opfncall (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE);
- if (result)
- return result;
+ if (args)
+ error ("arguments to destructor are not allowed");
+ /* Mark the pseudo-destructor call as having side-effects so
+ that we do not issue warnings about its use. */
+ result = build1 (NOP_EXPR,
+ void_type_node,
+ TREE_OPERAND (fn, 0));
+ TREE_SIDE_EFFECTS (result) = 1;
}
+ else if (CLASS_TYPE_P (TREE_TYPE (fn)))
+ /* If the "function" is really an object of class type, it might
+ have an overloaded `operator ()'. */
+ result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE,
+ /*overloaded_p=*/NULL);
+ if (!result)
+ /* A call where the function is unknown. */
+ result = build_function_call (fn, args);
- /* A call where the function is unknown. */
- return build_function_call (fn, args);
+ if (processing_template_decl)
+ {
+ result = build (CALL_EXPR, TREE_TYPE (result), orig_fn, orig_args);
+ KOENIG_LOOKUP_P (result) = koenig_p;
+ }
+ return result;
}
/* Finish a call to a postfix increment or decrement or EXPR. (Which
@@ -1312,24 +1748,15 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual)
POSTDECREMENT_EXPR.) */
tree
-finish_increment_expr (expr, code)
- tree expr;
- enum tree_code code;
+finish_increment_expr (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 ()
+finish_this_expr (void)
{
tree result;
@@ -1355,84 +1782,55 @@ finish_this_expr ()
return result;
}
-/* Finish a member function call using OBJECT and ARGS as arguments to
- FN. Returns an expression for the call. */
+/* Finish a pseudo-destructor expression. If SCOPE is NULL, the
+ expression was of the form `OBJECT.~DESTRUCTOR' where DESTRUCTOR is
+ the TYPE for the type given. If SCOPE is non-NULL, the expression
+ was of the form `OBJECT.SCOPE::~DESTRUCTOR'. */
tree
-finish_object_call_expr (fn, object, args)
- tree fn;
- tree object;
- tree args;
+finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
{
- if (DECL_DECLARES_TYPE_P (fn))
- {
- if (processing_template_decl)
- /* This can happen on code like:
+ if (destructor == error_mark_node)
+ return error_mark_node;
- class X;
- template <class T> void f(T t) {
- t.X();
- }
+ my_friendly_assert (TYPE_P (destructor), 20010905);
- We just grab the underlying IDENTIFIER. */
- fn = DECL_NAME (fn);
- else
+ if (!processing_template_decl)
+ {
+ if (scope == error_mark_node)
{
- error ("calling type `%T' like a method", fn);
+ error ("invalid qualifying scope in pseudo-destructor name");
return error_mark_node;
}
- }
-
- if (processing_template_decl || name_p (fn))
- return build_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
- else
- return build_new_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
-}
-
-/* Finish a qualified member function call using OBJECT and ARGS as
- arguments to FN. Returns an expression for the call. */
-
-tree
-finish_qualified_object_call_expr (fn, object, args)
- tree fn;
- tree object;
- tree args;
-{
- return build_scoped_method_call (object, TREE_OPERAND (fn, 0),
- TREE_OPERAND (fn, 1), args);
-}
+
+ /* [expr.pseudo] says both:
-/* Finish a pseudo-destructor call expression of OBJECT, with SCOPE
- being the scope, if any, of DESTRUCTOR. Returns an expression for
- the call. */
+ The type designated by the pseudo-destructor-name shall be
+ the same as the object type.
-tree
-finish_pseudo_destructor_call_expr (object, scope, destructor)
- tree object;
- tree scope;
- tree destructor;
-{
- if (processing_template_decl)
- return build_min_nt (PSEUDO_DTOR_EXPR, object, scope, destructor);
+ and:
- if (scope && scope != destructor)
- error ("destructor specifier `%T::~%T()' must have matching names",
- scope, destructor);
+ The cv-unqualified versions of the object type and of the
+ type designated by the pseudo-destructor-name shall be the
+ same type.
- if ((scope == NULL_TREE || IDENTIFIER_GLOBAL_VALUE (destructor))
- && (TREE_CODE (TREE_TYPE (object)) !=
- TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (destructor)))))
- error ("`%E' is not of type `%T'", object, destructor);
+ We implement the more generous second sentence, since that is
+ what most other compilers do. */
+ if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (object),
+ destructor))
+ {
+ error ("`%E' is not of type `%T'", object, destructor);
+ return error_mark_node;
+ }
+ }
- return cp_convert (void_type_node, object);
+ return build (PSEUDO_DTOR_EXPR, void_type_node, object, scope, destructor);
}
/* Finish an expression of the form CODE EXPR. */
tree
-finish_unary_op_expr (code, expr)
- enum tree_code code;
- tree expr;
+finish_unary_op_expr (enum tree_code code, tree expr)
{
tree result = build_x_unary_op (code, expr);
/* Inside a template, build_x_unary_op does not fold the
@@ -1447,18 +1845,35 @@ finish_unary_op_expr (code, expr)
return result;
}
-/* Finish an id-expression. */
+/* Finish a compound-literal expression. TYPE is the type to which
+ the INITIALIZER_LIST is being cast. */
tree
-finish_id_expr (expr)
- tree expr;
+finish_compound_literal (tree type, tree initializer_list)
{
- if (TREE_CODE (expr) == IDENTIFIER_NODE)
- expr = do_identifier (expr, 1, NULL_TREE);
+ tree compound_literal;
- if (TREE_TYPE (expr) == error_mark_node)
- expr = error_mark_node;
- return expr;
+ /* Build a CONSTRUCTOR for the INITIALIZER_LIST. */
+ compound_literal = build_constructor (NULL_TREE, initializer_list);
+ /* Mark it as a compound-literal. */
+ TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
+ if (processing_template_decl)
+ TREE_TYPE (compound_literal) = type;
+ else
+ {
+ /* Check the initialization. */
+ compound_literal = digest_init (type, compound_literal, NULL);
+ /* If the TYPE was an array type with an unknown bound, then we can
+ figure out the dimension now. For example, something like:
+
+ `(int []) { 2, 3 }'
+
+ implies that the array has two elements. */
+ if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
+ complete_array_type (type, compound_literal, 1);
+ }
+
+ return compound_literal;
}
/* Return the declaration for the function-name variable indicated by
@@ -1471,83 +1886,20 @@ finish_fname (tree id)
decl = fname_decl (C_RID_CODE (id), id);
if (processing_template_decl)
- decl = build_min_nt (LOOKUP_EXPR, DECL_NAME (decl));
+ decl = DECL_NAME (decl);
return decl;
}
-static tree current_type_lookups;
-
-/* Perform deferred access control for types used in the type of a
- declaration. */
-
-static void
-deferred_type_access_control ()
-{
- tree lookup = type_lookups;
-
- if (lookup == error_mark_node)
- return;
-
- for (; lookup; lookup = TREE_CHAIN (lookup))
- enforce_access (TREE_PURPOSE (lookup), TREE_VALUE (lookup));
-}
-
-void
-decl_type_access_control (decl)
- tree decl;
-{
- tree save_fn;
-
- if (type_lookups == error_mark_node)
- return;
-
- save_fn = current_function_decl;
-
- if (decl && TREE_CODE (decl) == FUNCTION_DECL)
- current_function_decl = decl;
-
- deferred_type_access_control ();
-
- current_function_decl = save_fn;
-
- /* Now strip away the checks for the current declarator; they were
- added to type_lookups after typed_declspecs saved the copy that
- ended up in current_type_lookups. */
- type_lookups = current_type_lookups;
-}
-
-void
-save_type_access_control (lookups)
- tree lookups;
-{
- current_type_lookups = lookups;
-}
-
-/* Reset the deferred access control. */
-
-void
-reset_type_access_control ()
-{
- type_lookups = NULL_TREE;
- current_type_lookups = NULL_TREE;
-}
-
/* Begin a function definition declared with DECL_SPECS, ATTRIBUTES,
and DECLARATOR. Returns nonzero if the function-declaration is
valid. */
int
-begin_function_definition (decl_specs, attributes, declarator)
- tree decl_specs;
- tree attributes;
- tree declarator;
+begin_function_definition (tree decl_specs, tree attributes, tree declarator)
{
if (!start_function (decl_specs, declarator, attributes, SF_DEFAULT))
return 0;
- deferred_type_access_control ();
- type_lookups = error_mark_node;
-
/* The things we're about to see are not directly qualified by any
template headers we've seen thus far. */
reset_specialization ();
@@ -1555,38 +1907,10 @@ begin_function_definition (decl_specs, attributes, declarator)
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_nt (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 ()
+finish_translation_unit (void)
{
/* In case there were missing closebraces,
get us back to the global binding level. */
@@ -1596,17 +1920,13 @@ finish_translation_unit ()
/* Do file scope __FUNCTION__ et al. */
finish_fname_decls ();
-
- 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;
+finish_template_type_parm (tree aggr, tree identifier)
{
if (aggr != class_type_node)
{
@@ -1621,9 +1941,7 @@ finish_template_type_parm (aggr, identifier)
Returns the parameter. */
tree
-finish_template_template_parm (aggr, identifier)
- tree aggr;
- tree identifier;
+finish_template_template_parm (tree aggr, tree identifier)
{
tree decl = build_decl (TYPE_DECL, identifier, NULL_TREE);
tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE);
@@ -1646,10 +1964,24 @@ check_template_template_default_arg (tree argument)
{
if (TREE_CODE (argument) != TEMPLATE_DECL
&& TREE_CODE (argument) != TEMPLATE_TEMPLATE_PARM
- && TREE_CODE (argument) != TYPE_DECL
&& TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
{
- error ("invalid default template argument");
+ if (TREE_CODE (argument) == TYPE_DECL)
+ {
+ tree t = TREE_TYPE (argument);
+
+ /* Try to emit a slightly smarter error message if we detect
+ that the user is using a template instantiation. */
+ if (CLASSTYPE_TEMPLATE_INFO (t)
+ && CLASSTYPE_TEMPLATE_INSTANTIATION (t))
+ error ("invalid use of type `%T' as a default value for a "
+ "template template-parameter", t);
+ else
+ error ("invalid use of `%D' as a default value for a template "
+ "template-parameter", argument);
+ }
+ else
+ error ("invalid default argument for a template template parameter");
return error_mark_node;
}
@@ -1660,9 +1992,7 @@ check_template_template_default_arg (tree argument)
nonzero, the parameter list was terminated by a `...'. */
tree
-finish_parmlist (parms, ellipsis)
- tree parms;
- int ellipsis;
+finish_parmlist (tree parms, int ellipsis)
{
if (parms)
{
@@ -1679,26 +2009,16 @@ finish_parmlist (parms, ellipsis)
/* Begin a class definition, as indicated by T. */
tree
-begin_class_definition (t)
- tree t;
+begin_class_definition (tree t)
{
if (t == error_mark_node)
return error_mark_node;
- /* Check the bases are accessible. */
- decl_type_access_control (TYPE_NAME (t));
- reset_type_access_control ();
-
if (processing_template_parmlist)
{
error ("definition of `%#T' inside template parameter list", t);
return error_mark_node;
}
-
- /* In a definition of a member class template, we will get here with
- an implicit typename. */
- if (IMPLICIT_TYPENAME_P (t))
- t = TREE_TYPE (t);
/* A non-implicit typename comes from code like:
template <typename T> struct A {
@@ -1717,61 +2037,17 @@ begin_class_definition (t)
pushtag (make_anon_name (), t, 0);
}
- /* 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_DECL_LIST (t) = NULL_TREE;
- CLASSTYPE_NESTED_UDTS (t) = NULL;
- CLASSTYPE_VBASECLASSES (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 (COMPLETE_TYPE_P (t))
- duplicate_tag_error (t);
+ if (COMPLETE_TYPE_P (t))
+ {
+ error ("redefinition of `%#T'", t);
+ cp_error_at ("previous definition of `%#T'", t);
+ return error_mark_node;
+ }
/* Update the location of the decl. */
- DECL_SOURCE_FILE (TYPE_NAME (t)) = input_filename;
- DECL_SOURCE_LINE (TYPE_NAME (t)) = lineno;
+ DECL_SOURCE_LOCATION (TYPE_NAME (t)) = input_location;
if (TYPE_BEING_DEFINED (t))
{
@@ -1779,9 +2055,18 @@ begin_class_definition (t)
pushtag (TYPE_IDENTIFIER (t), t, 0);
}
maybe_process_partial_specialization (t);
- pushclass (t, 1);
+ pushclass (t);
TYPE_BEING_DEFINED (t) = 1;
- TYPE_PACKED (t) = flag_pack_struct;
+ if (flag_pack_struct)
+ {
+ tree v;
+ TYPE_PACKED (t) = 1;
+ /* Even though the type is being defined for the first time
+ here, there might have been a forward declaration, so there
+ might be cv-qualified variants of T. */
+ for (v = TYPE_NEXT_VARIANT (t); v; v = TYPE_NEXT_VARIANT (v))
+ TYPE_PACKED (v) = 1;
+ }
/* Reset the interface data, at the earliest possible
moment, as it might have been set via a class foo;
before. */
@@ -1802,8 +2087,7 @@ begin_class_definition (t)
/* Finish the member declaration given by DECL. */
void
-finish_member_declaration (decl)
- tree decl;
+finish_member_declaration (tree decl)
{
if (decl == error_mark_node || decl == NULL_TREE)
return;
@@ -1854,7 +2138,8 @@ finish_member_declaration (decl)
/*friend_p=*/0);
}
/* Enter the DECL into the scope of the class. */
- else if (TREE_CODE (decl) == USING_DECL || pushdecl_class_level (decl))
+ else if ((TREE_CODE (decl) == USING_DECL && TREE_TYPE (decl))
+ || pushdecl_class_level (decl))
{
/* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields
go at the beginning. The reason is that lookup_field_1
@@ -1887,65 +2172,11 @@ finish_member_declaration (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, pop_scope_p)
- tree t;
- tree attributes;
- int semi;
- int pop_scope_p;
-{
- if (t == error_mark_node)
- return error_mark_node;
-
- /* 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 (TYPE_ATTRIBUTES (t), attributes);
- TYPE_ATTRIBUTES (t) = NULL_TREE;
-
- if (TREE_CODE (t) == ENUMERAL_TYPE)
- ;
- else
- {
- 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 ();
-
- return t;
-}
-
-/* Finish processing the default argument expressions cached during
- the processing of a class definition. */
-
-void
-begin_inline_definitions ()
-{
- if (current_scope () == current_function_decl)
- do_pending_inlines ();
-}
-
/* 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;
+finish_member_class_template (tree types)
{
tree t;
@@ -1956,7 +2187,6 @@ finish_member_class_template (types)
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
@@ -1976,8 +2206,7 @@ finish_member_class_template (types)
the template parameters. */
void
-finish_template_decl (parms)
- tree parms;
+finish_template_decl (tree parms)
{
if (parms)
end_template_decl ();
@@ -1991,50 +2220,19 @@ finish_template_decl (parms)
the scope of template-id indicated. */
tree
-finish_template_type (name, args, entering_scope)
- tree name;
- tree args;
- int entering_scope;
+finish_template_type (tree name, tree args, int entering_scope)
{
tree decl;
decl = lookup_template_class (name, args,
- NULL_TREE, NULL_TREE,
- entering_scope, /*complain=*/1);
+ NULL_TREE, NULL_TREE, entering_scope,
+ tf_error | tf_warning | tf_user);
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
@@ -2042,37 +2240,36 @@ enter_scope_of (sr)
access_{default,public,protected_private}[_virtual]_node.*/
tree
-finish_base_specifier (access_specifier, base_class)
- tree access_specifier;
- tree base_class;
+finish_base_specifier (tree base, tree access, bool virtual_p)
{
tree result;
- if (base_class == error_mark_node)
+ if (base == error_mark_node)
{
error ("invalid base-class specification");
result = NULL_TREE;
}
- else if (! is_aggr_type (base_class, 1))
+ else if (! is_aggr_type (base, 1))
result = NULL_TREE;
else
{
- if (cp_type_quals (base_class) != 0)
+ if (cp_type_quals (base) != 0)
{
- error ("base class `%T' has cv qualifiers", base_class);
- base_class = TYPE_MAIN_VARIANT (base_class);
+ error ("base class `%T' has cv qualifiers", base);
+ base = TYPE_MAIN_VARIANT (base);
}
- result = build_tree_list (access_specifier, base_class);
+ result = build_tree_list (access, base);
+ TREE_VIA_VIRTUAL (result) = virtual_p;
}
return result;
}
/* Called when multiple declarators are processed. If that is not
- premitted in this context, an error is issued. */
+ permitted in this context, an error is issued. */
void
-check_multiple_declarators ()
+check_multiple_declarators (void)
{
/* [temp]
@@ -2093,16 +2290,420 @@ check_multiple_declarators ()
error ("multiple declarators in template declaration");
}
+/* Issue a diagnostic that NAME cannot be found in SCOPE. */
+
+void
+qualified_name_lookup_error (tree scope, tree name)
+{
+ if (TYPE_P (scope))
+ {
+ if (!COMPLETE_TYPE_P (scope))
+ error ("incomplete type `%T' used in nested name specifier", scope);
+ else
+ error ("`%D' is not a member of `%T'", name, scope);
+ }
+ else if (scope != global_namespace)
+ error ("`%D' is not a member of `%D'", name, scope);
+ else
+ error ("`::%D' has not been declared", name);
+}
+
+/* ID_EXPRESSION is a representation of parsed, but unprocessed,
+ id-expression. (See cp_parser_id_expression for details.) SCOPE,
+ if non-NULL, is the type or namespace used to explicitly qualify
+ ID_EXPRESSION. DECL is the entity to which that name has been
+ resolved.
+
+ *CONSTANT_EXPRESSION_P is true if we are presently parsing a
+ constant-expression. In that case, *NON_CONSTANT_EXPRESSION_P will
+ be set to true if this expression isn't permitted in a
+ constant-expression, but it is otherwise not set by this function.
+ *ALLOW_NON_CONSTANT_EXPRESSION_P is true if we are parsing a
+ constant-expression, but a non-constant expression is also
+ permissible.
+
+ If an error occurs, and it is the kind of error that might cause
+ the parser to abort a tentative parse, *ERROR_MSG is filled in. It
+ is the caller's responsibility to issue the message. *ERROR_MSG
+ will be a string with static storage duration, so the caller need
+ not "free" it.
+
+ Return an expression for the entity, after issuing appropriate
+ diagnostics. This function is also responsible for transforming a
+ reference to a non-static member into a COMPONENT_REF that makes
+ the use of "this" explicit.
+
+ Upon return, *IDK will be filled in appropriately. */
+
+tree
+finish_id_expression (tree id_expression,
+ tree decl,
+ tree scope,
+ cp_id_kind *idk,
+ tree *qualifying_class,
+ bool integral_constant_expression_p,
+ bool allow_non_integral_constant_expression_p,
+ bool *non_integral_constant_expression_p,
+ const char **error_msg)
+{
+ /* Initialize the output parameters. */
+ *idk = CP_ID_KIND_NONE;
+ *error_msg = NULL;
+
+ if (id_expression == error_mark_node)
+ return error_mark_node;
+ /* If we have a template-id, then no further lookup is
+ required. If the template-id was for a template-class, we
+ will sometimes have a TYPE_DECL at this point. */
+ else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
+ || TREE_CODE (decl) == TYPE_DECL)
+ ;
+ /* Look up the name. */
+ else
+ {
+ if (decl == error_mark_node)
+ {
+ /* Name lookup failed. */
+ if (scope
+ && (!TYPE_P (scope)
+ || (!dependent_type_p (scope)
+ && !(TREE_CODE (id_expression) == IDENTIFIER_NODE
+ && IDENTIFIER_TYPENAME_P (id_expression)
+ && dependent_type_p (TREE_TYPE (id_expression))))))
+ {
+ /* If the qualifying type is non-dependent (and the name
+ does not name a conversion operator to a dependent
+ type), issue an error. */
+ qualified_name_lookup_error (scope, id_expression);
+ return error_mark_node;
+ }
+ else if (!scope)
+ {
+ /* It may be resolved via Koenig lookup. */
+ *idk = CP_ID_KIND_UNQUALIFIED;
+ return id_expression;
+ }
+ else
+ decl = id_expression;
+ }
+ /* If DECL is a variable that would be out of scope under
+ ANSI/ISO rules, but in scope in the ARM, name lookup
+ will succeed. Issue a diagnostic here. */
+ else
+ decl = check_for_out_of_scope_variable (decl);
+
+ /* Remember that the name was used in the definition of
+ the current class so that we can check later to see if
+ the meaning would have been different after the class
+ was entirely defined. */
+ if (!scope && decl != error_mark_node)
+ maybe_note_name_used_in_class (id_expression, decl);
+ }
+
+ /* If we didn't find anything, or what we found was a type,
+ then this wasn't really an id-expression. */
+ if (TREE_CODE (decl) == TEMPLATE_DECL
+ && !DECL_FUNCTION_TEMPLATE_P (decl))
+ {
+ *error_msg = "missing template arguments";
+ return error_mark_node;
+ }
+ else if (TREE_CODE (decl) == TYPE_DECL
+ || TREE_CODE (decl) == NAMESPACE_DECL)
+ {
+ *error_msg = "expected primary-expression";
+ return error_mark_node;
+ }
+
+ /* If the name resolved to a template parameter, there is no
+ need to look it up again later. */
+ if ((TREE_CODE (decl) == CONST_DECL && DECL_TEMPLATE_PARM_P (decl))
+ || TREE_CODE (decl) == TEMPLATE_PARM_INDEX)
+ {
+ *idk = CP_ID_KIND_NONE;
+ if (TREE_CODE (decl) == TEMPLATE_PARM_INDEX)
+ decl = TEMPLATE_PARM_DECL (decl);
+ if (integral_constant_expression_p
+ && !dependent_type_p (TREE_TYPE (decl))
+ && !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl)))
+ {
+ if (!allow_non_integral_constant_expression_p)
+ error ("template parameter `%D' of type `%T' is not allowed in "
+ "an integral constant expression because it is not of "
+ "integral or enumeration type", decl, TREE_TYPE (decl));
+ *non_integral_constant_expression_p = true;
+ }
+ return DECL_INITIAL (decl);
+ }
+ /* Similarly, we resolve enumeration constants to their
+ underlying values. */
+ else if (TREE_CODE (decl) == CONST_DECL)
+ {
+ *idk = CP_ID_KIND_NONE;
+ if (!processing_template_decl)
+ return DECL_INITIAL (decl);
+ return decl;
+ }
+ else
+ {
+ bool dependent_p;
+
+ /* If the declaration was explicitly qualified indicate
+ that. The semantics of `A::f(3)' are different than
+ `f(3)' if `f' is virtual. */
+ *idk = (scope
+ ? CP_ID_KIND_QUALIFIED
+ : (TREE_CODE (decl) == TEMPLATE_ID_EXPR
+ ? CP_ID_KIND_TEMPLATE_ID
+ : CP_ID_KIND_UNQUALIFIED));
+
+
+ /* [temp.dep.expr]
+
+ An id-expression is type-dependent if it contains an
+ identifier that was declared with a dependent type.
+
+ The standard is not very specific about an id-expression that
+ names a set of overloaded functions. What if some of them
+ have dependent types and some of them do not? Presumably,
+ such a name should be treated as a dependent name. */
+ /* Assume the name is not dependent. */
+ dependent_p = false;
+ if (!processing_template_decl)
+ /* No names are dependent outside a template. */
+ ;
+ /* A template-id where the name of the template was not resolved
+ is definitely dependent. */
+ else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
+ && (TREE_CODE (TREE_OPERAND (decl, 0))
+ == IDENTIFIER_NODE))
+ dependent_p = true;
+ /* For anything except an overloaded function, just check its
+ type. */
+ else if (!is_overloaded_fn (decl))
+ dependent_p
+ = dependent_type_p (TREE_TYPE (decl));
+ /* For a set of overloaded functions, check each of the
+ functions. */
+ else
+ {
+ tree fns = decl;
+
+ if (BASELINK_P (fns))
+ fns = BASELINK_FUNCTIONS (fns);
+
+ /* For a template-id, check to see if the template
+ arguments are dependent. */
+ if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
+ {
+ tree args = TREE_OPERAND (fns, 1);
+ dependent_p = any_dependent_template_arguments_p (args);
+ /* The functions are those referred to by the
+ template-id. */
+ fns = TREE_OPERAND (fns, 0);
+ }
+
+ /* If there are no dependent template arguments, go through
+ the overloaded functions. */
+ while (fns && !dependent_p)
+ {
+ tree fn = OVL_CURRENT (fns);
+
+ /* Member functions of dependent classes are
+ dependent. */
+ if (TREE_CODE (fn) == FUNCTION_DECL
+ && type_dependent_expression_p (fn))
+ dependent_p = true;
+ else if (TREE_CODE (fn) == TEMPLATE_DECL
+ && dependent_template_p (fn))
+ dependent_p = true;
+
+ fns = OVL_NEXT (fns);
+ }
+ }
+
+ /* If the name was dependent on a template parameter, we will
+ resolve the name at instantiation time. */
+ if (dependent_p)
+ {
+ /* Create a SCOPE_REF for qualified names, if the scope is
+ dependent. */
+ if (scope)
+ {
+ if (TYPE_P (scope))
+ *qualifying_class = scope;
+ /* Since this name was dependent, the expression isn't
+ constant -- yet. No error is issued because it might
+ be constant when things are instantiated. */
+ if (integral_constant_expression_p)
+ *non_integral_constant_expression_p = true;
+ if (TYPE_P (scope) && dependent_type_p (scope))
+ return build_nt (SCOPE_REF, scope, id_expression);
+ else if (TYPE_P (scope) && DECL_P (decl))
+ return build (SCOPE_REF, TREE_TYPE (decl), scope,
+ id_expression);
+ else
+ return decl;
+ }
+ /* A TEMPLATE_ID already contains all the information we
+ need. */
+ if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR)
+ return id_expression;
+ /* Since this name was dependent, the expression isn't
+ constant -- yet. No error is issued because it might be
+ constant when things are instantiated. */
+ if (integral_constant_expression_p)
+ *non_integral_constant_expression_p = true;
+ *idk = CP_ID_KIND_UNQUALIFIED_DEPENDENT;
+ /* If we found a variable, then name lookup during the
+ instantiation will always resolve to the same VAR_DECL
+ (or an instantiation thereof). */
+ if (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == PARM_DECL)
+ return decl;
+ return id_expression;
+ }
+
+ /* Only certain kinds of names are allowed in constant
+ expression. Enumerators and template parameters
+ have already been handled above. */
+ if (integral_constant_expression_p)
+ {
+ /* Const variables or static data members of integral or
+ enumeration types initialized with constant expressions
+ are OK. */
+ if (TREE_CODE (decl) == VAR_DECL
+ && CP_TYPE_CONST_P (TREE_TYPE (decl))
+ && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl))
+ && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
+ ;
+ else
+ {
+ if (!allow_non_integral_constant_expression_p)
+ {
+ error ("`%D' cannot appear in a constant-expression", decl);
+ return error_mark_node;
+ }
+ *non_integral_constant_expression_p = true;
+ }
+ }
+
+ if (TREE_CODE (decl) == NAMESPACE_DECL)
+ {
+ error ("use of namespace `%D' as expression", decl);
+ return error_mark_node;
+ }
+ else if (DECL_CLASS_TEMPLATE_P (decl))
+ {
+ error ("use of class template `%T' as expression", decl);
+ return error_mark_node;
+ }
+ else if (TREE_CODE (decl) == TREE_LIST)
+ {
+ /* Ambiguous reference to base members. */
+ error ("request for member `%D' is ambiguous in "
+ "multiple inheritance lattice", id_expression);
+ print_candidates (decl);
+ return error_mark_node;
+ }
+
+ /* Mark variable-like entities as used. Functions are similarly
+ marked either below or after overload resolution. */
+ if (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == PARM_DECL
+ || TREE_CODE (decl) == RESULT_DECL)
+ mark_used (decl);
+
+ if (scope)
+ {
+ decl = (adjust_result_of_qualified_name_lookup
+ (decl, scope, current_class_type));
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ mark_used (decl);
+
+ if (TREE_CODE (decl) == FIELD_DECL || BASELINK_P (decl))
+ *qualifying_class = scope;
+ else if (!processing_template_decl)
+ decl = convert_from_reference (decl);
+ else if (TYPE_P (scope))
+ decl = build (SCOPE_REF, TREE_TYPE (decl), scope, decl);
+ }
+ else if (TREE_CODE (decl) == FIELD_DECL)
+ decl = finish_non_static_data_member (decl, current_class_ref,
+ /*qualifying_scope=*/NULL_TREE);
+ else if (is_overloaded_fn (decl))
+ {
+ tree first_fn = OVL_CURRENT (decl);
+
+ if (TREE_CODE (first_fn) == TEMPLATE_DECL)
+ first_fn = DECL_TEMPLATE_RESULT (first_fn);
+
+ if (!really_overloaded_fn (decl))
+ mark_used (first_fn);
+
+ if (TREE_CODE (first_fn) == FUNCTION_DECL
+ && DECL_FUNCTION_MEMBER_P (first_fn))
+ {
+ /* A set of member functions. */
+ decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0);
+ return finish_class_member_access_expr (decl, id_expression);
+ }
+ }
+ else
+ {
+ if (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == PARM_DECL
+ || TREE_CODE (decl) == RESULT_DECL)
+ {
+ tree context = decl_function_context (decl);
+
+ if (context != NULL_TREE && context != current_function_decl
+ && ! TREE_STATIC (decl))
+ {
+ error ("use of %s from containing function",
+ (TREE_CODE (decl) == VAR_DECL
+ ? "`auto' variable" : "parameter"));
+ cp_error_at (" `%#D' declared here", decl);
+ return error_mark_node;
+ }
+ }
+
+ if (DECL_P (decl) && DECL_NONLOCAL (decl)
+ && DECL_CLASS_SCOPE_P (decl)
+ && DECL_CONTEXT (decl) != current_class_type)
+ {
+ tree path;
+
+ path = currently_open_derived_class (DECL_CONTEXT (decl));
+ perform_or_defer_access_check (TYPE_BINFO (path), decl);
+ }
+
+ if (! processing_template_decl)
+ decl = convert_from_reference (decl);
+ }
+
+ /* Resolve references to variables of anonymous unions
+ into COMPONENT_REFs. */
+ if (TREE_CODE (decl) == ALIAS_DECL)
+ decl = DECL_INITIAL (decl);
+ }
+
+ if (TREE_DEPRECATED (decl))
+ warn_deprecated_use (decl);
+
+ return decl;
+}
+
/* Implement the __typeof keyword: Return the type of EXPR, suitable for
use as a type-specifier. */
tree
-finish_typeof (expr)
- tree expr;
+finish_typeof (tree expr)
{
tree type;
- if (processing_template_decl)
+ if (type_dependent_expression_p (expr))
{
type = make_aggr_type (TYPEOF_TYPE);
TYPE_FIELDS (type) = expr;
@@ -2110,9 +2711,6 @@ finish_typeof (expr)
return type;
}
- if (TREE_CODE (expr) == OFFSET_REF)
- expr = resolve_offset_ref (expr);
-
type = TREE_TYPE (expr);
if (!type || type == unknown_type_node)
@@ -2124,37 +2722,11 @@ finish_typeof (expr)
return type;
}
-/* Compute the value of the `sizeof' operator. */
-
-tree
-finish_sizeof (t)
- tree t;
-{
- if (processing_template_decl)
- return build_min_nt (SIZEOF_EXPR, t);
-
- return TYPE_P (t) ? cxx_sizeof (t) : expr_sizeof (t);
-}
-
-/* Implement the __alignof keyword: Return the minimum required
- alignment of T, measured in bytes. */
-
-tree
-finish_alignof (t)
- tree t;
-{
- if (processing_template_decl)
- return build_min_nt (ALIGNOF_EXPR, t);
-
- return TYPE_P (t) ? cxx_alignof (t) : c_alignof_expr (t);
-}
-
/* Generate RTL for the statement T, and its substatements, and any
other statements at its nesting level. */
static void
-cp_expand_stmt (t)
- tree t;
+cp_expand_stmt (tree t)
{
switch (TREE_CODE (t))
{
@@ -2170,10 +2742,6 @@ cp_expand_stmt (t)
genrtl_handler (t);
break;
- case RETURN_INIT:
- genrtl_named_return_value ();
- break;
-
case USING_STMT:
break;
@@ -2187,95 +2755,120 @@ cp_expand_stmt (t)
will equivalent CALL_EXPRs. */
static tree
-simplify_aggr_init_exprs_r (tp, walk_subtrees, data)
- tree *tp;
- int *walk_subtrees ATTRIBUTE_UNUSED;
- void *data ATTRIBUTE_UNUSED;
+simplify_aggr_init_exprs_r (tree* tp,
+ int* walk_subtrees,
+ void* data ATTRIBUTE_UNUSED)
{
- tree aggr_init_expr;
- tree call_expr;
- tree fn;
- tree args;
- tree slot;
- tree type;
- int copy_from_buffer_p;
-
- aggr_init_expr = *tp;
/* We don't need to walk into types; there's nothing in a type that
needs simplification. (And, furthermore, there are places we
actively don't want to go. For example, we don't want to wander
into the default arguments for a FUNCTION_DECL that appears in a
CALL_EXPR.) */
- if (TYPE_P (aggr_init_expr))
+ if (TYPE_P (*tp))
{
*walk_subtrees = 0;
return NULL_TREE;
}
/* Only AGGR_INIT_EXPRs are interesting. */
- else if (TREE_CODE (aggr_init_expr) != AGGR_INIT_EXPR)
+ else if (TREE_CODE (*tp) != AGGR_INIT_EXPR)
return NULL_TREE;
+ simplify_aggr_init_expr (tp);
+
+ /* Keep iterating. */
+ return NULL_TREE;
+}
+
+/* Replace the AGGR_INIT_EXPR at *TP with an equivalent CALL_EXPR. This
+ function is broken out from the above for the benefit of the tree-ssa
+ project. */
+
+void
+simplify_aggr_init_expr (tree *tp)
+{
+ tree aggr_init_expr = *tp;
+
/* Form an appropriate CALL_EXPR. */
- fn = TREE_OPERAND (aggr_init_expr, 0);
- args = TREE_OPERAND (aggr_init_expr, 1);
- slot = TREE_OPERAND (aggr_init_expr, 2);
- type = TREE_TYPE (aggr_init_expr);
+ tree fn = TREE_OPERAND (aggr_init_expr, 0);
+ tree args = TREE_OPERAND (aggr_init_expr, 1);
+ tree slot = TREE_OPERAND (aggr_init_expr, 2);
+ tree type = TREE_TYPE (aggr_init_expr);
+
+ tree call_expr;
+ enum style_t { ctor, arg, pcc } style;
+
if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr))
+ style = ctor;
+#ifdef PCC_STATIC_STRUCT_RETURN
+ else if (1)
+ style = pcc;
+#endif
+ else if (TREE_ADDRESSABLE (type))
+ style = arg;
+ else
+ /* We shouldn't build an AGGR_INIT_EXPR if we don't need any special
+ handling. See build_cplus_new. */
+ abort ();
+
+ if (style == ctor || style == arg)
{
- /* Replace the first argument with the address of the third
- argument to the AGGR_INIT_EXPR. */
+ /* Pass the address of the slot. If this is a constructor, we
+ replace the first argument; otherwise, we tack on a new one. */
+ tree addr;
+
+ if (style == ctor)
+ args = TREE_CHAIN (args);
+
cxx_mark_addressable (slot);
- args = tree_cons (NULL_TREE,
- build1 (ADDR_EXPR,
- build_pointer_type (TREE_TYPE (slot)),
- slot),
- TREE_CHAIN (args));
+ addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (slot)), slot);
+ if (style == arg)
+ {
+ /* The return type might have different cv-quals from the slot. */
+ tree fntype = TREE_TYPE (TREE_TYPE (fn));
+#ifdef ENABLE_CHECKING
+ if (TREE_CODE (fntype) != FUNCTION_TYPE
+ && TREE_CODE (fntype) != METHOD_TYPE)
+ abort ();
+#endif
+ addr = convert (build_pointer_type (TREE_TYPE (fntype)), addr);
+ }
+
+ args = tree_cons (NULL_TREE, addr, args);
}
+
call_expr = build (CALL_EXPR,
TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
fn, args, NULL_TREE);
- TREE_SIDE_EFFECTS (call_expr) = 1;
- /* If we're using the non-reentrant PCC calling convention, then we
- need to copy the returned value out of the static buffer into the
- SLOT. */
- copy_from_buffer_p = 0;
-#ifdef PCC_STATIC_STRUCT_RETURN
- if (!AGGR_INIT_VIA_CTOR_P (aggr_init_expr) && aggregate_value_p (type))
+ if (style == arg)
+ /* Tell the backend that we've added our return slot to the argument
+ list. */
+ CALL_EXPR_HAS_RETURN_SLOT_ADDR (call_expr) = 1;
+ else if (style == pcc)
{
- int old_ac = flag_access_control;
-
- flag_access_control = 0;
+ /* If we're using the non-reentrant PCC calling convention, then we
+ need to copy the returned value out of the static buffer into the
+ SLOT. */
+ push_deferring_access_checks (dk_no_check);
call_expr = build_aggr_init (slot, call_expr,
DIRECT_BIND | LOOKUP_ONLYCONVERTING);
- flag_access_control = old_ac;
- copy_from_buffer_p = 1;
+ pop_deferring_access_checks ();
}
-#endif
- /* If this AGGR_INIT_EXPR indicates the value returned by a
- function, then we want to use the value of the initialized
- location as the result. */
- if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr) || copy_from_buffer_p)
- {
- call_expr = build (COMPOUND_EXPR, type,
- call_expr, slot);
- TREE_SIDE_EFFECTS (call_expr) = 1;
- }
+ /* We want to use the value of the initialized location as the
+ result. */
+ call_expr = build (COMPOUND_EXPR, type,
+ call_expr, slot);
/* Replace the AGGR_INIT_EXPR with the CALL_EXPR. */
TREE_CHAIN (call_expr) = TREE_CHAIN (aggr_init_expr);
*tp = call_expr;
-
- /* Keep iterating. */
- return NULL_TREE;
}
/* Emit all thunks to FN that should be emitted when FN is emitted. */
static void
-emit_associated_thunks (fn)
- tree fn;
+emit_associated_thunks (tree fn)
{
/* When we use vcall offsets, we emit thunks with the virtual
functions to which they thunk. The whole point of vcall offsets
@@ -2285,30 +2878,104 @@ emit_associated_thunks (fn)
if (DECL_VIRTUAL_P (fn))
{
tree thunk;
+
for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
- use_thunk (thunk, /*emit_p=*/1);
+ {
+ if (!THUNK_ALIAS (thunk))
+ {
+ use_thunk (thunk, /*emit_p=*/1);
+ if (DECL_RESULT_THUNK_P (thunk))
+ {
+ tree probe;
+
+ for (probe = DECL_THUNKS (thunk);
+ probe; probe = TREE_CHAIN (probe))
+ use_thunk (probe, /*emit_p=*/1);
+ }
+ }
+ else
+ my_friendly_assert (!DECL_THUNKS (thunk), 20031023);
+ }
}
}
/* Generate RTL for FN. */
void
-expand_body (fn)
- tree fn;
+expand_body (tree fn)
{
- int saved_lineno;
- const char *saved_input_filename;
tree saved_function;
+
+ /* Compute the appropriate object-file linkage for inline
+ functions. */
+ if (DECL_DECLARED_INLINE_P (fn))
+ import_export_decl (fn);
+
+ /* If FN is external, then there's no point in generating RTL for
+ it. This situation can arise with an inline function under
+ `-fexternal-templates'; we instantiate the function, even though
+ we're not planning on emitting it, in case we get a chance to
+ inline it. */
+ if (DECL_EXTERNAL (fn))
+ return;
+
+ /* ??? When is this needed? */
+ saved_function = current_function_decl;
+
+ /* Emit any thunks that should be emitted at the same time as FN. */
+ emit_associated_thunks (fn);
+
+ timevar_push (TV_INTEGRATION);
+ optimize_function (fn);
+ timevar_pop (TV_INTEGRATION);
+
+ tree_rest_of_compilation (fn, function_depth > 1);
+
+ current_function_decl = saved_function;
+
+ extract_interface_info ();
+ /* If this function is marked with the constructor attribute, add it
+ to the list of functions to be called along with constructors
+ from static duration objects. */
+ if (DECL_STATIC_CONSTRUCTOR (fn))
+ static_ctors = tree_cons (NULL_TREE, fn, static_ctors);
+
+ /* If this function is marked with the destructor attribute, add it
+ to the list of functions to be called along with destructors from
+ static duration objects. */
+ if (DECL_STATIC_DESTRUCTOR (fn))
+ static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
+
+ if (DECL_CLONED_FUNCTION_P (fn))
+ {
+ /* If this is a clone, go through the other clones now and mark
+ their parameters used. We have to do that here, as we don't
+ know whether any particular clone will be expanded, and
+ therefore cannot pick one arbitrarily. */
+ tree probe;
+
+ for (probe = TREE_CHAIN (DECL_CLONED_FUNCTION (fn));
+ probe && DECL_CLONED_FUNCTION_P (probe);
+ probe = TREE_CHAIN (probe))
+ {
+ tree parms;
+
+ for (parms = DECL_ARGUMENTS (probe);
+ parms; parms = TREE_CHAIN (parms))
+ TREE_USED (parms) = 1;
+ }
+ }
+}
+
+/* Generate RTL for FN. */
+
+void
+expand_or_defer_fn (tree fn)
+{
/* 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))))
+ function, we don't really want to expand the body. */
+ if (processing_template_decl)
{
/* Normally, collection only occurs in rest_of_compilation. So,
if we don't collect here, we never collect junk generated
@@ -2338,102 +3005,16 @@ expand_body (fn)
if (flag_syntax_only)
return;
- /* If possible, avoid generating RTL for this function. Instead,
- just record it as an inline function, and wait until end-of-file
- to decide whether to write it out or not. */
- if (/* We have to generate RTL if it's not an inline function. */
- (DECL_INLINE (fn) || DECL_COMDAT (fn))
- /* Or if we have to emit code for inline functions anyhow. */
- && !flag_keep_inline_functions
- /* Or if we actually have a reference to the function. */
- && !DECL_NEEDED_P (fn))
- {
- /* Set DECL_EXTERNAL so that assemble_external will be called as
- necessary. We'll clear it again in finish_file. */
- if (!DECL_EXTERNAL (fn))
- {
- DECL_NOT_REALLY_EXTERN (fn) = 1;
- DECL_EXTERNAL (fn) = 1;
- }
- /* Remember this function. In finish_file we'll decide if
- we actually need to write this function out. */
- defer_fn (fn);
- /* Let the back-end know that this function exists. */
- (*debug_hooks->deferred_inline_function) (fn);
- return;
- }
-
- /* Compute the appropriate object-file linkage for inline
- functions. */
+ /* Compute the appropriate object-file linkage for inline functions. */
if (DECL_DECLARED_INLINE_P (fn))
import_export_decl (fn);
- /* If FN is external, then there's no point in generating RTL for
- it. This situation can arise with an inline function under
- `-fexternal-templates'; we instantiate the function, even though
- we're not planning on emitting it, in case we get a chance to
- inline it. */
- if (DECL_EXTERNAL (fn))
- 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;
- saved_function = current_function_decl;
- lineno = DECL_SOURCE_LINE (fn);
- input_filename = DECL_SOURCE_FILE (fn);
- current_function_decl = fn;
+ function_depth++;
- timevar_push (TV_INTEGRATION);
-
- /* Optimize the body of the function before expanding it. */
- optimize_function (fn);
-
- timevar_pop (TV_INTEGRATION);
- timevar_push (TV_EXPAND);
+ /* Expand or defer, at the whim of the compilation unit manager. */
+ cgraph_finalize_function (fn, function_depth > 1);
- genrtl_start_function (fn);
- current_function_is_thunk = DECL_THUNK_P (fn);
-
- /* 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. */
- genrtl_finish_function (fn);
-
- /* If possible, obliterate the body of the function so that it can
- be garbage collected. */
- if (dump_enabled_p (TDI_all))
- /* Keep the body; we're going to dump it. */
- ;
- else if (DECL_INLINE (fn) && flag_inline_trees)
- /* We might need the body of this function so that we can expand
- it inline somewhere else. */
- ;
- else
- /* We don't need the body; blow it away. */
- DECL_SAVED_TREE (fn) = NULL_TREE;
-
- /* And restore the current source position. */
- current_function_decl = saved_function;
- lineno = saved_lineno;
- input_filename = saved_input_filename;
- extract_interface_info ();
-
- timevar_pop (TV_EXPAND);
-
- /* Emit any thunks that should be emitted at the same time as FN. */
- emit_associated_thunks (fn);
+ function_depth--;
}
/* Helper function for walk_tree, used by finish_function to override all
@@ -2441,10 +3022,7 @@ expand_body (fn)
value optimization. */
tree
-nullify_returns_r (tp, walk_subtrees, data)
- tree *tp;
- int *walk_subtrees;
- void *data;
+nullify_returns_r (tree* tp, int* walk_subtrees, void* data)
{
tree nrv = (tree) data;
@@ -2464,206 +3042,20 @@ nullify_returns_r (tp, walk_subtrees, data)
/* Start generating the RTL for FN. */
-static void
-genrtl_start_function (fn)
- tree fn;
-{
- /* Tell everybody what function we're processing. */
- current_function_decl = fn;
- /* Get the RTL machinery going for this function. */
- init_function_start (fn, DECL_SOURCE_FILE (fn), DECL_SOURCE_LINE (fn));
- /* Let everybody know that we're expanding this function, not doing
- semantic analysis. */
- expanding_p = 1;
-
- /* Even though we're inside a function body, we still don't want to
- call expand_expr to calculate the size of a variable-sized array.
- We haven't necessarily assigned RTL to all variables yet, so it's
- not safe to try to expand expressions involving them. */
- immediate_size_expand = 0;
- cfun->x_dont_save_pending_sizes_p = 1;
-
- /* Let the user know we're compiling this function. */
- announce_function (fn);
-
- /* Initialize the per-function data. */
- my_friendly_assert (!DECL_PENDING_INLINE_P (fn), 20000911);
- if (DECL_SAVED_FUNCTION_DATA (fn))
- {
- /* If we already parsed this function, and we're just expanding it
- now, restore saved state. */
- *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (fn);
-
- /* This function is being processed in whole-function mode; we
- already did semantic analysis. */
- cfun->x_whole_function_mode_p = 1;
-
- /* If we decided that we didn't want to inline this function,
- make sure the back-end knows that. */
- if (!current_function_cannot_inline)
- current_function_cannot_inline = cp_function_chain->cannot_inline;
-
- /* We don't need the saved data anymore. Unless this is an inline
- function; we need the named return value info for
- cp_copy_res_decl_for_inlining. */
- if (! DECL_INLINE (fn))
- DECL_SAVED_FUNCTION_DATA (fn) = NULL;
- }
-
- /* Keep track of how many functions we're presently expanding. */
- ++function_depth;
-
- /* Create a binding level for the parameters. */
- expand_function_start (fn, /*parms_have_cleanups=*/0);
- /* If this function is `main'. */
- if (DECL_MAIN_P (fn))
- expand_main_function ();
-
+void
+cxx_expand_function_start (void)
+{
/* Give our named return value the same RTL as our RESULT_DECL. */
if (current_function_return_value)
- COPY_DECL_RTL (DECL_RESULT (fn), current_function_return_value);
-}
-
-/* Finish generating the RTL for FN. */
-
-static void
-genrtl_finish_function (fn)
- tree fn;
-{
- tree t;
-
-#if 0
- if (write_symbols != NO_DEBUG)
- {
- /* Keep this code around in case we later want to control debug info
- based on whether a type is "used". (jason 1999-11-11) */
-
- tree ttype = target_type (fntype);
- tree parmdecl;
-
- if (IS_AGGR_TYPE (ttype))
- /* Let debugger know it should output info for this type. */
- note_debug_info_needed (ttype);
-
- for (parmdecl = DECL_ARGUMENTS (fndecl); parmdecl; parmdecl = TREE_CHAIN (parmdecl))
- {
- ttype = target_type (TREE_TYPE (parmdecl));
- if (IS_AGGR_TYPE (ttype))
- /* Let debugger know it should output info for this type. */
- note_debug_info_needed (ttype);
- }
- }
-#endif
-
- /* Clean house because we will need to reorder insns here. */
- do_pending_stack_adjust ();
-
- /* If we have a named return value, we need to force a return so that
- the return register is USEd. */
- if (DECL_NAME (DECL_RESULT (fn)))
- emit_jump (return_label);
-
- /* We hard-wired immediate_size_expand to zero in start_function.
- Expand_function_end will decrement this variable. So, we set the
- variable to one here, so that after the decrement it will remain
- zero. */
- immediate_size_expand = 1;
-
- /* Generate rtl for function exit. */
- expand_function_end (input_filename, lineno, 0);
-
- /* If this is a nested function (like a template instantiation that
- we're compiling in the midst of compiling something else), push a
- new GC context. That will keep local variables on the stack from
- being collected while we're doing the compilation of this
- function. */
- if (function_depth > 1)
- ggc_push_context ();
-
- /* There's no need to defer outputting this function any more; we
- know we want to output it. */
- DECL_DEFER_OUTPUT (fn) = 0;
-
- /* Run the optimizers and output the assembler code for this
- function. */
- rest_of_compilation (fn);
-
- /* Undo the call to ggc_push_context above. */
- if (function_depth > 1)
- ggc_pop_context ();
-
-#if 0
- /* Keep this code around in case we later want to control debug info
- based on whether a type is "used". (jason 1999-11-11) */
-
- if (ctype && TREE_ASM_WRITTEN (fn))
- note_debug_info_needed (ctype);
-#endif
-
- /* If this function is marked with the constructor attribute, add it
- to the list of functions to be called along with constructors
- from static duration objects. */
- if (DECL_STATIC_CONSTRUCTOR (fn))
- static_ctors = tree_cons (NULL_TREE, fn, static_ctors);
-
- /* If this function is marked with the destructor attribute, add it
- to the list of functions to be called along with destructors from
- static duration objects. */
- if (DECL_STATIC_DESTRUCTOR (fn))
- static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
-
- --function_depth;
-
- /* In C++, we should never be saving RTL for the function. */
- my_friendly_assert (!DECL_SAVED_INSNS (fn), 20010903);
-
- /* Since we don't need the RTL for this function anymore, stop
- pointing to it. That's especially important for LABEL_DECLs,
- since you can reach all the instructions in the function from the
- CODE_LABEL stored in the DECL_RTL for the LABEL_DECL. Walk the
- BLOCK-tree, clearing DECL_RTL for LABEL_DECLs and non-static
- local variables. */
- walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
- clear_decl_rtl,
- NULL);
-
- /* Clear out the RTL for the arguments. */
- for (t = DECL_ARGUMENTS (fn); t; t = TREE_CHAIN (t))
- {
- SET_DECL_RTL (t, NULL_RTX);
- DECL_INCOMING_RTL (t) = NULL_RTX;
- }
-
- if (!(flag_inline_trees && DECL_INLINE (fn)))
- /* DECL_INITIAL must remain nonzero so we know this was an
- actual function definition. */
- DECL_INITIAL (fn) = error_mark_node;
-
- /* Let the error reporting routines know that we're outside a
- function. For a nested function, this value is used in
- pop_cp_function_context and then reset via pop_function_context. */
- current_function_decl = NULL_TREE;
-}
-
-/* Clear out the DECL_RTL for the non-static variables in BLOCK and
- its sub-blocks. */
-
-static tree
-clear_decl_rtl (tp, walk_subtrees, data)
- tree *tp;
- int *walk_subtrees ATTRIBUTE_UNUSED;
- void *data ATTRIBUTE_UNUSED;
-{
- if (nonstatic_local_decl_p (*tp))
- SET_DECL_RTL (*tp, NULL_RTX);
-
- return NULL_TREE;
+ COPY_DECL_RTL (DECL_RESULT (cfun->decl), current_function_return_value);
}
/* Perform initialization related to this module. */
void
-init_cp_semantics ()
+init_cp_semantics (void)
{
lang_expand_stmt = cp_expand_stmt;
}
+
+#include "gt-cp-semantics.h"
OpenPOWER on IntegriCloud