building RTL. These routines are used both during actual parsing
and during the instantiation of template functions.
- Copyright (C) 1998, 1999, 2000, 2001, 2002,
- 2003, 2004 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.
#include "tm.h"
#include "tree.h"
#include "cp-tree.h"
+#include "c-common.h"
#include "tree-inline.h"
#include "tree-mudflap.h"
#include "except.h"
-#include "lex.h"
#include "toplev.h"
#include "flags.h"
#include "rtl.h"
#include "diagnostic.h"
#include "cgraph.h"
#include "tree-iterator.h"
+#include "vec.h"
+#include "target.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
In case of parsing error, we simply call `pop_deferring_access_checks'
without `perform_deferred_access_checks'. */
+typedef struct deferred_access GTY(())
+{
+ /* A TREE_LIST representing name-lookups for which we have deferred
+ checking access controls. We cannot check the accessibility of
+ names used in a decl-specifier-seq until we know what is being
+ declared because code like:
+
+ class A {
+ class B {};
+ B* f();
+ }
+
+ A::B* A::f() { return 0; }
+
+ is valid, even though `A::B' is not generally accessible.
+
+ The TREE_PURPOSE of each node is the scope used to qualify the
+ name being looked up; the TREE_VALUE is the DECL to which the
+ name was resolved. */
+ tree deferred_access_checks;
+
+ /* The current mode of access checks. */
+ enum deferring_kind deferring_access_checks_kind;
+
+} deferred_access;
+DEF_VEC_GC_O (deferred_access);
+
/* Data for deferred access checking. */
-static GTY(()) deferred_access *deferred_access_stack;
-static GTY(()) deferred_access *deferred_access_free_list;
+static GTY(()) VEC (deferred_access) *deferred_access_stack;
+static GTY(()) unsigned deferred_access_no_check;
/* 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;
- }
+ if (deferred_access_no_check || deferring == dk_no_check)
+ deferred_access_no_check++;
else
- d = ggc_alloc (sizeof (deferred_access));
+ {
+ deferred_access *ptr;
- d->next = deferred_access_stack;
- d->deferred_access_checks = NULL_TREE;
- d->deferring_access_checks_kind = deferring;
- deferred_access_stack = d;
+ ptr = VEC_safe_push (deferred_access, deferred_access_stack, NULL);
+ ptr->deferred_access_checks = NULL_TREE;
+ ptr->deferring_access_checks_kind = deferring;
+ }
}
/* Resume deferring access checks again after we stopped doing
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;
+ if (!deferred_access_no_check)
+ VEC_last (deferred_access, 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;
+ if (!deferred_access_no_check)
+ VEC_last (deferred_access, deferred_access_stack)
+ ->deferring_access_checks_kind = dk_no_deferred;
}
/* Discard the current deferred access checks and restore the
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;
+ if (deferred_access_no_check)
+ deferred_access_no_check--;
+ else
+ VEC_pop (deferred_access, deferred_access_stack);
}
/* Returns a TREE_LIST representing the deferred checks.
tree
get_deferred_access_checks (void)
{
- return deferred_access_stack->deferred_access_checks;
+ if (deferred_access_no_check)
+ return NULL;
+ else
+ return (VEC_last (deferred_access, deferred_access_stack)
+ ->deferred_access_checks);
}
/* Take current deferred checks and combine with the
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;
+ if (deferred_access_no_check)
+ deferred_access_no_check--;
+ else
+ {
+ tree checks;
+ deferred_access *ptr;
- 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));
+ checks = (VEC_last (deferred_access, deferred_access_stack)
+ ->deferred_access_checks);
- deferred_access_stack = d1;
- d1->next = d2;
- d2->next = d3;
- pop_deferring_access_checks ();
+ VEC_pop (deferred_access, deferred_access_stack);
+ ptr = VEC_last (deferred_access, deferred_access_stack);
+ if (ptr->deferring_access_checks_kind == dk_no_deferred)
+ {
+ /* Check access. */
+ for (; checks; checks = TREE_CHAIN (checks))
+ enforce_access (TREE_PURPOSE (checks),
+ TREE_VALUE (checks));
+ }
+ else
+ {
+ /* Merge with parent. */
+ tree next;
+ tree original = ptr->deferred_access_checks;
+
+ for (; checks; checks = next)
+ {
+ tree probe;
+
+ next = TREE_CHAIN (checks);
+
+ for (probe = original; probe; probe = TREE_CHAIN (probe))
+ if (TREE_VALUE (probe) == TREE_VALUE (checks)
+ && TREE_PURPOSE (probe) == TREE_PURPOSE (checks))
+ goto found;
+ /* Insert into parent's checks. */
+ TREE_CHAIN (checks) = ptr->deferred_access_checks;
+ ptr->deferred_access_checks = checks;
+ found:;
+ }
+ }
+ }
}
/* Perform the deferred access checks.
perform_deferred_access_checks (void)
{
tree deferred_check;
- for (deferred_check = deferred_access_stack->deferred_access_checks;
+
+ for (deferred_check = (VEC_last (deferred_access, deferred_access_stack)
+ ->deferred_access_checks);
deferred_check;
deferred_check = TREE_CHAIN (deferred_check))
/* Check access. */
perform_or_defer_access_check (tree binfo, tree decl)
{
tree check;
+ deferred_access *ptr;
- my_friendly_assert (TREE_CODE (binfo) == TREE_VEC, 20030623);
+ /* Exit if we are in a context that no access checking is performed.
+ */
+ if (deferred_access_no_check)
+ return;
+
+ gcc_assert (TREE_CODE (binfo) == TREE_BINFO);
+
+ ptr = VEC_last (deferred_access, deferred_access_stack);
/* If we are not supposed to defer access checks, just check now. */
- if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred)
+ if (ptr->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;
+ for (check = ptr->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);
+ ptr->deferred_access_checks
+ = tree_cons (binfo, decl, ptr->deferred_access_checks);
}
/* Returns nonzero if the current statement is a full expression,
: &scope_chain->x_stmt_tree);
}
+/* If statements are full expressions, wrap STMT in a CLEANUP_POINT_EXPR. */
+
+static tree
+maybe_cleanup_point_expr (tree expr)
+{
+ if (!processing_template_decl && stmts_are_full_exprs_p ())
+ expr = fold_build_cleanup_point_expr (TREE_TYPE (expr), expr);
+ return expr;
+}
+
+/* Like maybe_cleanup_point_expr except have the type of the new expression be
+ void so we don't need to create a temporary variable to hold the inner
+ expression. The reason why we do this is because the original type might be
+ an aggregate and we cannot create a temporary variable for that type. */
+
+static tree
+maybe_cleanup_point_expr_void (tree expr)
+{
+ if (!processing_template_decl && stmts_are_full_exprs_p ())
+ expr = fold_build_cleanup_point_expr (void_type_node, expr);
+ return expr;
+}
+
+
+
+/* Create a declaration statement for the declaration given by the DECL. */
+
+void
+add_decl_expr (tree decl)
+{
+ tree r = build_stmt (DECL_EXPR, decl);
+ if (DECL_INITIAL (decl)
+ || (DECL_SIZE (decl) && TREE_SIDE_EFFECTS (DECL_SIZE (decl))))
+ r = maybe_cleanup_point_expr_void (r);
+ add_stmt (r);
+}
+
/* Nonzero if TYPE is an anonymous union or struct type. We have to use a
flag for this because "A union for which objects or pointers are
declared is not an anonymous union" [class.union]. */
/* Finish a scope. */
-static tree
+tree
do_poplevel (tree stmt_list)
{
tree block = NULL;
return ret;
}
-/* Finish processing a conditional. COND contains the raw expression;
- STMT_P is a stacked statement list that will contain any other stmts
- emitting during the processing of this conditional. Place the
- resulting conditional back in STMT_P. */
+/* Queue a cleanup. CLEANUP is an expression/statement to be executed
+ when the current scope is exited. EH_ONLY is true when this is not
+ meant to apply to normal control flow transfer. */
+
+void
+push_cleanup (tree decl, tree cleanup, bool eh_only)
+{
+ tree stmt = build_stmt (CLEANUP_STMT, NULL, cleanup, decl);
+ CLEANUP_EH_ONLY (stmt) = eh_only;
+ add_stmt (stmt);
+ CLEANUP_BODY (stmt) = push_stmt_list ();
+}
+
+/* Begin a conditional that might contain a declaration. When generating
+ normal code, we want the declaration to appear before the statement
+ containing the conditional. When generating template code, we want the
+ conditional to be rendered as the raw DECL_EXPR. */
static void
-finish_cond (tree cond, tree *stmt_p)
-{
- tree stmt = *stmt_p;
- stmt = pop_stmt_list (stmt);
- if (TREE_SIDE_EFFECTS (stmt))
- {
- /* If stmt is set, it will be a DECL_STMT. When processing a template,
- using this is enough, because tsubst_expr considers the result of a
- DECL_STMT to be the DECL. When generating real code, we build a
- funny little TREE_LIST thingy that's handled by the gimplifier. */
- /* ??? The object of this thingy is to get the DECL declared in the
- proper scope. Seems like this oughtn't be terribly hard with the
- new explicit uses of BIND_EXPR and such. */
- if (processing_template_decl)
- {
- stmt = expr_only (stmt);
- if (!stmt)
- abort ();
- }
- else
- stmt = build_tree_list (stmt, cond);
+begin_cond (tree *cond_p)
+{
+ if (processing_template_decl)
+ *cond_p = push_stmt_list ();
+}
+
+/* Finish such a conditional. */
+
+static void
+finish_cond (tree *cond_p, tree expr)
+{
+ if (processing_template_decl)
+ {
+ tree cond = pop_stmt_list (*cond_p);
+ if (TREE_CODE (cond) == DECL_EXPR)
+ expr = cond;
}
- else
- stmt = cond;
- *stmt_p = stmt;
+ *cond_p = expr;
}
/* If *COND_P specifies a conditional with a declaration, transform the
loop such that
- while (A x = 42) { }
- for (; A x = 42;) { }
+ while (A x = 42) { }
+ for (; A x = 42;) { }
becomes
- while (true) { A x = 42; if (!x) break; }
- for (;;) { A x = 42; if (!x) break; }
- The statement list for the loop body should have been pushed. */
-
+ while (true) { A x = 42; if (!x) break; }
+ for (;;) { A x = 42; if (!x) break; }
+ The statement list for BODY will be empty if the conditional did
+ not declare anything. */
+
static void
-simplify_loop_decl_cond (tree *cond_p)
+simplify_loop_decl_cond (tree *cond_p, tree body)
{
- tree cond = *cond_p;
- if (TREE_CODE (cond) == TREE_LIST)
- {
- tree if_stmt;
+ tree cond, if_stmt;
- *cond_p = boolean_true_node;
-
- if_stmt = begin_if_stmt ();
- add_stmt (TREE_PURPOSE (cond));
- cond = build_unary_op (TRUTH_NOT_EXPR, TREE_VALUE (cond), 0);
- finish_if_stmt_cond (cond, if_stmt);
- finish_break_stmt ();
- finish_then_clause (if_stmt);
- finish_if_stmt (if_stmt);
- }
-}
+ if (!TREE_SIDE_EFFECTS (body))
+ return;
+ cond = *cond_p;
+ *cond_p = boolean_true_node;
+
+ if_stmt = begin_if_stmt ();
+ cond = build_unary_op (TRUTH_NOT_EXPR, cond, 0);
+ finish_if_stmt_cond (cond, if_stmt);
+ finish_break_stmt ();
+ finish_then_clause (if_stmt);
+ finish_if_stmt (if_stmt);
+}
/* Finish a goto-statement. */
check_goto (destination);
- return add_stmt (build_stmt (GOTO_STMT, destination));
+ return add_stmt (build_stmt (GOTO_EXPR, destination));
}
/* COND is the condition-expression for an if, while, etc.,
if (expr != NULL_TREE)
{
if (!processing_template_decl)
- expr = convert_to_void (expr, "statement");
+ {
+ if (warn_sequence_point)
+ verify_sequence_points (expr);
+ expr = convert_to_void (expr, "statement");
+ }
else if (!type_dependent_expression_p (expr))
convert_to_void (build_non_dependent_expr (expr), "statement");
/* Simplification of inner statement expressions, compound exprs,
- etc can result in the us already having an EXPR_STMT. */
- if (TREE_CODE (expr) != EXPR_STMT)
- expr = build_stmt (EXPR_STMT, expr);
+ etc can result in us already having an EXPR_STMT. */
+ if (TREE_CODE (expr) != CLEANUP_POINT_EXPR)
+ {
+ if (TREE_CODE (expr) != EXPR_STMT)
+ expr = build_stmt (EXPR_STMT, expr);
+ expr = maybe_cleanup_point_expr_void (expr);
+ }
+
r = add_stmt (expr);
}
scope = do_pushlevel (sk_block);
r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
TREE_CHAIN (r) = scope;
- add_stmt (r);
- IF_COND (r) = push_stmt_list ();
+ begin_cond (&IF_COND (r));
return r;
}
void
finish_if_stmt_cond (tree cond, tree if_stmt)
{
- cond = maybe_convert_cond (cond);
- finish_cond (cond, &IF_COND (if_stmt));
+ finish_cond (&IF_COND (if_stmt), maybe_convert_cond (cond));
+ add_stmt (if_stmt);
THEN_CLAUSE (if_stmt) = push_stmt_list ();
}
r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
add_stmt (r);
WHILE_BODY (r) = do_pushlevel (sk_block);
- WHILE_COND (r) = push_stmt_list ();
+ begin_cond (&WHILE_COND (r));
return r;
}
void
finish_while_stmt_cond (tree cond, tree while_stmt)
{
- cond = maybe_convert_cond (cond);
- finish_cond (cond, &WHILE_COND (while_stmt));
- simplify_loop_decl_cond (&WHILE_COND (while_stmt));
+ finish_cond (&WHILE_COND (while_stmt), maybe_convert_cond (cond));
+ simplify_loop_decl_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt));
}
/* Finish a while-statement, which may be given by WHILE_STMT. */
expr = check_return_expr (expr);
if (!processing_template_decl)
{
- if (DECL_DESTRUCTOR_P (current_function_decl))
+ if (DECL_DESTRUCTOR_P (current_function_decl)
+ || (DECL_CONSTRUCTOR_P (current_function_decl)
+ && targetm.cxx.cdtor_returns_this ()))
{
/* Similarly, all destructors must run destructors for
base-classes before returning. So, all returns in a
destructor get sent to the DTOR_LABEL; finish_function emits
code to return a value there. */
- return finish_goto_stmt (dtor_label);
+ return finish_goto_stmt (cdtor_label);
}
}
- r = add_stmt (build_stmt (RETURN_STMT, expr));
+
+ r = build_stmt (RETURN_EXPR, expr);
+ r = maybe_cleanup_point_expr_void (r);
+ r = add_stmt (r);
finish_stmt ();
return r;
if (flag_new_for_scope > 0)
TREE_CHAIN (r) = do_pushlevel (sk_for);
+ if (processing_template_decl)
+ FOR_INIT_STMT (r) = push_stmt_list ();
+
return r;
}
void
finish_for_init_stmt (tree for_stmt)
{
+ if (processing_template_decl)
+ FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt));
add_stmt (for_stmt);
FOR_BODY (for_stmt) = do_pushlevel (sk_block);
- FOR_COND (for_stmt) = push_stmt_list ();
+ begin_cond (&FOR_COND (for_stmt));
}
/* Finish the COND of a for-statement, which may be given by
void
finish_for_cond (tree cond, tree for_stmt)
{
- cond = maybe_convert_cond (cond);
- finish_cond (cond, &FOR_COND (for_stmt));
- if (FOR_COND (for_stmt))
- simplify_loop_decl_cond (&FOR_COND (for_stmt));
+ finish_cond (&FOR_COND (for_stmt), maybe_convert_cond (cond));
+ simplify_loop_decl_cond (&FOR_COND (for_stmt), FOR_BODY (for_stmt));
}
/* Finish the increment-EXPRESSION in a for-statement, which may be
void
finish_for_expr (tree expr, tree for_stmt)
{
+ if (!expr)
+ return;
/* 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))
+ if (type_unknown_p (expr))
{
cxx_incomplete_type_error (expr, TREE_TYPE (expr));
expr = error_mark_node;
}
+ if (!processing_template_decl)
+ {
+ if (warn_sequence_point)
+ verify_sequence_points (expr);
+ expr = convert_to_void (expr, "3rd expression in for");
+ }
+ else if (!type_dependent_expression_p (expr))
+ convert_to_void (build_non_dependent_expr (expr), "3rd expression in for");
+ expr = maybe_cleanup_point_expr_void (expr);
FOR_EXPR (for_stmt) = expr;
}
scope = do_pushlevel (sk_block);
TREE_CHAIN (r) = scope;
-
- add_stmt (r);
- SWITCH_COND (r) = push_stmt_list ();
+ begin_cond (&SWITCH_COND (r));
return r;
}
Integral promotions are performed. */
cond = perform_integral_promotions (cond);
- cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond));
+ cond = maybe_cleanup_point_expr (cond);
}
if (cond != error_mark_node)
cond = index;
}
}
- finish_cond (cond, &SWITCH_COND (switch_stmt));
+ finish_cond (&SWITCH_COND (switch_stmt), cond);
SWITCH_TYPE (switch_stmt) = orig_type;
+ add_stmt (switch_stmt);
push_switch (switch_stmt);
SWITCH_BODY (switch_stmt) = push_stmt_list ();
}
HANDLER_BODY (handler) = do_poplevel (HANDLER_BODY (handler));
}
-/* Begin a compound-statement. If HAS_NO_SCOPE is true, the
- compound-statement does not define a scope. Returns a new
- COMPOUND_STMT. */
+/* Begin a compound statement. FLAGS contains some bits that control the
+ behavior and context. If BCS_NO_SCOPE is set, the compound statement
+ does not define a scope. If BCS_FN_BODY is set, this is the outermost
+ block of a function. If BCS_TRY_BLOCK is set, this is the block
+ created on behalf of a TRY statement. Returns a token to be passed to
+ finish_compound_stmt. */
tree
begin_compound_stmt (unsigned int flags)
else
r = do_pushlevel (flags & BCS_TRY_BLOCK ? sk_try : sk_block);
- if (flags & BCS_FN_BODY || processing_template_decl)
+ /* When processing a template, we need to remember where the braces were,
+ so that we can set up identical scopes when instantiating the template
+ later. BIND_EXPR is a handy candidate for this.
+ Note that do_poplevel won't create a BIND_EXPR itself here (and thus
+ result in nested BIND_EXPRs), since we don't build BLOCK nodes when
+ processing templates. */
+ if (processing_template_decl)
{
- r = build (COMPOUND_STMT, NULL_TREE, r);
- COMPOUND_STMT_TRY_BLOCK (r) = (flags & BCS_TRY_BLOCK) != 0;
- COMPOUND_STMT_BODY_BLOCK (r) = (flags & BCS_FN_BODY) != 0;
+ r = build3 (BIND_EXPR, NULL, NULL, r, NULL);
+ BIND_EXPR_TRY_BLOCK (r) = (flags & BCS_TRY_BLOCK) != 0;
+ BIND_EXPR_BODY_BLOCK (r) = (flags & BCS_FN_BODY) != 0;
TREE_SIDE_EFFECTS (r) = 1;
}
return r;
}
-/* Finish a compound-statement, which is given by COMPOUND_STMT. */
+/* Finish a compound-statement, which is given by STMT. */
void
finish_compound_stmt (tree stmt)
{
- if (TREE_CODE (stmt) == COMPOUND_STMT)
- COMPOUND_BODY (stmt) = do_poplevel (COMPOUND_BODY (stmt));
+ if (TREE_CODE (stmt) == BIND_EXPR)
+ BIND_EXPR_BODY (stmt) = do_poplevel (BIND_EXPR_BODY (stmt));
else if (STATEMENT_LIST_NO_SCOPE (stmt))
stmt = pop_stmt_list (stmt);
else
- stmt = do_poplevel (stmt);
+ {
+ /* Destroy any ObjC "super" receivers that may have been
+ created. */
+ objc_clear_super_receiver ();
+
+ stmt = do_poplevel (stmt);
+ }
/* ??? See c_end_compound_stmt wrt statement expressions. */
add_stmt (stmt);
resolve the overloading. */
if (TREE_TYPE (converted_operand) == unknown_type_node)
{
- error ("type of asm operand `%E' could not be determined",
- TREE_VALUE (t));
+ error ("type of asm operand %qE could not be determined",
+ TREE_VALUE (t));
converted_operand = error_mark_node;
}
TREE_VALUE (t) = converted_operand;
}
}
- r = build_stmt (ASM_STMT, string,
+ r = build_stmt (ASM_EXPR, string,
output_operands, input_operands,
clobbers);
ASM_VOLATILE_P (r) = volatile_p;
+ r = maybe_cleanup_point_expr_void (r);
return add_stmt (r);
}
finish_label_stmt (tree name)
{
tree decl = define_label (input_location, name);
- return add_stmt (build_stmt (LABEL_STMT, decl));
+ return add_stmt (build_stmt (LABEL_EXPR, decl));
}
/* Finish a series of declarations for local labels. G++ allows users
finish_label_decl (tree name)
{
tree decl = declare_local_label (name);
- add_decl_stmt (decl);
+ add_decl_expr (decl);
}
/* When DECL goes out of scope, make sure that CLEANUP is executed. */
tree
finish_parenthesized_expr (tree expr)
{
- if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expr))))
+ if (EXPR_P (expr))
/* This inhibits warnings in c_common_truthvalue_conversion. */
- C_SET_EXP_ORIGINAL_CODE (expr, ERROR_MARK);
+ TREE_NO_WARNING (expr) = 1;
if (TREE_CODE (expr) == OFFSET_REF)
/* [expr.unary.op]/3 The qualified id of a pointer-to-member must not be
tree
finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
{
- my_friendly_assert (TREE_CODE (decl) == FIELD_DECL, 20020909);
+ gcc_assert (TREE_CODE (decl) == FIELD_DECL);
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",
+ cp_error_at ("invalid use of member %qD in static member function",
decl);
else
- cp_error_at ("invalid use of non-static data member `%D'", decl);
+ cp_error_at ("invalid use of non-static data member %qD", decl);
error ("from this location");
return error_mark_node;
type = cp_build_qualified_type (type, quals);
}
- return build_min (COMPONENT_REF, type, object, decl);
+ return build_min (COMPONENT_REF, type, object, decl, NULL_TREE);
}
else
{
if (!access_type)
{
- cp_error_at ("object missing in reference to `%D'", decl);
+ cp_error_at ("object missing in reference to %qD", decl);
error ("from this location");
return error_mark_node;
}
{
tree scope;
tree qualifying_type = NULL_TREE;
+
+ /* If we're not checking, return immediately. */
+ if (deferred_access_no_check)
+ return;
/* Determine the SCOPE of DECL. */
scope = context_for_name_lookup (decl);
its bases. */
qualifying_type = currently_open_derived_class (scope);
- if (qualifying_type)
+ if (qualifying_type && IS_AGGR_TYPE_CODE (TREE_CODE (qualifying_type)))
+ /* It is possible for qualifying type to be a TEMPLATE_TYPE_PARM
+ or similar in a default argument value. */
perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl);
}
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
+ if (!shared_member_p (fns)
+ && current_class_type
&& DERIVED_FROM_P (qualifying_class, current_class_type))
expr = (build_class_member_access_expr
(maybe_dummy_object (qualifying_class, NULL),
finish_stmt_expr_expr (tree expr, tree stmt_expr)
{
tree result = NULL_TREE;
- tree type = void_type_node;
if (expr)
{
- type = TREE_TYPE (expr);
-
if (!processing_template_decl && !VOID_TYPE_P (TREE_TYPE (expr)))
{
+ tree type = 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);
+ type = TREE_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
expr = build_special_member_call
(NULL_TREE, complete_ctor_identifier,
build_tree_list (NULL_TREE, expr),
- TYPE_BINFO (type), LOOKUP_NORMAL);
+ type, LOOKUP_NORMAL);
expr = build_cplus_new (type, expr);
- my_friendly_assert (TREE_CODE (expr) == TARGET_EXPR, 20030729);
+ gcc_assert (TREE_CODE (expr) == TARGET_EXPR);
}
}
case BIND_EXPR:
result_stmt_p = &BIND_EXPR_BODY (t);
break;
- case COMPOUND_STMT:
- result_stmt_p = &COMPOUND_BODY (t);
- break;
case TRY_FINALLY_EXPR:
case TRY_CATCH_EXPR:
case CLEANUP_STMT:
result_stmt_p = &TREE_OPERAND (t, 0);
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
type = TREE_TYPE (EXPR_STMT_EXPR (result_stmt));
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);
- *result_stmt_p = TREE_OPERAND (last_expr, 1);
+ tree init, target_expr = EXPR_STMT_EXPR (result_stmt);
+ gcc_assert (TREE_CODE (target_expr) == TARGET_EXPR);
+
+ /* The initializer will be void if the initialization is done by
+ AGGR_INIT_EXPR; propagate that out to the statement-expression as
+ a whole. */
+ init = TREE_OPERAND (target_expr, 1);
+ type = TREE_TYPE (init);
- if (TREE_CODE (result) == BIND_EXPR)
+ init = maybe_cleanup_point_expr (init);
+ *result_stmt_p = init;
+
+ if (VOID_TYPE_P (type))
+ /* No frobbing needed. */;
+ else if (TREE_CODE (result) == BIND_EXPR)
{
+ /* The BIND_EXPR created in finish_compound_stmt is void; if we're
+ returning a value directly, give it the appropriate type. */
if (VOID_TYPE_P (TREE_TYPE (result)))
- TREE_TYPE (result) = TREE_TYPE (last_expr);
- else if (same_type_p (TREE_TYPE (result), TREE_TYPE (last_expr)))
- ;
+ TREE_TYPE (result) = type;
else
- abort ();
+ gcc_assert (same_type_p (TREE_TYPE (result), type));
}
else if (TREE_CODE (result) == STATEMENT_LIST)
- result = build (BIND_EXPR, TREE_TYPE (last_expr), NULL, result, NULL);
+ /* We need to wrap a STATEMENT_LIST in a BIND_EXPR so it can have a
+ type other than void. FIXME why can't we just return a value
+ from STATEMENT_LIST? */
+ result = build3 (BIND_EXPR, type, NULL, result, NULL);
- TREE_OPERAND (last_expr, 1) = result;
- result = last_expr;
+ TREE_OPERAND (target_expr, 1) = result;
+ result = target_expr;
}
return result;
return error_mark_node;
/* ARGS should be a list of arguments. */
- my_friendly_assert (!args || TREE_CODE (args) == TREE_LIST,
- 20020712);
+ gcc_assert (!args || TREE_CODE (args) == TREE_LIST);
orig_fn = fn;
orig_args = args;
if (processing_template_decl)
{
- result = build (CALL_EXPR, TREE_TYPE (result), orig_fn,
- orig_args, NULL_TREE);
+ result = build3 (CALL_EXPR, TREE_TYPE (result), orig_fn,
+ orig_args, NULL_TREE);
KOENIG_LOOKUP_P (result) = koenig_p;
}
return result;
else if (current_function_decl
&& DECL_STATIC_FUNCTION_P (current_function_decl))
{
- error ("`this' is unavailable for static member functions");
+ error ("%<this%> is unavailable for static member functions");
result = error_mark_node;
}
else
{
if (current_function_decl)
- error ("invalid use of `this' in non-member function");
+ error ("invalid use of %<this%> in non-member function");
else
- error ("invalid use of `this' at top level");
+ error ("invalid use of %<this%> at top level");
result = error_mark_node;
}
if (destructor == error_mark_node)
return error_mark_node;
- my_friendly_assert (TYPE_P (destructor), 20010905);
+ gcc_assert (TYPE_P (destructor));
if (!processing_template_decl)
{
if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (object),
destructor))
{
- error ("`%E' is not of type `%T'", object, destructor);
+ error ("%qE is not of type %qT", object, destructor);
return error_mark_node;
}
}
- return build (PSEUDO_DTOR_EXPR, void_type_node, object, scope, destructor);
+ return build3 (PSEUDO_DTOR_EXPR, void_type_node, object, scope, destructor);
}
/* Finish an expression of the form CODE EXPR. */
return decl;
}
-/* Begin a function definition declared with DECL_SPECS, ATTRIBUTES,
- and DECLARATOR. Returns nonzero if the function-declaration is
- valid. */
-
-int
-begin_function_definition (tree decl_specs, tree attributes, tree declarator)
-{
- if (!start_function (decl_specs, declarator, attributes, SF_DEFAULT))
- return 0;
-
- /* The things we're about to see are not directly qualified by any
- template headers we've seen thus far. */
- reset_specialization ();
-
- return 1;
-}
-
/* Finish a translation unit. */
void
{
if (aggr != class_type_node)
{
- pedwarn ("template type parameters must use the keyword `class' or `typename'");
+ pedwarn ("template type parameters must use the keyword %<class%> or %<typename%>");
aggr = class_type_node;
}
DECL_ARTIFICIAL (decl) = 1;
end_template_decl ();
- my_friendly_assert (DECL_TEMPLATE_PARMS (tmpl), 20010110);
+ gcc_assert (DECL_TEMPLATE_PARMS (tmpl));
return finish_template_type_parm (aggr, tmpl);
}
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 "
+ error ("invalid use of type %qT as a default value for a "
"template template-parameter", t);
else
- error ("invalid use of `%D' as a default value for a template "
+ error ("invalid use of %qD as a default value for a template "
"template-parameter", argument);
}
else
return argument;
}
-/* Finish a parameter list, indicated by PARMS. If ELLIPSIS is
- nonzero, the parameter list was terminated by a `...'. */
-
-tree
-finish_parmlist (tree parms, int ellipsis)
-{
- if (parms)
- {
- /* We mark the PARMS as a parmlist so that declarator processing can
- disambiguate certain constructs. */
- TREE_PARMLIST (parms) = 1;
- /* We do not append void_list_node here, but leave it to grokparms
- to do that. */
- PARMLIST_ELLIPSIS_P (parms) = ellipsis;
- }
- return parms;
-}
-
/* Begin a class definition, as indicated by T. */
tree
if (processing_template_parmlist)
{
- error ("definition of `%#T' inside template parameter list", t);
+ error ("definition of %q#T inside template parameter list", t);
return error_mark_node;
}
/* A non-implicit typename comes from code like:
This is erroneous. */
else if (TREE_CODE (t) == TYPENAME_TYPE)
{
- error ("invalid definition of qualified type `%T'", t);
+ error ("invalid definition of qualified type %qT", t);
t = error_mark_node;
}
that's an error. */
if (COMPLETE_TYPE_P (t))
{
- error ("redefinition of `%#T'", t);
- cp_error_at ("previous definition of `%#T'", t);
+ error ("redefinition of %q#T", t);
+ cp_error_at ("previous definition of %q#T", t);
return error_mark_node;
}
before. */
if (! TYPE_ANONYMOUS_P (t))
{
- CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
+ struct c_fileinfo *finfo = get_fileinfo (lbasename (input_filename));
+ CLASSTYPE_INTERFACE_ONLY (t) = finfo->interface_only;
SET_CLASSTYPE_INTERFACE_UNKNOWN_X
- (t, interface_unknown);
+ (t, finfo->interface_unknown);
}
reset_specialization();
return;
/* We should see only one DECL at a time. */
- my_friendly_assert (TREE_CHAIN (decl) == NULL_TREE, 0);
+ gcc_assert (TREE_CHAIN (decl) == NULL_TREE);
/* Set up access control for DECL. */
TREE_PRIVATE (decl)
{
/* We also need to add this function to the
CLASSTYPE_METHOD_VEC. */
- add_method (current_class_type, decl, /*error_p=*/0);
+ add_method (current_class_type, decl);
TREE_CHAIN (decl) = TYPE_METHODS (current_class_type);
TYPE_METHODS (current_class_type) = decl;
}
}
-/* Finish processing the declaration of a member class template
- TYPES whose template parameters are given by PARMS. */
-
-tree
-finish_member_class_template (tree types)
-{
- tree t;
-
- /* If there are declared, but undefined, partial specializations
- mixed in with the typespecs they will not yet have passed through
- maybe_process_partial_specialization, so we do that here. */
- for (t = types; t != NULL_TREE; t = TREE_CHAIN (t))
- if (IS_AGGR_TYPE_CODE (TREE_CODE (TREE_VALUE (t))))
- maybe_process_partial_specialization (TREE_VALUE (t));
-
- grok_x_components (types);
- if (TYPE_CONTEXT (TREE_VALUE (types)) != current_class_type)
- /* The component was in fact a friend declaration. We avoid
- finish_member_template_decl performing certain checks by
- unsetting TYPES. */
- types = NULL_TREE;
-
- finish_member_template_decl (types);
-
- /* As with other component type declarations, we do
- not store the new DECL on the list of
- component_decls. */
- return NULL_TREE;
-}
-
/* Finish processing a complete template declaration. The PARMS are
the template parameters. */
Return a TREE_LIST containing the ACCESS_SPECIFIER and the
BASE_CLASS, or NULL_TREE if an error occurred. The
ACCESS_SPECIFIER is one of
- access_{default,public,protected_private}[_virtual]_node.*/
+ access_{default,public,protected_private}_node. For a virtual base
+ we set TREE_TYPE. */
tree
finish_base_specifier (tree base, tree access, bool virtual_p)
{
if (cp_type_quals (base) != 0)
{
- error ("base class `%T' has cv qualifiers", base);
+ error ("base class %qT has cv qualifiers", base);
base = TYPE_MAIN_VARIANT (base);
}
result = build_tree_list (access, base);
- TREE_VIA_VIRTUAL (result) = virtual_p;
+ if (virtual_p)
+ TREE_TYPE (result) = integer_type_node;
}
return result;
error ("multiple declarators in template declaration");
}
-/* Issue a diagnostic that NAME cannot be found in SCOPE. */
+/* Issue a diagnostic that NAME cannot be found in SCOPE. DECL is
+ what we found when we tried to do the lookup. */
void
-qualified_name_lookup_error (tree scope, tree name)
+qualified_name_lookup_error (tree scope, tree name, tree decl)
{
if (TYPE_P (scope))
{
if (!COMPLETE_TYPE_P (scope))
- error ("incomplete type `%T' used in nested name specifier", scope);
+ error ("incomplete type %qT used in nested name specifier", scope);
+ else if (TREE_CODE (decl) == TREE_LIST)
+ {
+ error ("reference to %<%T::%D%> is ambiguous", scope, name);
+ print_candidates (decl);
+ }
else
- error ("`%D' is not a member of `%T'", name, scope);
+ error ("%qD is not a member of %qT", name, scope);
}
else if (scope != global_namespace)
- error ("`%D' is not a member of `%D'", name, scope);
+ error ("%qD is not a member of %qD", name, scope);
else
- error ("`::%D' has not been declared", name);
+ error ("%<::%D%> has not been declared", name);
}
/* ID_EXPRESSION is a representation of parsed, but unprocessed,
/* 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);
+ qualified_name_lookup_error (scope, id_expression, decl);
return error_mark_node;
}
else if (!scope)
&& !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 "
+ error ("template parameter %qD of type %qT 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;
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);
+ return build2 (SCOPE_REF, TREE_TYPE (decl), scope,
+ id_expression);
else
return decl;
}
/* Only certain kinds of names are allowed in constant
expression. Enumerators and template parameters
have already been handled above. */
- if (integral_constant_expression_p)
+ if (integral_constant_expression_p
+ && !DECL_INTEGRAL_CONSTANT_VAR_P (decl))
{
- /* 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)
{
- 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;
+ error ("%qD 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);
+ error ("use of namespace %qD as expression", decl);
return error_mark_node;
}
else if (DECL_CLASS_TEMPLATE_P (decl))
{
- error ("use of class template `%T' as expression", decl);
+ error ("use of class template %qT 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 "
+ error ("request for member %qD is ambiguous in "
"multiple inheritance lattice", id_expression);
print_candidates (decl);
return error_mark_node;
else if (!processing_template_decl)
decl = convert_from_reference (decl);
else if (TYPE_P (scope))
- decl = build (SCOPE_REF, TREE_TYPE (decl), scope, decl);
+ decl = build2 (SCOPE_REF, TREE_TYPE (decl), scope, decl);
}
else if (TREE_CODE (decl) == FIELD_DECL)
decl = finish_non_static_data_member (decl, current_class_ref,
mark_used (first_fn);
if (TREE_CODE (first_fn) == FUNCTION_DECL
- && DECL_FUNCTION_MEMBER_P (first_fn))
+ && DECL_FUNCTION_MEMBER_P (first_fn)
+ && !shared_member_p (decl))
{
/* A set of member functions. */
decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0);
{
error ("use of %s from containing function",
(TREE_CODE (decl) == VAR_DECL
- ? "`auto' variable" : "parameter"));
- cp_error_at (" `%#D' declared here", decl);
+ ? "%<auto%> variable" : "parameter"));
+ cp_error_at (" %q#D declared here", decl);
return error_mark_node;
}
}
if (!type || type == unknown_type_node)
{
- error ("type of `%E' is unknown", expr);
+ error ("type of %qE is unknown", expr);
return error_mark_node;
}
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 type = TREE_TYPE (slot);
tree call_expr;
enum style_t { ctor, arg, pcc } style;
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 ();
+ {
+ gcc_assert (TREE_ADDRESSABLE (type));
+ style = arg;
+ }
if (style == ctor || style == arg)
{
args = TREE_CHAIN (args);
cxx_mark_addressable (slot);
- addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (slot)), slot);
+ addr = build1 (ADDR_EXPR, build_pointer_type (type), 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
+
+ gcc_assert (TREE_CODE (fntype) == FUNCTION_TYPE
+ || TREE_CODE (fntype) == METHOD_TYPE);
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);
+ call_expr = build3 (CALL_EXPR,
+ TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
+ fn, args, NULL_TREE);
if (style == arg)
/* Tell the backend that we've added our return slot to the argument
pop_deferring_access_checks ();
}
- /* We want to use the value of the initialized location as the
- result. */
- call_expr = build (COMPOUND_EXPR, type, call_expr, slot);
-
*tp = call_expr;
}
}
}
else
- my_friendly_assert (!DECL_THUNKS (thunk), 20031023);
+ gcc_assert (!DECL_THUNKS (thunk));
}
}
}
/* Emit any thunks that should be emitted at the same time as FN. */
emit_associated_thunks (fn);
- tree_rest_of_compilation (fn, function_depth > 1);
-
- current_function_decl = saved_function;
-
- extract_interface_info ();
+ /* This function is only called from cgraph, or recursively from
+ emit_associated_thunks. In neither case should we be currently
+ generating trees for a function. */
+ gcc_assert (function_depth == 0);
- /* 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);
+ tree_rest_of_compilation (fn);
- /* 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);
+ current_function_decl = saved_function;
if (DECL_CLONED_FUNCTION_P (fn))
{
return;
}
+ /* 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);
+
+ /* We make a decision about linkage for these functions at the end
+ of the compilation. Until that point, we do not want the back
+ end to output them -- but we do want it to see the bodies of
+ these functions so that it can inline them as appropriate. */
+ if (DECL_DECLARED_INLINE_P (fn) || DECL_IMPLICIT_INSTANTIATION (fn))
+ {
+ if (!at_eof)
+ {
+ DECL_EXTERNAL (fn) = 1;
+ DECL_NOT_REALLY_EXTERN (fn) = 1;
+ note_vague_linkage_fn (fn);
+ }
+ else
+ import_export_decl (fn);
+
+ /* If the user wants us to keep all inline functions, then mark
+ this function as needed so that finish_file will make sure to
+ output it later. */
+ if (flag_keep_inline_functions && DECL_DECLARED_INLINE_P (fn))
+ mark_needed (fn);
+ }
+
/* There's no reason to do any of the work here if we're only doing
semantic analysis; this code just generates RTL. */
if (flag_syntax_only)
return;
- /* Compute the appropriate object-file linkage for inline functions. */
- if (DECL_DECLARED_INLINE_P (fn))
- import_export_decl (fn);
-
function_depth++;
/* Expand or defer, at the whim of the compilation unit manager. */
/* Change all returns to just refer to the RESULT_DECL; this is a nop,
but differs from using NULL_TREE in that it indicates that we care
about the value of the RESULT_DECL. */
- else if (TREE_CODE (*tp) == RETURN_STMT)
- RETURN_STMT_EXPR (*tp) = dp->result;
+ else if (TREE_CODE (*tp) == RETURN_EXPR)
+ TREE_OPERAND (*tp, 0) = dp->result;
/* Change all cleanups for the NRV to only run when an exception is
thrown. */
else if (TREE_CODE (*tp) == CLEANUP_STMT
&& CLEANUP_DECL (*tp) == dp->var)
CLEANUP_EH_ONLY (*tp) = 1;
- /* Replace the DECL_STMT for the NRV with an initialization of the
+ /* Replace the DECL_EXPR for the NRV with an initialization of the
RESULT_DECL, if needed. */
- else if (TREE_CODE (*tp) == DECL_STMT
- && DECL_STMT_DECL (*tp) == dp->var)
+ else if (TREE_CODE (*tp) == DECL_EXPR
+ && DECL_EXPR_DECL (*tp) == dp->var)
{
tree init;
if (DECL_INITIAL (dp->var)
&& DECL_INITIAL (dp->var) != error_mark_node)
{
- init = build (INIT_EXPR, void_type_node, dp->result,
- DECL_INITIAL (dp->var));
+ init = build2 (INIT_EXPR, void_type_node, dp->result,
+ DECL_INITIAL (dp->var));
DECL_INITIAL (dp->var) = error_mark_node;
}
else
- init = NULL_TREE;
- init = build_stmt (EXPR_STMT, init);
+ init = build_empty_stmt ();
SET_EXPR_LOCUS (init, EXPR_LOCUS (*tp));
- TREE_CHAIN (init) = TREE_CHAIN (*tp);
*tp = init;
}
/* And replace all uses of the NRV with the RESULT_DECL. */
}
/* Called from finish_function to implement the named return value
- optimization by overriding all the RETURN_STMTs and pertinent
+ optimization by overriding all the RETURN_EXPRs and pertinent
CLEANUP_STMTs and replacing all occurrences of VAR with RESULT, the
RESULT_DECL for the function. */
/* Copy debugging information from VAR to RESULT. */
DECL_NAME (result) = DECL_NAME (var);
+ DECL_ARTIFICIAL (result) = DECL_ARTIFICIAL (var);
+ DECL_IGNORED_P (result) = DECL_IGNORED_P (var);
DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (var);
DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (var);
/* Don't forget that we take its address. */