mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-02-20 01:59:40 +08:00
Remove support for assigning to `this'.
* NEWS: Note that fact. * class.c (build_vbase_path): Don't check flag_this_is_variable. * cp-tree.h (EXPR_STMT_ASSIGNS_THIS): Remove. (language_function): Remove assigns_this, just_assigned_this, and x_base_init_expr. Add x_vcalls_possible_p. Add vtbls_set_up_p. (base_init_expr): Remove. (current_vcalls_possible_p): New macro. (vtbls_set_up_p): Likewise. (emit_base_init): Change prototype. * decl.c (finish_destructor_body): New function, split out from finish_function. (current_function_assigns_this): Remove. (current_function_just_assigned_this): Likewise. (start_function): Don't set them. (finish_function): Don't check them. Don't emit base-initialization code here. Generate code for destructors when doing semantic analysis. (finish_stmt): Don't check current_function_just_assigned_this. * decl2.c (lang_f_options): Remove this-is-variable. (lang_decode_option): Likewise. (grokclassfn): Don't check flag_this_is_variable. * init.c (emit_base_init): Return the expression generated. (construct_virtual_bases): Don't push/pop obstacks. Fix typo. (build_new_1): Don't check flag_this_is_variable. (get_temp_regvar): Don't set DECL_REGISTER. (build_vec_init): Don't call use_variable. * lang-options.h: Remove "-fthis-is-variable" and "-fno-this-is-variable". * pt.c (tsubst_expr): Don't check EXPR_STMT_ASSIGNS_THIS. * search.c (expand_upcast_fixups): Use finish_expr_stmt, not expand_expr_stmt. * semantics.c (finish_expr_stmt_real): Rename to ... (finish_expr_stmt): This. Remove assigned_this parameter. (begin_if_stmt): Call do_pushlevel before starting the statement. (begin_compound_stmt): Don't declare __FUNCTION__ in scope-less blocks. (setup_vtbl_ptr): Emit initialization code for bases and members at semantic-analysis time. Emit code to initialize vtables in destructors here. (expand_stmt): Use finish_expr_stmt, not finish_expr_stmt_real. Don't handle CTOR_INITIALIZER any more. * typeck.c (build_modify_expr): Don't check for assignments to this. (c_expand_return): Don't suggest assigning to `this'. * Makefile.in (decl.o): Depend on RTL_H. (decl2.o): Likewise. (class.o): Likewise. (call.o): Likewise. (method.o): Likewise. (search.o): Likewise. (tree.o): Likewise. (pt.o): Likewise. * decl.c (duplicate_decls): When a builtin function is redeclared as static, make sure it is mangled correctly. * ir.texi (CTOR_INITIALIZER): Remove mention. Fix typo. Add detail about the statement-tree. From-SVN: r29531
This commit is contained in:
parent
2307e37238
commit
9bfadf57a2
@ -1,3 +1,67 @@
|
||||
1999-09-20 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
Remove support for assigning to `this'.
|
||||
* NEWS: Note that fact.
|
||||
* class.c (build_vbase_path): Don't check flag_this_is_variable.
|
||||
* cp-tree.h (EXPR_STMT_ASSIGNS_THIS): Remove.
|
||||
(language_function): Remove assigns_this, just_assigned_this, and
|
||||
x_base_init_expr. Add x_vcalls_possible_p. Add vtbls_set_up_p.
|
||||
(base_init_expr): Remove.
|
||||
(current_vcalls_possible_p): New macro.
|
||||
(vtbls_set_up_p): Likewise.
|
||||
(emit_base_init): Change prototype.
|
||||
* decl.c (finish_destructor_body): New function, split out from
|
||||
finish_function.
|
||||
(current_function_assigns_this): Remove.
|
||||
(current_function_just_assigned_this): Likewise.
|
||||
(start_function): Don't set them.
|
||||
(finish_function): Don't check them. Don't emit
|
||||
base-initialization code here. Generate code for destructors when
|
||||
doing semantic analysis.
|
||||
(finish_stmt): Don't check current_function_just_assigned_this.
|
||||
* decl2.c (lang_f_options): Remove this-is-variable.
|
||||
(lang_decode_option): Likewise.
|
||||
(grokclassfn): Don't check flag_this_is_variable.
|
||||
* init.c (emit_base_init): Return the expression generated.
|
||||
(construct_virtual_bases): Don't push/pop obstacks. Fix
|
||||
typo.
|
||||
(build_new_1): Don't check flag_this_is_variable.
|
||||
(get_temp_regvar): Don't set DECL_REGISTER.
|
||||
(build_vec_init): Don't call use_variable.
|
||||
* lang-options.h: Remove "-fthis-is-variable" and
|
||||
"-fno-this-is-variable".
|
||||
* pt.c (tsubst_expr): Don't check EXPR_STMT_ASSIGNS_THIS.
|
||||
* search.c (expand_upcast_fixups): Use finish_expr_stmt, not
|
||||
expand_expr_stmt.
|
||||
* semantics.c (finish_expr_stmt_real): Rename to ...
|
||||
(finish_expr_stmt): This. Remove assigned_this parameter.
|
||||
(begin_if_stmt): Call do_pushlevel before starting the statement.
|
||||
(begin_compound_stmt): Don't declare __FUNCTION__ in scope-less
|
||||
blocks.
|
||||
(setup_vtbl_ptr): Emit initialization code for bases and members
|
||||
at semantic-analysis time. Emit code to initialize vtables in
|
||||
destructors here.
|
||||
(expand_stmt): Use finish_expr_stmt, not finish_expr_stmt_real.
|
||||
Don't handle CTOR_INITIALIZER any more.
|
||||
* typeck.c (build_modify_expr): Don't check for assignments to
|
||||
this.
|
||||
(c_expand_return): Don't suggest assigning to `this'.
|
||||
|
||||
* Makefile.in (decl.o): Depend on RTL_H.
|
||||
(decl2.o): Likewise.
|
||||
(class.o): Likewise.
|
||||
(call.o): Likewise.
|
||||
(method.o): Likewise.
|
||||
(search.o): Likewise.
|
||||
(tree.o): Likewise.
|
||||
(pt.o): Likewise.
|
||||
|
||||
* decl.c (duplicate_decls): When a builtin function is redeclared
|
||||
as static, make sure it is mangled correctly.
|
||||
|
||||
* ir.texi (CTOR_INITIALIZER): Remove mention. Fix typo. Add
|
||||
detail about the statement-tree.
|
||||
|
||||
1999-09-20 Nathan Sidwell <nathan@acm.org>
|
||||
|
||||
* parse.y (primary): Use build_functional_cast for CV_QUALIFIER.
|
||||
|
@ -248,33 +248,33 @@ lex.o : lex.c $(CONFIG_H) $(CXX_TREE_H) \
|
||||
decl.o : decl.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
lex.h decl.h $(srcdir)/../stack.h $(srcdir)/../output.h \
|
||||
$(srcdir)/../except.h $(srcdir)/../system.h $(srcdir)/../toplev.h \
|
||||
$(srcdir)/../hash.h $(srcdir)/../ggc.h
|
||||
$(srcdir)/../hash.h $(srcdir)/../ggc.h $(RTL_H)
|
||||
decl2.o : decl2.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
lex.h decl.h $(EXPR_H) $(srcdir)/../except.h \
|
||||
$(srcdir)/../output.h $(srcdir)/../except.h $(srcdir)/../system.h \
|
||||
$(srcdir)/../toplev.h $(srcdir)/../dwarf2out.h $(srcdir)/../dwarfout.h \
|
||||
$(srcdir)/../../include/splay-tree.h $(srcdir)/../ggc.h
|
||||
$(srcdir)/../../include/splay-tree.h $(srcdir)/../ggc.h $(RTL_H)
|
||||
typeck2.o : typeck2.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h
|
||||
typeck.o : typeck.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
|
||||
$(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h
|
||||
class.o : class.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h \
|
||||
$(srcdir)/../../include/splay-tree.h
|
||||
$(srcdir)/../../include/splay-tree.h $(RTL_H)
|
||||
call.o : call.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h $(RTL_H)
|
||||
friend.o : friend.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h
|
||||
init.o : init.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
|
||||
$(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h
|
||||
method.o : method.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
|
||||
$(srcdir)/../toplev.h $(srcdir)/../ggc.h
|
||||
$(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H)
|
||||
cvt.o : cvt.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h decl.h \
|
||||
$(srcdir)/../flags.h $(srcdir)/../toplev.h $(srcdir)/../convert.h
|
||||
search.o : search.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../stack.h \
|
||||
$(srcdir)/../flags.h $(srcdir)/../system.h $(srcdir)/../toplev.h
|
||||
$(srcdir)/../flags.h $(srcdir)/../system.h $(srcdir)/../toplev.h $(RTL_H)
|
||||
tree.o : tree.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H)
|
||||
ptree.o : ptree.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h
|
||||
rtti.o : rtti.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h
|
||||
@ -285,7 +285,7 @@ expr.o : expr.c $(CONFIG_H) $(CXX_TREE_H) $(RTL_H) $(srcdir)/../flags.h \
|
||||
xref.o : xref.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../input.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h
|
||||
pt.o : pt.c $(CONFIG_H) $(CXX_TREE_H) decl.h $(PARSE_H) lex.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H)
|
||||
error.o : error.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
|
||||
$(srcdir)/../toplev.h
|
||||
errfn.o : errfn.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
|
||||
|
@ -1,5 +1,10 @@
|
||||
*** Changes in GCC 3.0:
|
||||
|
||||
* Support for assignment to `this' has been removed. This idiom
|
||||
was used in the very early days of C++, before users were allowed
|
||||
to overload `operator new'; it is no longer allowed by the C++
|
||||
standard.
|
||||
|
||||
* Support for signatures, a G++ extension, have been removed.
|
||||
|
||||
* Certain invalid conversions that were previously accepted will now
|
||||
|
@ -224,11 +224,6 @@ build_vbase_path (code, type, expr, path, nonnull)
|
||||
if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE)
|
||||
return build1 (NOP_EXPR, type, expr);
|
||||
|
||||
/* If -fthis-is-variable, we might have set nonnull incorrectly. We
|
||||
don't care enough to get this right, so just clear it. */
|
||||
if (flag_this_is_variable > 0)
|
||||
nonnull = 0;
|
||||
|
||||
/* We could do better if we had additional logic to convert back to the
|
||||
unconverted type (the static type of the complete object), and then
|
||||
convert back to the type we want. Until that is done, we only optimize
|
||||
|
@ -29,7 +29,6 @@ Boston, MA 02111-1307, USA. */
|
||||
/* Usage of TREE_LANG_FLAG_?:
|
||||
0: BINFO_MARKED (BINFO nodes).
|
||||
COMPOUND_STMT_NO_SCOPE (in COMPOUND_STMT).
|
||||
EXPR_STMT_ASSIGNS_THIS (in EXPR_STMT).
|
||||
NEW_EXPR_USE_GLOBAL (in NEW_EXPR).
|
||||
DELETE_EXPR_USE_GLOBAL (in DELETE_EXPR).
|
||||
LOOKUP_EXPR_GLOBAL (in LOOKUP_EXPR).
|
||||
@ -618,7 +617,6 @@ struct language_function
|
||||
tree x_dtor_label;
|
||||
tree x_base_init_list;
|
||||
tree x_member_init_list;
|
||||
tree x_base_init_expr;
|
||||
tree x_current_class_ptr;
|
||||
tree x_current_class_ref;
|
||||
tree x_last_tree;
|
||||
@ -627,14 +625,14 @@ struct language_function
|
||||
tree x_scope_stmt_stack;
|
||||
tree x_in_charge_parm;
|
||||
|
||||
tree *x_vcalls_possible_p;
|
||||
|
||||
struct rtx_def *x_last_dtor_insn;
|
||||
struct rtx_def *x_last_parm_cleanup_insn;
|
||||
struct rtx_def *x_result_rtx;
|
||||
|
||||
int returns_value;
|
||||
int returns_null;
|
||||
int assigns_this;
|
||||
int just_assigned_this;
|
||||
int parms_stored;
|
||||
int temp_name_counter;
|
||||
int static_labelno;
|
||||
@ -642,6 +640,7 @@ struct language_function
|
||||
int x_expanding_p;
|
||||
int stmts_are_full_exprs_p;
|
||||
int name_declared;
|
||||
int vtbls_set_up_p;
|
||||
|
||||
struct named_label_list *x_named_label_uses;
|
||||
struct binding_level *bindings;
|
||||
@ -674,10 +673,6 @@ struct language_function
|
||||
#define current_base_init_list cp_function_chain->x_base_init_list
|
||||
#define current_member_init_list cp_function_chain->x_member_init_list
|
||||
|
||||
/* Sequence of insns which represents base initialization. */
|
||||
|
||||
#define base_init_expr cp_function_chain->x_base_init_expr
|
||||
|
||||
/* When we're processing a member function, current_class_ptr is the
|
||||
PARM_DECL for the `this' pointer. The current_class_ref is an
|
||||
expression for `*this'. */
|
||||
@ -712,6 +707,12 @@ struct language_function
|
||||
|
||||
#define current_in_charge_parm cp_function_chain->x_in_charge_parm
|
||||
|
||||
/* In destructors, this is a pointer to a condition in an
|
||||
if-statement. If the pointed-to value is boolean_true_node, then
|
||||
there may be virtual function calls in this destructor. */
|
||||
|
||||
#define current_vcalls_possible_p cp_function_chain->x_vcalls_possible_p
|
||||
|
||||
/* Set to 0 at beginning of a function definition, set to 1 if
|
||||
a return statement that specifies a return value is seen. */
|
||||
|
||||
@ -734,6 +735,11 @@ struct language_function
|
||||
#define current_function_name_declared \
|
||||
cp_function_chain->name_declared
|
||||
|
||||
/* Nonzero if we have already generated code to initialize virtual
|
||||
function tables in this function. */
|
||||
|
||||
#define vtbls_set_up_p cp_function_chain->vtbls_set_up_p
|
||||
|
||||
/* Used to help generate temporary names which are unique within
|
||||
a function. Reset to 0 by start_function. */
|
||||
|
||||
@ -1868,12 +1874,6 @@ struct lang_decl
|
||||
constructor call, rather than an ordinary function call. */
|
||||
#define AGGR_INIT_VIA_CTOR_P(NODE) TREE_LANG_FLAG_0 (NODE)
|
||||
|
||||
/* Nonzero if this statement contained the first assigned to `this' in
|
||||
the current function. (Of course, one cannot assign to `this' in
|
||||
ANSI/ISO C++, but we still support assignments to this with
|
||||
-fthis-is-variable.) */
|
||||
#define EXPR_STMT_ASSIGNS_THIS(NODE) TREE_LANG_FLAG_0 ((NODE))
|
||||
|
||||
/* Nonzero if this statement should be considered a full-expression. */
|
||||
#define STMT_IS_FULL_EXPR_P(NODE) TREE_LANG_FLAG_1 ((NODE))
|
||||
|
||||
@ -2857,8 +2857,7 @@ struct pending_inline
|
||||
/* in method.c */
|
||||
extern struct pending_inline *pending_inlines;
|
||||
|
||||
/* Positive values means that we cannot make optimizing assumptions about
|
||||
`this'. Negative values means we know `this' to be of static type. */
|
||||
/* Negative values means we know `this' to be of static type. */
|
||||
|
||||
extern int flag_this_is_variable;
|
||||
|
||||
@ -3420,7 +3419,7 @@ extern tree do_friend PROTO((tree, tree, tree, tree, tree, enum overload_flag
|
||||
/* in init.c */
|
||||
extern void init_init_processing PROTO((void));
|
||||
extern void expand_direct_vtbls_init PROTO((tree, tree, int, int, tree));
|
||||
extern void emit_base_init PROTO((tree));
|
||||
extern tree emit_base_init PROTO((tree));
|
||||
extern void check_base_init PROTO((tree));
|
||||
extern void expand_member_init PROTO((tree, tree, tree));
|
||||
extern tree build_aggr_init PROTO((tree, tree, int));
|
||||
|
410
gcc/cp/decl.c
410
gcc/cp/decl.c
@ -180,6 +180,7 @@ static void save_function_data PROTO((tree));
|
||||
static void check_function_type PROTO((tree));
|
||||
static void destroy_local_static PROTO((tree));
|
||||
static void destroy_local_var PROTO((tree));
|
||||
static void finish_destructor_body PROTO((void));
|
||||
|
||||
#if defined (DEBUG_CP_BINDING_LEVELS)
|
||||
static void indent PROTO((void));
|
||||
@ -371,13 +372,6 @@ extern int flag_conserve_space;
|
||||
|
||||
/* C and C++ flags are in decl2.c. */
|
||||
|
||||
/* Set to 0 at beginning of a constructor, set to 1
|
||||
if that function does an allocation before referencing its
|
||||
instance variable. */
|
||||
#define current_function_assigns_this cp_function_chain->assigns_this
|
||||
#define current_function_just_assigned_this \
|
||||
cp_function_chain->just_assigned_this
|
||||
|
||||
/* Flag used when debugging spew.c */
|
||||
|
||||
extern int spew_debug;
|
||||
@ -3060,6 +3054,15 @@ duplicate_decls (newdecl, olddecl)
|
||||
the declarations, but make the original one static. */
|
||||
DECL_THIS_STATIC (olddecl) = 1;
|
||||
TREE_PUBLIC (olddecl) = 0;
|
||||
|
||||
/* Make the olddeclaration consistent with the new one so that
|
||||
all remnants of the builtin-ness of this function will be
|
||||
banished. */
|
||||
DECL_LANGUAGE (olddecl) = DECL_LANGUAGE (newdecl);
|
||||
DECL_RTL (olddecl) = DECL_RTL (newdecl);
|
||||
DECL_ASSEMBLER_NAME (olddecl) = DECL_ASSEMBLER_NAME (newdecl);
|
||||
SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (newdecl),
|
||||
newdecl);
|
||||
}
|
||||
}
|
||||
else if (TREE_CODE (olddecl) != TREE_CODE (newdecl))
|
||||
@ -12927,10 +12930,6 @@ start_function (declspecs, declarator, attrs, flags)
|
||||
*cp_function_chain = *DECL_SAVED_FUNCTION_DATA (decl1);
|
||||
current_binding_level = bl;
|
||||
|
||||
/* This function has not assigned to `this' yet. */
|
||||
current_function_assigns_this = 0;
|
||||
current_function_just_assigned_this = 0;
|
||||
|
||||
/* This function is being processed in whole-function mode; we
|
||||
already did semantic analysis. */
|
||||
current_function->x_whole_function_mode_p = 1;
|
||||
@ -13298,6 +13297,121 @@ save_function_data (decl)
|
||||
f->x_expanding_p = 1;
|
||||
}
|
||||
|
||||
/* At the end of every destructor we generate code to restore virtual
|
||||
function tables to the values desired by base classes and to call
|
||||
to base class destructors. Do that now, for DECL. */
|
||||
|
||||
static void
|
||||
finish_destructor_body ()
|
||||
{
|
||||
tree compound_stmt;
|
||||
tree in_charge;
|
||||
tree virtual_size;
|
||||
tree exprstmt;
|
||||
|
||||
/* Create a block to contain all the extra code. */
|
||||
compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
|
||||
|
||||
/* Generate the code to call destructor on base class. If this
|
||||
destructor belongs to a class with virtual functions, then set
|
||||
the virtual function table pointer to represent the type of our
|
||||
base class. */
|
||||
|
||||
/* This side-effect makes call to `build_delete' generate the code
|
||||
we have to have at the end of this destructor. `build_delete'
|
||||
will set the flag again. */
|
||||
TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
|
||||
|
||||
/* These are two cases where we cannot delegate deletion. */
|
||||
if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
|
||||
|| TYPE_GETS_REG_DELETE (current_class_type))
|
||||
in_charge = integer_zero_node;
|
||||
else
|
||||
in_charge = current_in_charge_parm;
|
||||
|
||||
exprstmt = build_delete (current_class_type,
|
||||
current_class_ref,
|
||||
in_charge,
|
||||
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
|
||||
0);
|
||||
|
||||
if (exprstmt != error_mark_node
|
||||
&& (TREE_CODE (exprstmt) != NOP_EXPR
|
||||
|| TREE_OPERAND (exprstmt, 0) != integer_zero_node
|
||||
|| TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
|
||||
{
|
||||
add_tree (build_min_nt (LABEL_STMT, dtor_label));
|
||||
if (exprstmt != void_zero_node)
|
||||
/* Don't call `expand_expr_stmt' if we're not going to do
|
||||
anything, since -Wall will give a diagnostic. */
|
||||
finish_expr_stmt (exprstmt);
|
||||
|
||||
/* Run destructor on all virtual baseclasses. */
|
||||
if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
|
||||
{
|
||||
tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type)));
|
||||
tree if_stmt = begin_if_stmt ();
|
||||
finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
|
||||
current_in_charge_parm,
|
||||
integer_two_node),
|
||||
if_stmt);
|
||||
|
||||
while (vbases)
|
||||
{
|
||||
if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
|
||||
{
|
||||
tree vb = get_vbase
|
||||
(BINFO_TYPE (vbases),
|
||||
TYPE_BINFO (current_class_type));
|
||||
finish_expr_stmt
|
||||
(build_scoped_method_call
|
||||
(current_class_ref, vb, dtor_identifier,
|
||||
build_expr_list (NULL_TREE, integer_zero_node)));
|
||||
}
|
||||
vbases = TREE_CHAIN (vbases);
|
||||
}
|
||||
|
||||
finish_then_clause (if_stmt);
|
||||
finish_if_stmt ();
|
||||
}
|
||||
}
|
||||
|
||||
virtual_size = c_sizeof (current_class_type);
|
||||
|
||||
/* At the end, call delete if that's what's requested. */
|
||||
|
||||
/* FDIS sez: At the point of definition of a virtual destructor
|
||||
(including an implicit definition), non-placement operator delete
|
||||
shall be looked up in the scope of the destructor's class and if
|
||||
found shall be accessible and unambiguous.
|
||||
|
||||
This is somewhat unclear, but I take it to mean that if the class
|
||||
only defines placement deletes we don't do anything here. So we
|
||||
pass LOOKUP_SPECULATIVELY; delete_sanity will complain for us if
|
||||
they ever try to delete one of these. */
|
||||
if (TYPE_GETS_REG_DELETE (current_class_type)
|
||||
|| TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
|
||||
{
|
||||
tree if_stmt;
|
||||
|
||||
exprstmt = build_op_delete_call
|
||||
(DELETE_EXPR, current_class_ptr, virtual_size,
|
||||
LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
|
||||
|
||||
if_stmt = begin_if_stmt ();
|
||||
finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
|
||||
current_in_charge_parm,
|
||||
integer_one_node),
|
||||
if_stmt);
|
||||
finish_expr_stmt (exprstmt);
|
||||
finish_then_clause (if_stmt);
|
||||
finish_if_stmt ();
|
||||
}
|
||||
|
||||
/* Close the block we started above. */
|
||||
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
|
||||
}
|
||||
|
||||
/* Finish up a function declaration and compile that function
|
||||
all the way to assembler language output. The free the storage
|
||||
for the function definition.
|
||||
@ -13322,7 +13436,6 @@ finish_function (lineno, flags)
|
||||
{
|
||||
register tree fndecl = current_function_decl;
|
||||
tree fntype, ctype = NULL_TREE;
|
||||
rtx fn_last_parm_insn, insns;
|
||||
/* Label to use if this function is supposed to return a value. */
|
||||
tree no_return_label = NULL_TREE;
|
||||
int call_poplevel = (flags & 1) != 0;
|
||||
@ -13338,9 +13451,9 @@ finish_function (lineno, flags)
|
||||
nested = function_depth > 1;
|
||||
fntype = TREE_TYPE (fndecl);
|
||||
|
||||
/* TREE_READONLY (fndecl) = 1;
|
||||
This caused &foo to be of type ptr-to-const-function
|
||||
which then got a warning when stored in a ptr-to-function variable. */
|
||||
/* TREE_READONLY (fndecl) = 1;
|
||||
This caused &foo to be of type ptr-to-const-function
|
||||
which then got a warning when stored in a ptr-to-function variable. */
|
||||
|
||||
/* This happens on strange parse errors. */
|
||||
if (! current_function_parms_stored)
|
||||
@ -13353,6 +13466,8 @@ finish_function (lineno, flags)
|
||||
{
|
||||
if (DECL_CONSTRUCTOR_P (fndecl) && call_poplevel)
|
||||
do_poplevel ();
|
||||
else if (DECL_DESTRUCTOR_P (fndecl) && !processing_template_decl)
|
||||
finish_destructor_body ();
|
||||
|
||||
/* Finish dealing with exception specifiers. */
|
||||
if (flag_exceptions && !processing_template_decl
|
||||
@ -13385,242 +13500,9 @@ finish_function (lineno, flags)
|
||||
do_pending_stack_adjust ();
|
||||
|
||||
if (dtor_label)
|
||||
{
|
||||
tree binfo = TYPE_BINFO (current_class_type);
|
||||
tree cond = integer_one_node;
|
||||
tree exprstmt;
|
||||
tree virtual_size;
|
||||
int ok_to_optimize_dtor = 0;
|
||||
int empty_dtor = get_last_insn () == last_dtor_insn;
|
||||
|
||||
if (current_function_assigns_this)
|
||||
cond = build (NE_EXPR, boolean_type_node,
|
||||
current_class_ptr, integer_zero_node);
|
||||
else
|
||||
{
|
||||
int n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
|
||||
|
||||
/* If this destructor is empty, then we don't need to check
|
||||
whether `this' is NULL in some cases. */
|
||||
if ((flag_this_is_variable & 1) == 0)
|
||||
ok_to_optimize_dtor = 1;
|
||||
else if (empty_dtor)
|
||||
ok_to_optimize_dtor
|
||||
= (n_baseclasses == 0
|
||||
|| (n_baseclasses == 1
|
||||
&& TYPE_HAS_DESTRUCTOR (TYPE_BINFO_BASETYPE (current_class_type, 0))));
|
||||
}
|
||||
|
||||
/* These initializations might go inline. Protect
|
||||
the binding level of the parms. */
|
||||
do_pushlevel ();
|
||||
|
||||
if (current_function_assigns_this)
|
||||
{
|
||||
current_function_assigns_this = 0;
|
||||
current_function_just_assigned_this = 0;
|
||||
}
|
||||
|
||||
/* Generate the code to call destructor on base class.
|
||||
If this destructor belongs to a class with virtual
|
||||
functions, then set the virtual function table
|
||||
pointer to represent the type of our base class. */
|
||||
|
||||
/* This side-effect makes call to `build_delete' generate the
|
||||
code we have to have at the end of this destructor.
|
||||
`build_delete' will set the flag again. */
|
||||
TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
|
||||
|
||||
/* These are two cases where we cannot delegate deletion. */
|
||||
if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
|
||||
|| TYPE_GETS_REG_DELETE (current_class_type))
|
||||
exprstmt = build_delete (current_class_type, current_class_ref, integer_zero_node,
|
||||
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0);
|
||||
else
|
||||
exprstmt = build_delete (current_class_type,
|
||||
current_class_ref,
|
||||
current_in_charge_parm,
|
||||
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0);
|
||||
|
||||
/* If we did not assign to this, then `this' is non-zero at
|
||||
the end of a destructor. As a special optimization, don't
|
||||
emit test if this is an empty destructor. If it does nothing,
|
||||
it does nothing. If it calls a base destructor, the base
|
||||
destructor will perform the test. */
|
||||
|
||||
if (exprstmt != error_mark_node
|
||||
&& (TREE_CODE (exprstmt) != NOP_EXPR
|
||||
|| TREE_OPERAND (exprstmt, 0) != integer_zero_node
|
||||
|| TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
|
||||
{
|
||||
expand_label (dtor_label);
|
||||
if (cond != integer_one_node)
|
||||
expand_start_cond (cond, 0);
|
||||
if (exprstmt != void_zero_node)
|
||||
/* Don't call `expand_expr_stmt' if we're not going to do
|
||||
anything, since -Wall will give a diagnostic. */
|
||||
expand_expr_stmt (exprstmt);
|
||||
|
||||
/* Run destructor on all virtual baseclasses. */
|
||||
if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
|
||||
{
|
||||
tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type)));
|
||||
expand_start_cond (build (BIT_AND_EXPR, integer_type_node,
|
||||
current_in_charge_parm,
|
||||
integer_two_node), 0);
|
||||
while (vbases)
|
||||
{
|
||||
if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
|
||||
{
|
||||
tree vb = get_vbase
|
||||
(BINFO_TYPE (vbases),
|
||||
TYPE_BINFO (current_class_type));
|
||||
expand_expr_stmt
|
||||
(build_scoped_method_call
|
||||
(current_class_ref, vb, dtor_identifier,
|
||||
build_expr_list (NULL_TREE, integer_zero_node)));
|
||||
}
|
||||
vbases = TREE_CHAIN (vbases);
|
||||
}
|
||||
expand_end_cond ();
|
||||
}
|
||||
|
||||
do_pending_stack_adjust ();
|
||||
if (cond != integer_one_node)
|
||||
expand_end_cond ();
|
||||
}
|
||||
|
||||
virtual_size = c_sizeof (current_class_type);
|
||||
|
||||
/* At the end, call delete if that's what's requested. */
|
||||
|
||||
/* FDIS sez: At the point of definition of a virtual destructor
|
||||
(including an implicit definition), non-placement operator
|
||||
delete shall be looked up in the scope of the destructor's
|
||||
class and if found shall be accessible and unambiguous.
|
||||
|
||||
This is somewhat unclear, but I take it to mean that if the
|
||||
class only defines placement deletes we don't do anything here.
|
||||
So we pass LOOKUP_SPECULATIVELY; delete_sanity will complain
|
||||
for us if they ever try to delete one of these. */
|
||||
|
||||
if (TYPE_GETS_REG_DELETE (current_class_type)
|
||||
|| TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
|
||||
exprstmt = build_op_delete_call
|
||||
(DELETE_EXPR, current_class_ptr, virtual_size,
|
||||
LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
|
||||
else
|
||||
exprstmt = NULL_TREE;
|
||||
|
||||
if (exprstmt)
|
||||
{
|
||||
cond = build (BIT_AND_EXPR, integer_type_node,
|
||||
current_in_charge_parm, integer_one_node);
|
||||
expand_start_cond (cond, 0);
|
||||
expand_expr_stmt (exprstmt);
|
||||
expand_end_cond ();
|
||||
}
|
||||
|
||||
/* End of destructor. */
|
||||
do_poplevel ();
|
||||
|
||||
/* Back to the top of destructor. */
|
||||
/* Don't execute destructor code if `this' is NULL. */
|
||||
|
||||
start_sequence ();
|
||||
|
||||
/* If the dtor is empty, and we know there is not possible way we
|
||||
could use any vtable entries, before they are possibly set by
|
||||
a base class dtor, we don't have to setup the vtables, as we
|
||||
know that any base class dtoring will set up any vtables it
|
||||
needs. We avoid MI, because one base class dtor can do a
|
||||
virtual dispatch to an overridden function that would need to
|
||||
have a non-related vtable set up, we cannot avoid setting up
|
||||
vtables in that case. We could change this to see if there is
|
||||
just one vtable. */
|
||||
if (! empty_dtor || TYPE_USES_COMPLEX_INHERITANCE (current_class_type))
|
||||
{
|
||||
/* Make all virtual function table pointers in non-virtual base
|
||||
classes point to CURRENT_CLASS_TYPE's virtual function
|
||||
tables. */
|
||||
expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr);
|
||||
|
||||
if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
|
||||
expand_indirect_vtbls_init (binfo, current_class_ref, current_class_ptr);
|
||||
}
|
||||
|
||||
if (! ok_to_optimize_dtor)
|
||||
{
|
||||
cond = build_binary_op (NE_EXPR,
|
||||
current_class_ptr, integer_zero_node);
|
||||
expand_start_cond (cond, 0);
|
||||
}
|
||||
|
||||
insns = get_insns ();
|
||||
end_sequence ();
|
||||
|
||||
fn_last_parm_insn = get_first_nonparm_insn ();
|
||||
if (fn_last_parm_insn == NULL_RTX)
|
||||
fn_last_parm_insn = get_last_insn ();
|
||||
else
|
||||
fn_last_parm_insn = previous_insn (fn_last_parm_insn);
|
||||
|
||||
emit_insns_after (insns, fn_last_parm_insn);
|
||||
|
||||
if (! ok_to_optimize_dtor)
|
||||
expand_end_cond ();
|
||||
}
|
||||
;
|
||||
else if (DECL_CONSTRUCTOR_P (fndecl))
|
||||
{
|
||||
/* If the current function assigns to `this', then code to
|
||||
initialize members and base-classes will be generated
|
||||
directly after the assignment. */
|
||||
if (!current_function_assigns_this)
|
||||
{
|
||||
start_sequence ();
|
||||
|
||||
if (flag_this_is_variable > 0)
|
||||
{
|
||||
/* Allow constructor for a type to get a new instance of
|
||||
the object using `build_new'. */
|
||||
tree cond = NULL_TREE, thenclause = NULL_TREE;
|
||||
tree abstract_virtuals
|
||||
= CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type);
|
||||
CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE;
|
||||
|
||||
cond = build_binary_op (EQ_EXPR,
|
||||
current_class_ptr, integer_zero_node);
|
||||
|
||||
expand_start_cond (cond, 0);
|
||||
|
||||
thenclause
|
||||
= build_modify_expr (current_class_ptr, NOP_EXPR,
|
||||
build_new (NULL_TREE,
|
||||
current_class_type,
|
||||
|
||||
void_type_node, 0));
|
||||
CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type)
|
||||
= abstract_virtuals;
|
||||
expand_expr_stmt (thenclause);
|
||||
expand_end_cond ();
|
||||
}
|
||||
|
||||
/* Emit insns from `emit_base_init' which sets up
|
||||
virtual function table pointer(s). Don't do this for
|
||||
a function which assigns to `this' as we will emit
|
||||
the appropriate code right after the assignment. */
|
||||
if (!current_function_assigns_this && base_init_expr)
|
||||
{
|
||||
expand_expr_stmt (base_init_expr);
|
||||
base_init_expr = NULL_TREE;
|
||||
}
|
||||
|
||||
insns = get_insns ();
|
||||
end_sequence ();
|
||||
|
||||
emit_insns_after (insns, last_parm_cleanup_insn);
|
||||
}
|
||||
|
||||
/* This is where the body of the constructor begins. All
|
||||
subobjects have been fully constructed at this point. */
|
||||
end_protect_partials ();
|
||||
@ -13634,9 +13516,6 @@ finish_function (lineno, flags)
|
||||
|
||||
/* c_expand_return knows to return 'this' from a constructor. */
|
||||
c_expand_return (NULL_TREE);
|
||||
|
||||
current_function_assigns_this = 0;
|
||||
current_function_just_assigned_this = 0;
|
||||
}
|
||||
else if (DECL_MAIN_P (fndecl))
|
||||
{
|
||||
@ -13648,13 +13527,9 @@ finish_function (lineno, flags)
|
||||
#endif
|
||||
}
|
||||
else if (return_label != NULL_RTX
|
||||
&& ((flag_this_is_variable <= 0
|
||||
&& current_function_return_value == NULL_TREE
|
||||
&& ! DECL_NAME (DECL_RESULT (current_function_decl)))
|
||||
|| (flag_this_is_variable > 0
|
||||
&& (TREE_CODE (TREE_TYPE (DECL_RESULT
|
||||
(current_function_decl)))
|
||||
== VOID_TYPE))))
|
||||
&& flag_this_is_variable <= 0
|
||||
&& current_function_return_value == NULL_TREE
|
||||
&& ! DECL_NAME (DECL_RESULT (current_function_decl)))
|
||||
no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
|
||||
|
||||
if (flag_exceptions)
|
||||
@ -14241,22 +14116,6 @@ cplus_expand_expr_stmt (exp)
|
||||
void
|
||||
finish_stmt ()
|
||||
{
|
||||
if (!current_function_assigns_this
|
||||
&& current_function_just_assigned_this)
|
||||
{
|
||||
if (DECL_CONSTRUCTOR_P (current_function_decl)
|
||||
&& !building_stmt_tree ())
|
||||
{
|
||||
/* Constructors must wait until we are out of control
|
||||
zones before calling base constructors. */
|
||||
if (in_control_zone_p ())
|
||||
return;
|
||||
expand_expr_stmt (base_init_expr);
|
||||
check_base_init (current_class_type);
|
||||
}
|
||||
current_function_assigns_this = 1;
|
||||
}
|
||||
|
||||
/* Always assume this statement was not an expression statement. If
|
||||
it actually was an expression statement, its our callers
|
||||
responsibility to fix this up. */
|
||||
@ -14344,7 +14203,6 @@ mark_lang_function (p)
|
||||
ggc_mark_tree (p->x_dtor_label);
|
||||
ggc_mark_tree (p->x_base_init_list);
|
||||
ggc_mark_tree (p->x_member_init_list);
|
||||
ggc_mark_tree (p->x_base_init_expr);
|
||||
ggc_mark_tree (p->x_current_class_ptr);
|
||||
ggc_mark_tree (p->x_current_class_ref);
|
||||
ggc_mark_tree (p->x_last_tree);
|
||||
|
@ -523,7 +523,6 @@ lang_f_options[] =
|
||||
{"squangle", &flag_do_squangling, 1},
|
||||
{"stats", &flag_detailed_statistics, 1},
|
||||
{"strict-prototype", &flag_strict_prototype, 1},
|
||||
{"this-is-variable", &flag_this_is_variable, 1},
|
||||
{"vtable-gc", &flag_vtable_gc, 1},
|
||||
{"vtable-thunks", &flag_vtable_thunks, 1},
|
||||
{"weak", &flag_weak, 1},
|
||||
@ -619,12 +618,6 @@ lang_decode_option (argc, argv)
|
||||
flag_guiding_decls = 0;
|
||||
found = 1;
|
||||
}
|
||||
else if (!strcmp (p, "this-is-variable"))
|
||||
{
|
||||
flag_this_is_variable = 1;
|
||||
found = 1;
|
||||
cp_deprecated ("-fthis-is-variable");
|
||||
}
|
||||
else if (!strcmp (p, "external-templates"))
|
||||
{
|
||||
flag_external_templates = 1;
|
||||
@ -1007,11 +1000,6 @@ grokclassfn (ctype, function, flags, quals)
|
||||
/* Right now we just make this a pointer. But later
|
||||
we may wish to make it special. */
|
||||
tree type = TREE_VALUE (arg_types);
|
||||
int constp = 1;
|
||||
|
||||
if ((flag_this_is_variable > 0)
|
||||
&& (flags == DTOR_FLAG || DECL_CONSTRUCTOR_P (function)))
|
||||
constp = 0;
|
||||
|
||||
parm = build_decl (PARM_DECL, this_identifier, type);
|
||||
/* Mark the artificial `this' parameter as "artificial". */
|
||||
@ -1020,8 +1008,7 @@ grokclassfn (ctype, function, flags, quals)
|
||||
/* We can make this a register, so long as we don't
|
||||
accidentally complain if someone tries to take its address. */
|
||||
DECL_REGISTER (parm) = 1;
|
||||
if (constp)
|
||||
TREE_READONLY (parm) = 1;
|
||||
TREE_READONLY (parm) = 1;
|
||||
TREE_CHAIN (parm) = last_function_parms;
|
||||
last_function_parms = parm;
|
||||
}
|
||||
|
@ -483,7 +483,7 @@ sort_base_init (t, rbase_ptr, vbase_ptr)
|
||||
Note that emit_base_init does *not* initialize virtual base
|
||||
classes. That is done specially, elsewhere. */
|
||||
|
||||
void
|
||||
tree
|
||||
emit_base_init (t)
|
||||
tree t;
|
||||
{
|
||||
@ -623,10 +623,9 @@ emit_base_init (t)
|
||||
mem_init_list = TREE_CHAIN (mem_init_list);
|
||||
}
|
||||
|
||||
base_init_expr = finish_init_stmts (stmt_expr, compound_stmt);
|
||||
|
||||
/* All the implicit try blocks we built up will be zapped
|
||||
when we come to a real binding contour boundary. */
|
||||
return finish_init_stmts (stmt_expr, compound_stmt);
|
||||
}
|
||||
|
||||
/* Check that all fields are properly initialized after
|
||||
@ -747,10 +746,6 @@ construct_virtual_bases (type, this_ref, this_ptr, init_list, flag)
|
||||
if_stmt = begin_if_stmt ();
|
||||
finish_if_stmt_cond (flag, if_stmt);
|
||||
result = init_vbase_pointers (type, this_ptr);
|
||||
/* The RESULT will contain entries on the momentary obstack. They
|
||||
must live until the end of this function; we use them in the loop
|
||||
below. */
|
||||
push_momentary ();
|
||||
if (result)
|
||||
finish_expr_stmt (build_compound_expr (result));
|
||||
finish_then_clause (if_stmt);
|
||||
@ -785,14 +780,11 @@ construct_virtual_bases (type, this_ref, this_ptr, init_list, flag)
|
||||
TREE_OPERAND (TREE_VALUE (tmp), 0),
|
||||
init_list);
|
||||
finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
|
||||
finish_then_clause (if_stmt);
|
||||
finish_then_clause (inner_if_stmt);
|
||||
finish_if_stmt ();
|
||||
|
||||
expand_cleanup_for_base (vbases, flag);
|
||||
}
|
||||
|
||||
/* Undo the call to push_momentary above. */
|
||||
pop_momentary ();
|
||||
}
|
||||
|
||||
/* Find the context in which this FIELD can be initialized. */
|
||||
@ -2214,18 +2206,7 @@ build_new_1 (exp)
|
||||
|
||||
/* Allocate the object. */
|
||||
|
||||
if (! has_array && ! placement && flag_this_is_variable > 0
|
||||
&& TYPE_NEEDS_CONSTRUCTING (true_type) && init != void_type_node)
|
||||
{
|
||||
if (init == NULL_TREE || TREE_CODE (init) == TREE_LIST)
|
||||
rval = NULL_TREE;
|
||||
else
|
||||
{
|
||||
error ("constructors take parameter lists");
|
||||
return error_mark_node;
|
||||
}
|
||||
}
|
||||
else if (! placement && TYPE_FOR_JAVA (true_type))
|
||||
if (! placement && TYPE_FOR_JAVA (true_type))
|
||||
{
|
||||
tree class_addr, alloc_decl;
|
||||
tree class_decl = build_java_class_ref (true_type);
|
||||
@ -2677,7 +2658,6 @@ get_temp_regvar (type, init)
|
||||
decl = create_temporary_var (type);
|
||||
if (building_stmt_tree ())
|
||||
add_decl_stmt (decl);
|
||||
DECL_REGISTER (decl) = 1;
|
||||
if (!building_stmt_tree ())
|
||||
DECL_RTL (decl) = assign_temp (type, 2, 0, 1);
|
||||
finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
|
||||
@ -2827,9 +2807,6 @@ build_vec_init (decl, base, maxindex, init, from_array)
|
||||
|
||||
/* Clear out INIT so that we don't get confused below. */
|
||||
init = NULL_TREE;
|
||||
|
||||
if (obey_regdecls && !building_stmt_tree ())
|
||||
use_variable (DECL_RTL (base));
|
||||
}
|
||||
else if (from_array)
|
||||
{
|
||||
@ -2958,13 +2935,6 @@ build_vec_init (decl, base, maxindex, init, from_array)
|
||||
build (PLUS_EXPR, build_pointer_type (type),
|
||||
base2, size)));
|
||||
|
||||
if (obey_regdecls && !building_stmt_tree ())
|
||||
{
|
||||
use_variable (DECL_RTL (base));
|
||||
if (base2)
|
||||
use_variable (DECL_RTL (base2));
|
||||
}
|
||||
|
||||
finish_compound_stmt (/*has_no_scope=*/1, do_body);
|
||||
finish_do_body (do_stmt);
|
||||
finish_do_stmt (build (NE_EXPR, boolean_type_node,
|
||||
@ -2996,12 +2966,6 @@ build_vec_init (decl, base, maxindex, init, from_array)
|
||||
finish_cleanup (e, try_block);
|
||||
}
|
||||
|
||||
if (obey_regdecls && !building_stmt_tree ())
|
||||
{
|
||||
use_variable (DECL_RTL (iterator));
|
||||
use_variable (DECL_RTL (rval));
|
||||
}
|
||||
|
||||
/* The value of the array initialization is the address of the
|
||||
first element in the array. */
|
||||
finish_expr_stmt (rval);
|
||||
|
@ -660,7 +660,7 @@ list. In particular, no @code{FIELD_DECL}, @code{LABEL_DECL}, or
|
||||
A class type is represented by either a @code{RECORD_TYPE} or a
|
||||
@code{UNION_TYPE}. A class declared with the @code{union} tag is
|
||||
represented by a @code{UNION_TYPE}, while classes declared with either
|
||||
the @code{struct} or the @code{union} tag are represented by
|
||||
the @code{struct} or the @code{class} tag are represented by
|
||||
@code{RECORD_TYPE}s. You can use the @code{CLASSTYPE_DECLARED_CLASS}
|
||||
macro to discern whether or not a particular type is a @code{class} as
|
||||
opposed to a @code{struct}. This macro will be true only for classes
|
||||
@ -1010,7 +1010,6 @@ FIXME: Explain about constructor try-catch blocks.
|
||||
@tindex COMPOUND_STMT
|
||||
@findex COMPOUND_BODY
|
||||
@tindex CONTINUE_STMT
|
||||
@tindex CTOR_INITIALIZER
|
||||
@tindex DECL_STMT
|
||||
@findex DECL_STMT_DECL
|
||||
@tindex DO_STMT
|
||||
@ -1050,26 +1049,17 @@ FIXME: Explain about constructor try-catch blocks.
|
||||
@findex WHILE_COND
|
||||
|
||||
A function that has a definition in the current translation unit will
|
||||
have a non-NULL @code{DECL_INITIAL}. However, the @code{DECL_INITIAL}
|
||||
will simply be the @code{error_mark_node}. (When tree structure is
|
||||
translated to RTL, @code{DECL_INITIAL} will contain a different value.)
|
||||
have a non-NULL @code{DECL_INITIAL}. However, back-ends should not make
|
||||
use of the particular value given by @code{DECL_INITIAL}.
|
||||
|
||||
The @code{DECL_SAVED_TREE} macro will give the complete body of the
|
||||
function. This node will usually be a @code{COMPOUND_STMT} representing
|
||||
the outermost block of the function, but it may also be a
|
||||
@code{TRY_BLOCK}, @code{RETURN_INIT}, or @code{CTOR_INITIALIZER}, as
|
||||
described below.
|
||||
@code{TRY_BLOCK} or a @code{RETURN_INIT}.
|
||||
|
||||
If the function has a function try-block, the @code{DECL_SAVED_TREE}
|
||||
will be a @code{TRY_BLOCK}. The @code{TRY_STMTS} will then be either a
|
||||
@code{RETURN_INIT}, @code{CTOR_INITIALIZER}, or @code{COMPOUND_STMT}.
|
||||
|
||||
If the function is a constructor, the @code{DECL_SAVED_TREE} may be a
|
||||
@code{CTOR_INITIALIZER} node, indicating how base classes and members
|
||||
should be initialized. The @code{TREE_CHAIN} of the
|
||||
@code{CTOR_INITIALIZER} will be the @code{COMPOUND_STMT} representing
|
||||
the body of the constructor. FIXME: Document how the base initializers
|
||||
and member initializers can be used.
|
||||
@code{RETURN_INIT}, or a @code{COMPOUND_STMT}.
|
||||
|
||||
If the function uses the G++ ``named return value'' extension, meaning
|
||||
that the function has been defined like:
|
||||
@ -1079,10 +1069,8 @@ S f(int) return s @{...@}
|
||||
the @code{DECL_SAVED_TREE} will be a @code{RETURN_INIT}. The
|
||||
@code{TREE_CHAIN} of the @code{RETURN_INIT} will be the
|
||||
@code{COMPOUND_STMT} representing the body of the function. There is
|
||||
never a named returned value for a constructor, so there is never a
|
||||
situation in which a @code{RETURN_INIT} and a @code{CTOR_INITIALIZER}
|
||||
appear simultaneously. FIXME: Document how the @code{RETURN_INIT} can
|
||||
be used.
|
||||
never a named returned value for a constructor. FIXME: Document how the
|
||||
@code{RETURN_INIT} can be used.
|
||||
|
||||
@subsection Statements
|
||||
|
||||
@ -1115,7 +1103,34 @@ Many of the statements have substatements. For example, a @code{while}
|
||||
loop will have a body, which is itself a statement. If the substatement
|
||||
is @code{NULL_TREE}, it is considered equivalent to a statement
|
||||
consisting of a single @code{;}, i.e., an expression statement in which
|
||||
the expression has been omitted.
|
||||
the expression has been omitted. A substatement may in fact be a list
|
||||
of statements, connected via their @code{TREE_CHAIN}s. So, you should
|
||||
always process the statement tree by looping over substatements, like
|
||||
this:
|
||||
@example
|
||||
void process_stmt (stmt)
|
||||
tree stmt;
|
||||
{
|
||||
while (stmt)
|
||||
{
|
||||
switch (TREE_CODE (stmt))
|
||||
{
|
||||
case IF_STMT:
|
||||
process_stmt (THEN_CLAUSE (stmt));
|
||||
/* More processing here. */
|
||||
break;
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
stmt = TREE_CHAIN (stmt);
|
||||
}
|
||||
}
|
||||
@end example
|
||||
In other words, while the @code{then} clause of an @code{if} statement
|
||||
in C++ can be only one statement (although that one statement may be a
|
||||
compound statement), the intermediate representation will sometimes use
|
||||
several statements chained together.
|
||||
|
||||
@table @code
|
||||
@item ASM_STMT
|
||||
|
@ -96,8 +96,6 @@ DEFINE_LANG_NAME ("C++")
|
||||
{ "-fstrict-prototype", "" },
|
||||
{ "-fno-strict-prototype", "Do not assume that empty prototype means no args" },
|
||||
{ "-ftemplate-depth-", "Specify maximum template instantiation depth"},
|
||||
{ "-fthis-is-variable", "Make 'this' not be type '* const'" },
|
||||
{ "-fno-this-is-variable", "" },
|
||||
{ "-fvtable-gc", "Discard unused virtual functions" },
|
||||
{ "-fno-vtable-gc", "" },
|
||||
{ "-fvtable-thunks", "Implement vtables using thunks" },
|
||||
|
@ -7261,11 +7261,6 @@ tsubst_expr (t, args, complain, in_decl)
|
||||
|
||||
case EXPR_STMT:
|
||||
prep_stmt (t);
|
||||
/* If we're doing tsubst'ing, then we should not yet have done
|
||||
semantic analysisy, so we should not know that this statement
|
||||
assigns to the `this' pointer. */
|
||||
my_friendly_assert (EXPR_STMT_ASSIGNS_THIS (t) == 0,
|
||||
19990831);
|
||||
finish_expr_stmt (tsubst_expr (EXPR_STMT_EXPR (t),
|
||||
args, complain, in_decl));
|
||||
break;
|
||||
|
@ -2609,12 +2609,12 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
|
||||
init = build (MODIFY_EXPR, TREE_TYPE (nvtbl),
|
||||
nvtbl, vtbl);
|
||||
TREE_SIDE_EFFECTS (init) = 1;
|
||||
expand_expr_stmt (init);
|
||||
finish_expr_stmt (init);
|
||||
/* Update the vtable pointers as necessary. */
|
||||
ref = build_vfield_ref
|
||||
(build_indirect_ref (addr, NULL_PTR),
|
||||
DECL_CONTEXT (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))));
|
||||
expand_expr_stmt
|
||||
finish_expr_stmt
|
||||
(build_modify_expr (ref, NOP_EXPR, nvtbl));
|
||||
}
|
||||
assemble_external (vtbl);
|
||||
@ -2657,7 +2657,7 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
|
||||
cp_build_qualified_type (TREE_TYPE (new_delta),
|
||||
CP_TYPE_QUALS (TREE_TYPE (new_delta))
|
||||
& ~TYPE_QUAL_CONST);
|
||||
expand_expr_stmt (build_modify_expr (new_delta, NOP_EXPR,
|
||||
finish_expr_stmt (build_modify_expr (new_delta, NOP_EXPR,
|
||||
old_delta));
|
||||
}
|
||||
++n;
|
||||
|
@ -41,7 +41,6 @@
|
||||
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 void finish_expr_stmt_real PROTO((tree, int));
|
||||
static tree expand_cond PROTO((tree));
|
||||
static tree maybe_convert_cond PROTO((tree));
|
||||
|
||||
@ -110,14 +109,11 @@ maybe_convert_cond (cond)
|
||||
return condition_conversion (cond);
|
||||
}
|
||||
|
||||
/* Finish an expression-statement, whose EXPRESSION is as indicated.
|
||||
If ASSIGNED_THIS is non-zero, then this statement just assigned to
|
||||
the `this' pointer. */
|
||||
/* Finish an expression-statement, whose EXPRESSION is as indicated. */
|
||||
|
||||
static void
|
||||
finish_expr_stmt_real (expr, assigned_this)
|
||||
void
|
||||
finish_expr_stmt (expr)
|
||||
tree expr;
|
||||
int assigned_this;
|
||||
{
|
||||
if (expr != NULL_TREE)
|
||||
{
|
||||
@ -147,11 +143,6 @@ finish_expr_stmt_real (expr, assigned_this)
|
||||
}
|
||||
}
|
||||
|
||||
/* If this statement assigned to the `this' pointer, record that
|
||||
fact for finish_stmt. */
|
||||
if (assigned_this)
|
||||
current_function_just_assigned_this = 1;
|
||||
|
||||
finish_stmt ();
|
||||
|
||||
/* This was an expression-statement, so we save the type of the
|
||||
@ -159,15 +150,6 @@ finish_expr_stmt_real (expr, assigned_this)
|
||||
last_expr_type = expr ? TREE_TYPE (expr) : NULL_TREE;
|
||||
}
|
||||
|
||||
/* Like finish_expr_stmt_real, but ASSIGNS_THIS is always zero. */
|
||||
|
||||
void
|
||||
finish_expr_stmt (expr)
|
||||
tree expr;
|
||||
{
|
||||
finish_expr_stmt_real (expr, /*assigns_this=*/0);
|
||||
}
|
||||
|
||||
/* Begin an if-statement. Returns a newly created IF_STMT if
|
||||
appropriate. */
|
||||
|
||||
@ -176,6 +158,8 @@ begin_if_stmt ()
|
||||
{
|
||||
tree r;
|
||||
|
||||
do_pushlevel ();
|
||||
|
||||
if (building_stmt_tree ())
|
||||
{
|
||||
r = build_min_nt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
|
||||
@ -184,8 +168,6 @@ begin_if_stmt ()
|
||||
else
|
||||
r = NULL_TREE;
|
||||
|
||||
do_pushlevel ();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -924,7 +906,9 @@ begin_compound_stmt (has_no_scope)
|
||||
|
||||
/* If this is the outermost block of the function, declare the
|
||||
variables __FUNCTION__, __PRETTY_FUNCTION__, and so forth. */
|
||||
if (!current_function_name_declared && !processing_template_decl)
|
||||
if (!current_function_name_declared
|
||||
&& !processing_template_decl
|
||||
&& !has_no_scope)
|
||||
{
|
||||
declare_function_name ();
|
||||
current_function_name_declared = 1;
|
||||
@ -1163,21 +1147,69 @@ finish_named_return_value (return_id, init)
|
||||
void
|
||||
setup_vtbl_ptr ()
|
||||
{
|
||||
if (base_init_expr == 0
|
||||
&& DECL_CONSTRUCTOR_P (current_function_decl))
|
||||
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 (building_stmt_tree ())
|
||||
if (processing_template_decl)
|
||||
add_tree (build_min_nt
|
||||
(CTOR_INITIALIZER,
|
||||
current_member_init_list, current_base_init_list));
|
||||
else
|
||||
emit_base_init (current_class_type);
|
||||
finish_expr_stmt (emit_base_init (current_class_type));
|
||||
}
|
||||
else if (DECL_DESTRUCTOR_P (current_function_decl)
|
||||
&& !processing_template_decl)
|
||||
{
|
||||
tree binfo = TYPE_BINFO (current_class_type);
|
||||
tree if_stmt;
|
||||
tree compound_stmt;
|
||||
|
||||
/* If the dtor is empty, and we know there is not possible way we
|
||||
could use any vtable entries, before they are possibly set by
|
||||
a base class dtor, we don't have to setup the vtables, as we
|
||||
know that any base class dtoring will set up any vtables it
|
||||
needs. We avoid MI, because one base class dtor can do a
|
||||
virtual dispatch to an overridden function that would need to
|
||||
have a non-related vtable set up, we cannot avoid setting up
|
||||
vtables in that case. We could change this to see if there is
|
||||
just one vtable. */
|
||||
if_stmt = begin_if_stmt ();
|
||||
|
||||
/* If it is not safe to avoid setting up the vtables, then
|
||||
someone will change the condition to be boolean_true_node.
|
||||
(Actually, for now, we do not have code to set the condition
|
||||
appropriate, so we just assume that we always need to
|
||||
initialize the vtables.) */
|
||||
finish_if_stmt_cond (boolean_true_node, if_stmt);
|
||||
current_vcalls_possible_p = &IF_COND (if_stmt);
|
||||
compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
|
||||
|
||||
/* Make all virtual function table pointers in non-virtual base
|
||||
classes point to CURRENT_CLASS_TYPE's virtual function
|
||||
tables. */
|
||||
expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr);
|
||||
|
||||
if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
|
||||
expand_indirect_vtbls_init (binfo, current_class_ref,
|
||||
current_class_ptr);
|
||||
|
||||
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
|
||||
finish_then_clause (if_stmt);
|
||||
finish_if_stmt ();
|
||||
}
|
||||
|
||||
/* Always keep the BLOCK node associated with the outermost pair of
|
||||
curley braces of a function. These are needed for correct
|
||||
curly braces of a function. These are needed for correct
|
||||
operation of dwarfout.c. */
|
||||
keep_next_level (1);
|
||||
|
||||
/* The virtual function tables are set up now. */
|
||||
vtbls_set_up_p = 1;
|
||||
}
|
||||
|
||||
/* Begin a new scope. */
|
||||
@ -2214,8 +2246,7 @@ expand_stmt (t)
|
||||
break;
|
||||
|
||||
case EXPR_STMT:
|
||||
finish_expr_stmt_real (EXPR_STMT_EXPR (t),
|
||||
EXPR_STMT_ASSIGNS_THIS (t));
|
||||
finish_expr_stmt (EXPR_STMT_EXPR (t));
|
||||
break;
|
||||
|
||||
case DECL_STMT:
|
||||
@ -2394,12 +2425,6 @@ expand_stmt (t)
|
||||
expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0);
|
||||
break;
|
||||
|
||||
case CTOR_INITIALIZER:
|
||||
current_member_init_list = TREE_OPERAND (t, 0);
|
||||
current_base_init_list = TREE_OPERAND (t, 1);
|
||||
setup_vtbl_ptr ();
|
||||
break;
|
||||
|
||||
case RETURN_INIT:
|
||||
/* Clear this out so that finish_named_return_value can set it
|
||||
again. */
|
||||
|
@ -5802,17 +5802,6 @@ build_modify_expr (lhs, modifycode, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
/* check to see if there is an assignment to `this' */
|
||||
if (lhs == current_class_ptr)
|
||||
{
|
||||
if (flag_this_is_variable > 0
|
||||
&& DECL_NAME (current_function_decl) != NULL_TREE
|
||||
&& (DECL_NAME (current_function_decl)
|
||||
!= constructor_name (current_class_type)))
|
||||
warning ("assignment to `this' not in constructor or destructor");
|
||||
current_function_just_assigned_this = 1;
|
||||
}
|
||||
|
||||
if (modifycode != INIT_EXPR)
|
||||
{
|
||||
/* Make modifycode now either a NOP_EXPR or an INIT_EXPR. */
|
||||
@ -6716,10 +6705,7 @@ c_expand_return (retval)
|
||||
}
|
||||
else if (DECL_CONSTRUCTOR_P (current_function_decl))
|
||||
{
|
||||
if (flag_this_is_variable)
|
||||
error ("return from a constructor: use `this = ...' instead");
|
||||
else
|
||||
error ("returning a value from a constructor");
|
||||
error ("returning a value from a constructor");
|
||||
retval = current_class_ptr;
|
||||
}
|
||||
|
||||
|
7
gcc/testsuite/g++.old-deja/g++.other/static8.C
Normal file
7
gcc/testsuite/g++.old-deja/g++.other/static8.C
Normal file
@ -0,0 +1,7 @@
|
||||
// Build don't link:
|
||||
// Special g++ Options: -fno-squangle
|
||||
// Origin: Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
static unsigned int strlen (const char*) {} // ERROR - previous declaration
|
||||
|
||||
int strlen__FPCc = 0; // ERROR - duplicate declaration
|
Loading…
Reference in New Issue
Block a user