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:
Mark Mitchell 1999-09-20 20:19:04 +00:00 committed by Mark Mitchell
parent 2307e37238
commit 9bfadf57a2
15 changed files with 340 additions and 442 deletions

View File

@ -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.

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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));

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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" },

View File

@ -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;

View File

@ -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;

View File

@ -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. */

View File

@ -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;
}

View 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