building RTL. These routines are used both during actual parsing
and during the instantiation of template functions.
- Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Written by Mark Mitchell (mmitchell@usa.net) based on code found
formerly in parse.y and pt.c.
#include "system.h"
#include "tree.h"
#include "cp-tree.h"
+#include "tree-inline.h"
#include "except.h"
#include "lex.h"
#include "toplev.h"
#include "expr.h"
#include "output.h"
#include "timevar.h"
+#include "debug.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
static tree maybe_convert_cond PARAMS ((tree));
static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
-static tree nullify_returns_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_ctor_stmt PARAMS ((tree));
-static void genrtl_subobject PARAMS ((tree));
static void genrtl_named_return_value PARAMS ((void));
static void cp_expand_stmt PARAMS ((tree));
static void genrtl_start_function PARAMS ((tree));
/* Finish processing the COND, the SUBSTMT condition for STMT. */
-#define FINISH_COND(cond, stmt, substmt) \
+#define FINISH_COND(COND, STMT, SUBSTMT) \
do { \
- if (last_tree != stmt) \
+ if (last_tree != (STMT)) \
{ \
- RECHAIN_STMTS (stmt, substmt); \
- if (!processing_template_decl) \
- { \
- cond = build_tree_list (substmt, cond); \
- substmt = cond; \
- } \
+ RECHAIN_STMTS (STMT, SUBSTMT); \
+ if (!processing_template_decl) \
+ { \
+ (COND) = build_tree_list (SUBSTMT, COND); \
+ (SUBSTMT) = (COND); \
+ } \
} \
else \
- substmt = cond; \
+ (SUBSTMT) = (COND); \
} while (0)
/* Returns non-zero if the current statement is a full expression,
current_stmt_tree ()
{
return (cfun
- ? &cfun->language->x_stmt_tree
+ ? &cfun->language->base.x_stmt_tree
: &scope_chain->x_stmt_tree);
}
anon_aggr_type_p (node)
tree node;
{
- return (CLASS_TYPE_P (node) && TYPE_LANG_SPECIFIC(node)->anon_aggr);
+ return ANON_AGGR_TYPE_P (node);
}
/* Finish a scope. */
tree expr;
{
tree r = NULL_TREE;
+ tree expr_type = NULL_TREE;;
if (expr != NULL_TREE)
{
|| 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 ())
expr = convert_to_void (expr, "statement");
/* This was an expression-statement, so we save the type of the
expression. */
- last_expr_type = expr ? TREE_TYPE (expr) : NULL_TREE;
+ last_expr_type = expr_type;
return r;
}
tree if_stmt;
{
RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
- last_tree = if_stmt;
return if_stmt;
}
void
finish_if_stmt ()
{
- do_poplevel ();
finish_stmt ();
-}
-
-void
-clear_out_block ()
-{
- /* If COND wasn't a declaration, clear out the
- block we made for it and start a new one here so the
- optimization in expand_end_loop will work. */
- if (getdecls () == NULL_TREE)
- {
- do_poplevel ();
- do_pushlevel ();
- }
+ do_poplevel ();
}
/* Begin a while-statement. Returns a newly created WHILE_STMT if
tree while_stmt;
{
cond = maybe_convert_cond (cond);
- FINISH_COND (cond, while_stmt, WHILE_COND (while_stmt));
- clear_out_block ();
+ if (getdecls () == NULL_TREE)
+ /* It was a simple condition; install it. */
+ WHILE_COND (while_stmt) = cond;
+ else
+ {
+ /* If there was a declaration in the condition, we can't leave it
+ there; transform
+ while (A x = 42) { }
+ to
+ while (true) { A x = 42; if (!x) break; } */
+ tree if_stmt;
+ WHILE_COND (while_stmt) = 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 ();
+ }
}
/* Finish a while-statement, which may be given by WHILE_STMT. */
expr = check_return_expr (expr);
if (!processing_template_decl)
{
- if (DECL_CONSTRUCTOR_P (current_function_decl) && ctor_label)
- {
- /* Even returns without a value in a constructor must return
- `this'. We accomplish this by sending all returns in a
- constructor to the CTOR_LABEL; finish_function emits code to
- return a value there. When we finally generate the real
- return statement, CTOR_LABEL is no longer set, and we fall
- through into the normal return-processing code below. */
- return finish_goto_stmt (ctor_label);
- }
- else if (DECL_DESTRUCTOR_P (current_function_decl))
+ if (DECL_DESTRUCTOR_P (current_function_decl))
{
/* Similarly, all destructors must run destructors for
base-classes before returning. So, all returns in a
r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
NULL_TREE, NULL_TREE);
NEW_FOR_SCOPE_P (r) = flag_new_for_scope > 0;
- add_stmt (r);
if (NEW_FOR_SCOPE_P (r))
{
do_pushlevel ();
note_level_for_for ();
}
+ add_stmt (r);
return r;
}
tree for_stmt;
{
cond = maybe_convert_cond (cond);
- FINISH_COND (cond, for_stmt, FOR_COND (for_stmt));
- clear_out_block ();
+ if (getdecls () == NULL_TREE)
+ /* It was a simple condition; install it. */
+ FOR_COND (for_stmt) = cond;
+ else
+ {
+ /* If there was a declaration in the condition, we can't leave it
+ there; transform
+ for (; A x = 42;) { }
+ to
+ for (;;) { A x = 42; if (!x) break; } */
+ tree if_stmt;
+ FOR_COND (for_stmt) = NULL_TREE;
+
+ 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 ();
+ }
}
/* Finish the increment-EXPRESSION in a for-statement, which may be
begin_switch_stmt ()
{
tree r;
- r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE);
- add_stmt (r);
do_pushlevel ();
+ r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
+ add_stmt (r);
return r;
}
tree cond;
tree switch_stmt;
{
+ tree orig_type = NULL;
if (!processing_template_decl)
{
- tree type;
tree index;
/* Convert the condition to an integer or enumeration type. */
error ("switch quantity not an integer");
cond = error_mark_node;
}
+ orig_type = TREE_TYPE (cond);
if (cond != error_mark_node)
{
cond = default_conversion (cond);
cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond));
}
- type = TREE_TYPE (cond);
- index = get_unwidened (cond, NULL_TREE);
- /* We can't strip a conversion from a signed type to an unsigned,
- because if we did, int_fits_type_p would do the wrong thing
- when checking case values for being in range,
- and it's too hard to do the right thing. */
- if (TREE_UNSIGNED (TREE_TYPE (cond))
- == TREE_UNSIGNED (TREE_TYPE (index)))
- cond = index;
+ if (cond != error_mark_node)
+ {
+ index = get_unwidened (cond, NULL_TREE);
+ /* We can't strip a conversion from a signed type to an unsigned,
+ because if we did, int_fits_type_p would do the wrong thing
+ when checking case values for being in range,
+ and it's too hard to do the right thing. */
+ if (TREE_UNSIGNED (TREE_TYPE (cond))
+ == TREE_UNSIGNED (TREE_TYPE (index)))
+ cond = index;
+ }
}
FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt));
+ SWITCH_TYPE (switch_stmt) = orig_type;
push_switch (switch_stmt);
}
{
RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt));
pop_switch ();
- do_poplevel ();
finish_stmt ();
+ do_poplevel ();
}
/* Generate the RTL for T, which is a TRY_BLOCK. */
if (FN_TRY_BLOCK_P (t))
{
- end_protect_partials ();
expand_start_all_catch ();
in_function_try_handler = 1;
expand_stmt (TRY_HANDLERS (t));
void
finish_function_try_block (try_block)
- tree try_block;
+ tree try_block;
{
if (TREE_CHAIN (try_block)
&& TREE_CODE (TREE_CHAIN (try_block)) == CTOR_INITIALIZER)
RECHAIN_STMTS (handler, HANDLER_BODY (handler));
}
-/* Generate the RTL for T, which is a CTOR_STMT. */
-
-static void
-genrtl_ctor_stmt (t)
- tree t;
-{
- if (CTOR_BEGIN_P (t))
- begin_protect_partials ();
- else
- /* After this point, any exceptions will cause the
- destructor to be executed, so we no longer need to worry
- about destroying the various subobjects ourselves. */
- end_protect_partials ();
-}
-
/* Begin a compound-statement. If HAS_NO_SCOPE is non-zero, the
compound-statement does not define a scope. Returns a new
COMPOUND_STMT if appropriate. */
tree r;
tree t;
- if (TREE_CHAIN (string))
- string = combine_strings (string);
-
if (cv_qualifier != NULL_TREE
&& cv_qualifier != ridpointers[(int) RID_VOLATILE])
{
- cp_warning ("%s qualifier ignored on asm",
+ warning ("%s qualifier ignored on asm",
IDENTIFIER_POINTER (cv_qualifier));
cv_qualifier = NULL_TREE;
}
if (!processing_template_decl)
- for (t = input_operands; t; t = TREE_CHAIN (t))
- {
- tree converted_operand
- = decay_conversion (TREE_VALUE (t));
-
- /* If the type of the operand hasn't been determined (e.g.,
- because it involves an overloaded function), then issue an
- error message. There's no context available to resolve the
- overloading. */
- if (TREE_TYPE (converted_operand) == unknown_type_node)
- {
- cp_error ("type of asm operand `%E' could not be determined",
- TREE_VALUE (t));
- converted_operand = error_mark_node;
- }
- TREE_VALUE (t) = converted_operand;
- }
+ {
+ int i;
+ int ninputs;
+ int noutputs;
+
+ for (t = input_operands; t; t = TREE_CHAIN (t))
+ {
+ tree converted_operand
+ = decay_conversion (TREE_VALUE (t));
+
+ /* If the type of the operand hasn't been determined (e.g.,
+ because it involves an overloaded function), then issue
+ an error message. There's no context available to
+ resolve the overloading. */
+ if (TREE_TYPE (converted_operand) == unknown_type_node)
+ {
+ error ("type of asm operand `%E' could not be determined",
+ TREE_VALUE (t));
+ converted_operand = error_mark_node;
+ }
+ TREE_VALUE (t) = converted_operand;
+ }
+
+ ninputs = list_length (input_operands);
+ noutputs = list_length (output_operands);
+
+ for (i = 0, t = output_operands; t; t = TREE_CHAIN (t), ++i)
+ {
+ bool allows_mem;
+ bool allows_reg;
+ bool is_inout;
+ const char *constraint;
+ tree operand;
+
+ constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+ operand = TREE_VALUE (output_operands);
+
+ if (!parse_output_constraint (&constraint,
+ i, ninputs, noutputs,
+ &allows_mem,
+ &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;
+ continue;
+ }
+
+ /* If the operand is a DECL that is going to end up in
+ memory, assume it is addressable. This is a bit more
+ conservative than it would ideally be; the exact test is
+ buried deep in expand_asm_operands and depends on the
+ DECL_RTL for the OPERAND -- which we don't have at this
+ point. */
+ if (!allows_reg && DECL_P (operand))
+ cxx_mark_addressable (operand);
+ }
+ }
r = build_stmt (ASM_STMT, cv_qualifier, string,
output_operands, input_operands,
add_decl_stmt (decl);
}
-/* Generate the RTL for a SUBOBJECT. */
-
-static void
-genrtl_subobject (cleanup)
- tree cleanup;
-{
- add_partial_entry (cleanup);
-}
-
-/* We're in a constructor, and have just constructed a a subobject of
- *THIS. CLEANUP is code to run if an exception is thrown before the
- end of the current function is reached. */
+/* When DECL goes out of scope, make sure that CLEANUP is executed. */
void
-finish_subobject (cleanup)
+finish_decl_cleanup (decl, cleanup)
+ tree decl;
tree cleanup;
{
- tree r = build_stmt (SUBOBJECT, cleanup);
- add_stmt (r);
+ add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
}
-/* When DECL goes out of scope, make sure that CLEANUP is executed. */
+/* If the current scope exits with an exception, run CLEANUP. */
-void
-finish_decl_cleanup (decl, cleanup)
- tree decl;
+void
+finish_eh_cleanup (cleanup)
tree cleanup;
{
- add_stmt (build_stmt (CLEANUP_STMT, decl, 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. */
DECL_NAME (decl) = return_id;
else
{
- cp_error ("return identifier `%D' already in place", return_id);
+ error ("return identifier `%D' already in place", return_id);
return;
}
}
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 INIT_LIST is a list of mem-initializers, in the order they were
written by the user. The TREE_VALUE of each node is a list of
initializers for a particular subobject. The TREE_PURPOSE is a
/* We're running through the initializers from right to left
as we process them here. So, if we see a data member
initializer after we see a base initializer, that
- actually means that the base initializer preceeded the
+ actually means that the base initializer preceded the
data member initializer. */
if (warn_reorder && last_base_warned_about != base_init_list)
{
base != last_base_warned_about;
base = TREE_CHAIN (base))
{
- cp_warning ("base initializer for `%T'",
+ warning ("base initializer for `%T'",
TREE_PURPOSE (base));
warning (" will be re-ordered to precede member initializations");
}
}
}
- setup_vtbl_ptr (member_init_list, base_init_list);
-}
-
-/* Cache the value of this class's main virtual function table pointer
- in a register variable. This will save one indirection if a
- more than one virtual function call is made this function. */
-
-void
-setup_vtbl_ptr (member_init_list, base_init_list)
- tree member_init_list;
- tree base_init_list;
-{
- my_friendly_assert (doing_semantic_analysis_p (), 19990919);
-
- /* If we've already done this, there's no need to do it again. */
- if (vtbls_set_up_p)
- return;
-
- if (DECL_CONSTRUCTOR_P (current_function_decl))
- {
- if (processing_template_decl)
- add_stmt (build_min_nt
- (CTOR_INITIALIZER,
- member_init_list, base_init_list));
- else
- {
- tree ctor_stmt;
-
- /* Mark the beginning of the constructor. */
- ctor_stmt = build_stmt (CTOR_STMT);
- CTOR_BEGIN_P (ctor_stmt) = 1;
- add_stmt (ctor_stmt);
-
- /* And actually initialize the base-classes and members. */
- emit_base_init (member_init_list, base_init_list);
- }
- }
- else if (DECL_DESTRUCTOR_P (current_function_decl)
- && !processing_template_decl)
- {
- tree if_stmt;
- tree compound_stmt;
-
- /* If the dtor is empty, and we know there is not any possible
- way we could use any vtable entries, before they are possibly
- set by a base class dtor, we don't have to setup the vtables,
- as we know that any base class dtor will set up any vtables
- it needs. We avoid MI, because one base class dtor can do a
- virtual dispatch to an overridden function that would need to
- have a non-related vtable set up, we cannot avoid setting up
- vtables in that case. We could change this to see if there
- is just one vtable. */
- if_stmt = begin_if_stmt ();
-
- /* If it is not safe to avoid setting up the vtables, then
- someone will change the condition to be boolean_true_node.
- (Actually, for now, we do not have code to set the condition
- appropriately, so we just assume that we always need to
- initialize the vtables.) */
- finish_if_stmt_cond (boolean_true_node, if_stmt);
- current_vcalls_possible_p = &IF_COND (if_stmt);
-
- compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
-
- /* Make all virtual function table pointers in non-virtual base
- classes point to CURRENT_CLASS_TYPE's virtual function
- tables. */
- initialize_vtbl_ptrs (current_class_ptr);
-
- finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
- finish_then_clause (if_stmt);
- finish_if_stmt ();
- }
-
- /* Always keep the BLOCK node associated with the outermost pair of
- curly braces of a function. These are needed for correct
- operation of dwarfout.c. */
- keep_next_level (1);
-
- /* The virtual function tables are set up now. */
- vtbls_set_up_p = 1;
+ if (processing_template_decl)
+ add_stmt (build_min_nt (CTOR_INITIALIZER,
+ member_init_list, base_init_list));
+ else
+ emit_base_init (member_init_list, base_init_list);
}
/* Returns the stack of SCOPE_STMTs for the current function. */
tree *
current_scope_stmt_stack ()
{
- return &cfun->language->x_scope_stmt_stack;
+ return &cfun->language->base.x_scope_stmt_stack;
}
/* Finish a parenthesized expression EXPR. */
tree expr;
{
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expr))))
- /* This inhibits warnings in truthvalue_conversion. */
+ /* This inhibits warnings in c_common_truthvalue_conversion. */
C_SET_EXP_ORIGINAL_CODE (expr, ERROR_MARK);
if (TREE_CODE (expr) == OFFSET_REF)
keep_next_level (1);
- return (last_tree != NULL_TREE) ? last_tree : expand_start_stmt_expr();
+ return last_tree ? last_tree : expand_start_stmt_expr(/*has_scope=*/1);
}
/* Finish the STMT_EXPR last begun with begin_global_stmt_expr. */
return result;
}
-/* Finish a call to FN with ARGS. Returns a representation of the
- call. */
+/* Generate an expression for `FN (ARGS)'.
+
+ If DISALLOW_VIRTUAL is true, the call to FN will be not generated
+ as a virtual call, even if FN is virtual. (This flag is set when
+ encountering an expression where the function name is explicitly
+ qualified. For example a call to `X::f' never generates a virtual
+ call.)
+
+ Returns code for the call. */
tree
-finish_call_expr (fn, args, koenig)
- tree fn;
- tree args;
- int koenig;
+finish_call_expr (tree fn, tree args, bool disallow_virtual)
{
- tree result;
+ 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);
- if (koenig)
+ /* ARGS should be a list of arguments. */
+ my_friendly_assert (!args || TREE_CODE (args) == TREE_LIST,
+ 20020712);
+
+ if (BASELINK_P (fn))
{
- if (TREE_CODE (fn) == BIT_NOT_EXPR)
- fn = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND (fn, 0));
- else if (TREE_CODE (fn) != TEMPLATE_ID_EXPR)
- fn = do_identifier (fn, 2, args);
- }
- result = build_x_function_call (fn, args, current_class_ref);
+ tree object;
+
+ /* A call to a member function. From [over.call.func]:
+
+ If the keyword this is in scope and refers to the class of
+ that member function, or a derived class thereof, then the
+ function call is transformed into a qualified function call
+ using (*this) as the postfix-expression to the left of the
+ . operator.... [Otherwise] a contrived object of type T
+ becomes the implied object argument.
+
+ This paragraph is unclear about this situation:
+
+ struct A { void f(); };
+ struct B : public A {};
+ struct C : public A { void g() { B::f(); }};
+
+ In particular, for `B::f', this paragraph does not make clear
+ whether "the class of that member function" refers to `A' or
+ to `B'. We believe it refers to `B'. */
+ if (current_class_type
+ && DERIVED_FROM_P (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)),
+ current_class_type)
+ && current_class_ref)
+ object = current_class_ref;
+ else
+ {
+ tree representative_fn;
- if (TREE_CODE (result) == CALL_EXPR
- && (! TREE_TYPE (result)
- || TREE_CODE (TREE_TYPE (result)) != VOID_TYPE))
- result = require_complete_type (result);
+ representative_fn = BASELINK_FUNCTIONS (fn);
+ if (TREE_CODE (representative_fn) == TEMPLATE_ID_EXPR)
+ representative_fn = TREE_OPERAND (representative_fn, 0);
+ representative_fn = get_first_fn (representative_fn);
+ object = build_dummy_object (DECL_CONTEXT (representative_fn));
+ }
- return result;
+ return 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)))
+ {
+ /* 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;
+ }
+
+ /* A call where the function is unknown. */
+ return build_function_call (fn, args);
}
/* Finish a call to a postfix increment or decrement or EXPR. (Which
if (current_class_ptr)
{
-#ifdef WARNING_ABOUT_CCD
- TREE_USED (current_class_ptr) = 1;
-#endif
result = current_class_ptr;
}
else if (current_function_decl
tree object;
tree args;
{
-#if 0
- /* This is a future direction of this code, but because
- build_x_function_call cannot always undo what is done in
- build_component_ref entirely yet, we cannot do this. */
-
- tree real_fn = build_component_ref (object, fn, NULL_TREE, 1);
- return finish_call_expr (real_fn, args);
-#else
if (DECL_DECLARES_TYPE_P (fn))
{
if (processing_template_decl)
fn = DECL_NAME (fn);
else
{
- cp_error ("calling type `%T' like a method", fn);
+ error ("calling type `%T' like a method", fn);
return error_mark_node;
}
}
-
- return build_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
-#endif
+
+ if (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
return build_min_nt (PSEUDO_DTOR_EXPR, object, scope, destructor);
if (scope && scope != destructor)
- cp_error ("destructor specifier `%T::~%T()' must have matching names",
+ error ("destructor specifier `%T::~%T()' must have matching names",
scope, destructor);
if ((scope == NULL_TREE || IDENTIFIER_GLOBAL_VALUE (destructor))
&& (TREE_CODE (TREE_TYPE (object)) !=
TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (destructor)))))
- cp_error ("`%E' is not of type `%T'", object, destructor);
+ error ("`%E' is not of type `%T'", object, destructor);
return cp_convert (void_type_node, object);
}
-/* Finish a call to a globally qualified member function FN using
- ARGS. Returns an expression for the call. */
-
-tree
-finish_qualified_call_expr (fn, args)
- tree fn;
- tree args;
-{
- if (processing_template_decl)
- return build_min_nt (CALL_EXPR, fn, args, NULL_TREE);
- else
- return build_member_call (TREE_OPERAND (fn, 0),
- TREE_OPERAND (fn, 1),
- args);
-}
-
/* Finish an expression of the form CODE EXPR. */
tree
return expr;
}
+/* Return the declaration for the function-name variable indicated by
+ ID. */
+
+tree
+finish_fname (tree id)
+{
+ tree decl;
+
+ decl = fname_decl (C_RID_CODE (id), id);
+ if (processing_template_decl)
+ decl = build_min_nt (LOOKUP_EXPR, DECL_NAME (decl));
+ return decl;
+}
+
static tree current_type_lookups;
/* Perform deferred access control for types used in the type of a
added to type_lookups after typed_declspecs saved the copy that
ended up in current_type_lookups. */
type_lookups = current_type_lookups;
-
- current_type_lookups = NULL_TREE;
}
-/* Record the lookups, if we're doing deferred access control. */
-
void
save_type_access_control (lookups)
tree lookups;
{
- if (type_lookups != error_mark_node)
- {
- my_friendly_assert (!current_type_lookups, 20010301);
- current_type_lookups = lookups;
- }
- else
- my_friendly_assert (!lookups || lookups == error_mark_node, 20010301);
-}
-
-/* Set things up so that the next deferred access control will succeed.
- This is needed for friend declarations see grokdeclarator for details. */
-
-void
-skip_type_access_control ()
-{
- type_lookups = NULL_TREE;
+ current_type_lookups = lookups;
}
/* Reset the deferred access control. */
current_type_lookups = NULL_TREE;
}
-/* Begin a function definition declared with DECL_SPECS and
- DECLARATOR. Returns non-zero if the function-declaration is
- legal. */
+/* Begin a function definition declared with DECL_SPECS, ATTRIBUTES,
+ and DECLARATOR. Returns non-zero if the function-declaration is
+ valid. */
int
-begin_function_definition (decl_specs, declarator)
+begin_function_definition (decl_specs, attributes, declarator)
tree decl_specs;
+ tree attributes;
tree declarator;
{
- tree specs;
- tree attrs;
-
- split_specs_attrs (decl_specs, &specs, &attrs);
- if (!start_function (specs, declarator, attrs, SF_DEFAULT))
+ if (!start_function (decl_specs, declarator, attributes, SF_DEFAULT))
return 0;
deferred_type_access_control ();
return finish_template_type_parm (aggr, tmpl);
}
+/* ARGUMENT is the default-argument value for a template template
+ parameter. If ARGUMENT is invalid, issue error messages and return
+ the ERROR_MARK_NODE. Otherwise, ARGUMENT itself is returned. */
+
+tree
+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");
+ return error_mark_node;
+ }
+
+ return argument;
+}
+
/* Finish a parameter list, indicated by PARMS. If ELLIPSIS is
non-zero, the parameter list was terminated by a `...'. */
begin_class_definition (t)
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)
{
- cp_error ("definition of `%#T' inside template parameter list", t);
+ error ("definition of `%#T' inside template parameter list", t);
return error_mark_node;
}
This is erroneous. */
else if (TREE_CODE (t) == TYPENAME_TYPE)
{
- cp_error ("invalid definition of qualified type `%T'", t);
+ error ("invalid definition of qualified type `%T'", t);
t = error_mark_node;
}
struct S { enum E { }; int E } s;
s.E = 3;
- is legal. In addition, the FIELD_DECLs must be maintained in
+ is valid. In addition, the FIELD_DECLs must be maintained in
declaration order so that class layout works as expected.
However, we don't need that order until class layout, so we
save a little time by putting FIELD_DECLs on in reverse order
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)
/* If we got any attributes in class_head, xref_tag will stick them in
TREE_TYPE of the type. Grab them now. */
- attributes = chainon (TREE_TYPE (t), attributes);
- TREE_TYPE (t) = NULL_TREE;
+ attributes = chainon (TYPE_ATTRIBUTES (t), attributes);
+ TYPE_ATTRIBUTES (t) = NULL_TREE;
if (TREE_CODE (t) == ENUMERAL_TYPE)
;
check_for_missing_semicolon (t);
if (pop_scope_p)
pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (t)));
- if (current_function_decl)
- type_lookups = error_mark_node;
if (current_scope () == current_function_decl)
do_pending_defargs ();
do_pending_inlines ();
}
-/* Finish processing the inline function definitions cached during the
- processing of a class definition. */
-
-void
-finish_inline_definitions ()
-{
- if (current_class_type == NULL_TREE)
- clear_inline_text_obstack ();
-}
-
/* Finish processing the declaration of a member class template
TYPES whose template parameters are given by PARMS. */
return NULL_TREE;
}
-/* Finish processsing a complete template declaration. The PARMS are
+/* Finish processing a complete template declaration. The PARMS are
the template parameters. */
void
/* Finish processing a BASE_CLASS with the indicated ACCESS_SPECIFIER.
Return a TREE_LIST containing the ACCESS_SPECIFIER and the
BASE_CLASS, or NULL_TREE if an error occurred. The
- ACCESSS_SPECIFIER is one of
+ ACCESS_SPECIFIER is one of
access_{default,public,protected_private}[_virtual]_node.*/
tree
{
tree result;
- if (! is_aggr_type (base_class, 1))
+ if (base_class == error_mark_node)
+ {
+ error ("invalid base-class specification");
+ result = NULL_TREE;
+ }
+ else if (! is_aggr_type (base_class, 1))
result = NULL_TREE;
else
{
- if (CP_TYPE_QUALS (base_class) != 0)
+ if (cp_type_quals (base_class) != 0)
{
- cp_error ("base class `%T' has cv qualifiers", base_class);
+ error ("base class `%T' has cv qualifiers", base_class);
base_class = TYPE_MAIN_VARIANT (base_class);
}
result = build_tree_list (access_specifier, base_class);
contain at most one declarator.
We don't just use PROCESSING_TEMPLATE_DECL for the first
- condition since that would disallow the perfectly legal code,
+ condition since that would disallow the perfectly valid code,
like `template <class T> struct S { int i, j; };'. */
- tree scope = current_scope ();
-
- if (scope && TREE_CODE (scope) == FUNCTION_DECL)
+ if (at_function_scope_p ())
/* It's OK to write `template <class T> void f() { int i, j;}'. */
return;
if (PROCESSING_REAL_TEMPLATE_DECL_P ()
|| processing_explicit_instantiation
|| processing_specialization)
- cp_error ("multiple declarators in template declaration");
+ error ("multiple declarators in template declaration");
}
+/* Implement the __typeof keyword: Return the type of EXPR, suitable for
+ use as a type-specifier. */
+
tree
finish_typeof (expr)
tree expr;
return TREE_TYPE (expr);
}
+/* 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. */
{
switch (TREE_CODE (t))
{
- case CLEANUP_STMT:
- /* Don't destroy the chosen named return value. */
- if (CLEANUP_DECL (t) != current_function_return_value)
- genrtl_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
- break;
-
- case CTOR_STMT:
- genrtl_ctor_stmt (t);
- break;
-
case TRY_BLOCK:
genrtl_try_block (t);
break;
genrtl_handler (t);
break;
- case SUBOBJECT:
- genrtl_subobject (SUBOBJECT_CLEANUP (t));
- break;
-
case RETURN_INIT:
genrtl_named_return_value ();
break;
break;
default:
- my_friendly_abort (19990810);
+ abort ();
break;
}
}
{
/* Replace the first argument with the address of the third
argument to the AGGR_INIT_EXPR. */
- mark_addressable (slot);
+ cxx_mark_addressable (slot);
args = tree_cons (NULL_TREE,
build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (slot)),
int old_ac = flag_access_control;
flag_access_control = 0;
- call_expr = build_aggr_init (slot, call_expr, LOOKUP_ONLYCONVERTING);
+ call_expr = build_aggr_init (slot, call_expr,
+ DIRECT_BIND | LOOKUP_ONLYCONVERTING);
flag_access_control = old_ac;
copy_from_buffer_p = 1;
}
is so that you can know statically the entire set of thunks that
will ever be needed for a given virtual function, thereby
enabling you to output all the thunks with the function itself. */
- if (vcall_offsets_in_vtable_p () && DECL_VIRTUAL_P (fn))
+ if (DECL_VIRTUAL_P (fn))
{
tree binfo;
tree v;
{
int saved_lineno;
const char *saved_input_filename;
+ tree saved_function;
/* 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
simplify_aggr_init_exprs_r,
NULL);
- /* If this is a constructor or destructor body, we have to clone it
- under the new ABI. */
+ /* If this is a constructor or destructor body, we have to clone
+ it. */
if (maybe_clone_body (fn))
{
/* We don't want to process FN again, so pretend we've written
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 keep all inline functions anyhow. */
+ /* 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)
- /* Or if this is a nested function. */
- && !decl_function_context (fn))
+ && !DECL_NEEDED_P (fn))
{
/* Set DECL_EXTERNAL so that assemble_external will be called as
necessary. We'll clear it again in finish_file. */
/* 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 funtion exists. */
- note_deferral_of_defined_inline_function (fn);
+ /* Let the back-end know that this function exists. */
+ (*debug_hooks->deferred_inline_function) (fn);
return;
}
if (DECL_DECLARED_INLINE_P (fn))
import_export_decl (fn);
- /* Emit any thunks that should be emitted at the same time as FN. */
- emit_associated_thunks (fn);
-
- timevar_push (TV_INTEGRATION);
-
- /* Optimize the body of the function before expanding it. */
- optimize_function (fn);
-
- timevar_pop (TV_INTEGRATION);
- timevar_push (TV_EXPAND);
+ /* 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;
+
+ timevar_push (TV_INTEGRATION);
+
+ /* Optimize the body of the function before expanding it. */
+ optimize_function (fn);
+
+ timevar_pop (TV_INTEGRATION);
+ timevar_push (TV_EXPAND);
genrtl_start_function (fn);
current_function_is_thunk = DECL_THUNK_P (fn);
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);
}
-/* Helper function for walk_tree, used by genrtl_start_function to override
- all the RETURN_STMTs for the named return value optimization. */
+/* Helper function for walk_tree, used by finish_function to override all
+ the RETURN_STMTs and pertinent CLEANUP_STMTs for the named return
+ value optimization. */
-static tree
+tree
nullify_returns_r (tp, walk_subtrees, data)
tree *tp;
int *walk_subtrees;
- void *data ATTRIBUTE_UNUSED;
+ void *data;
{
- /* No need to walk into types. */
+ tree nrv = (tree) data;
+
+ /* No need to walk into types. There wouldn't be any need to walk into
+ non-statements, except that we have to consider STMT_EXPRs. */
if (TYPE_P (*tp))
*walk_subtrees = 0;
else if (TREE_CODE (*tp) == RETURN_STMT)
- RETURN_NULLIFIED_P (*tp) = 1;
+ RETURN_STMT_EXPR (*tp) = NULL_TREE;
+ else if (TREE_CODE (*tp) == CLEANUP_STMT
+ && CLEANUP_DECL (*tp) == nrv)
+ CLEANUP_EH_ONLY (*tp) = 1;
/* Keep iterating. */
return NULL_TREE;
genrtl_start_function (fn)
tree fn;
{
- tree parm;
-
/* Tell everybody what function we're processing. */
current_function_decl = fn;
/* Get the RTL machinery going for this function. */
if (!current_function_cannot_inline)
current_function_cannot_inline = cp_function_chain->cannot_inline;
- /* We don't need the saved data anymore. */
- free (DECL_SAVED_FUNCTION_DATA (fn));
- DECL_SAVED_FUNCTION_DATA (fn) = NULL;
+ /* 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;
}
- /* Tell the cross-reference machinery that we're defining this
- function. */
- GNU_xref_function (fn, DECL_ARGUMENTS (fn));
-
/* Keep track of how many functions we're presently expanding. */
++function_depth;
/* Create a binding level for the parameters. */
- expand_start_bindings (2);
- /* Clear out any previously saved instructions for this function, in
- case it was defined more than once. */
- DECL_SAVED_INSNS (fn) = NULL;
- /* Go through the PARM_DECLs for this function to see if any need
- cleanups. */
- for (parm = DECL_ARGUMENTS (fn); parm; parm = TREE_CHAIN (parm))
- if (TREE_TYPE (parm) != error_mark_node
- && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (parm)))
- {
- expand_function_start (fn, /*parms_have_cleanups=*/1);
- break;
- }
- if (!parm)
- expand_function_start (fn, /*parms_have_cleanups=*/0);
+ expand_function_start (fn, /*parms_have_cleanups=*/0);
/* If this function is `main'. */
if (DECL_MAIN_P (fn))
expand_main_function ();
- /* Create a binding contour which can be used to catch
- cleanup-generated temporaries. */
- expand_start_bindings (2);
- /* Set up the named return value optimization, if we can. */
- if (current_function_return_value
- && current_function_return_value != error_mark_node)
- {
- tree r = current_function_return_value;
- /* This is only worth doing for fns that return in memory--and
- simpler, since we don't have to worry about promoted modes. */
- if (aggregate_value_p (TREE_TYPE (TREE_TYPE (fn))))
- {
- COPY_DECL_RTL (DECL_RESULT (fn), r);
- DECL_ALIGN (r) = DECL_ALIGN (DECL_RESULT (fn));
- walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
- nullify_returns_r, NULL_TREE);
- }
- }
+ /* 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. */
genrtl_finish_function (fn)
tree fn;
{
- tree no_return_label = NULL_TREE;
+ tree t;
#if 0
if (write_symbols != NO_DEBUG)
/* Clean house because we will need to reorder insns here. */
do_pending_stack_adjust ();
- if (!dtor_label && !DECL_CONSTRUCTOR_P (fn)
- && return_label != NULL_RTX
- && ! DECL_NAME (DECL_RESULT (current_function_decl)))
- no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-
- /* If this function is supposed to return a value, ensure that
- we do not fall into the cleanups by mistake. The end of our
- function will look like this:
-
- user code (may have return stmt somewhere)
- goto no_return_label
- cleanup_label:
- cleanups
- goto return_label
- no_return_label:
- NOTE_INSN_FUNCTION_END
- return_label:
- things for return
-
- If the user omits a return stmt in the USER CODE section, we
- will have a control path which reaches NOTE_INSN_FUNCTION_END.
- Otherwise, we won't. */
- if (no_return_label)
- {
- DECL_CONTEXT (no_return_label) = fn;
- DECL_INITIAL (no_return_label) = error_mark_node;
- DECL_SOURCE_FILE (no_return_label) = input_filename;
- DECL_SOURCE_LINE (no_return_label) = lineno;
- expand_goto (no_return_label);
- }
-
- if (cleanup_label)
- {
- /* Remove the binding contour which is used to catch
- cleanup-generated temporaries. */
- expand_end_bindings (0, 0, 0);
- poplevel (0, 0, 0);
-
- /* Emit label at beginning of cleanup code for parameters. */
- emit_label (cleanup_label);
- }
-
- /* Finish building code that will trigger warnings if users forget
- to make their functions return values. */
- if (return_label)
+ /* 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);
- if (no_return_label)
- {
- /* We don't need to call `expand_*_return' here because we don't
- need any cleanups here--this path of code is only for error
- checking purposes. */
- expand_label (no_return_label);
- }
/* We hard-wired immediate_size_expand to zero in start_function.
Expand_function_end will decrement this variable. So, we set the
immediate_size_expand = 1;
/* Generate rtl for function exit. */
- expand_function_end (input_filename, lineno, 1);
+ 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
if (function_depth > 1)
ggc_pop_context ();
- if (DECL_SAVED_INSNS (fn) && ! TREE_ASM_WRITTEN (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;
- defer_fn (fn);
- }
-
#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) */
--function_depth;
- /* If 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. */
- if (!DECL_SAVED_INSNS (fn))
- {
- tree t;
-
- /* 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);
+ /* In C++, we should never be saving RTL for the function. */
+ my_friendly_assert (!DECL_SAVED_INSNS (fn), 20010903);
- /* 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;
- }
+ /* 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);
- 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;
+ /* 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