Under the new ABI, constructors don't return `this'.

* cp-tree.h (warn_reorder): Declare.
	(special_function_kind): New enum.
	(global_base_init_list): Remove declaration.
	(emit_base_init): Don't return a value.
	(check_base_init): Don't declare.
	(is_aggr_typedef): Likewise.
	* decl.c (check_special_function_return_type): New function.
	(return_types): Remove.
	(grokdeclarator): Use check_special_function_return_type.
	(start_function): Don't initialize ctor_label under the new ABI.
	(finish_construtor_body): Don't create a corresponding LABEL_STMT.
	* init.c (begin_init_stmts): Move to top of file.
	(finish_init_stmts): Likewise.
	(warn_reorder): Don't declare.
	(emit_base_init): Don't create a STMT_EXPR here.  Don't return a
	value.
	(check_base_init): Remove.
	(is_aggr_typedef): Likewise.
	(build_new_1): Don't use the return value of a constructor.
	* semantics.c (setup_vtbl_ptr): Don't use the return value
	of emit_base_init.
	* typeck.c (check_return_expr): Don't magically convert return
	statements into `return this' in constructors under the new ABI.

From-SVN: r33035
This commit is contained in:
Mark Mitchell 2000-04-09 04:28:33 +00:00 committed by Mark Mitchell
parent 4eaf5996ad
commit 3dbc07b651
6 changed files with 174 additions and 175 deletions

View File

@ -1,5 +1,30 @@
2000-04-08 Mark Mitchell <mark@codesourcery.com>
Under the new ABI, constructors don't return `this'.
* cp-tree.h (warn_reorder): Declare.
(special_function_kind): New enum.
(global_base_init_list): Remove declaration.
(emit_base_init): Don't return a value.
(check_base_init): Don't declare.
(is_aggr_typedef): Likewise.
* decl.c (check_special_function_return_type): New function.
(return_types): Remove.
(grokdeclarator): Use check_special_function_return_type.
(start_function): Don't initialize ctor_label under the new ABI.
(finish_construtor_body): Don't create a corresponding LABEL_STMT.
* init.c (begin_init_stmts): Move to top of file.
(finish_init_stmts): Likewise.
(warn_reorder): Don't declare.
(emit_base_init): Don't create a STMT_EXPR here. Don't return a
value.
(check_base_init): Remove.
(is_aggr_typedef): Likewise.
(build_new_1): Don't use the return value of a constructor.
* semantics.c (setup_vtbl_ptr): Don't use the return value
of emit_base_init.
* typeck.c (check_return_expr): Don't magically convert return
statements into `return this' in constructors under the new ABI.
* cp-tree.h (cp_tree_index): Add CPTI_BASE_CTOR_IDENTIFIER,
CPTI_BASE_DTOR_IDENTIFIER, and CPTI_DELETING_DTOR_IDENTIFIER.
(base_ctor_identifier): New macro.

View File

@ -1102,6 +1102,10 @@ extern int warn_extern_inline;
extern int warn_old_style_cast;
/* Non-zero means warn when the compiler will reorder code. */
extern int warn_reorder;
/* Nonzero means to treat bitfields as unsigned unless they say `signed'. */
extern int flag_signed_bitfields;
@ -3098,6 +3102,13 @@ typedef enum access_kind {
ak_private = 3 /* Accessible, as a `private' thing. */
} access_kind;
typedef enum special_function_kind {
sfk_none, /* Not a special function. */
sfk_constructor, /* A constructor. */
sfk_destructor, /* A destructor. */
sfk_conversion /* A conversion operator. */
} special_function_kind;
/* Zero means prototype weakly, as in ANSI C (no args means nothing).
Each language context defines how this variable should be set. */
extern int strict_prototype;
@ -3217,10 +3228,6 @@ extern int current_class_depth;
/* Points to the name of that function. May not be the DECL_NAME
of CURRENT_FUNCTION_DECL due to overloading */
extern tree original_function_name;
/* in init.c */
extern tree global_base_init_list;
/* Here's where we control how name mangling takes place. */
@ -3999,11 +4006,9 @@ extern tree do_friend PARAMS ((tree, tree, tree, tree, tree, enum overload_fl
/* in init.c */
extern void init_init_processing PARAMS ((void));
extern tree emit_base_init PARAMS ((tree));
extern void check_base_init PARAMS ((tree));
extern void emit_base_init PARAMS ((tree));
extern void expand_member_init PARAMS ((tree, tree, tree));
extern tree build_aggr_init PARAMS ((tree, tree, int));
extern int is_aggr_typedef PARAMS ((tree, int));
extern int is_aggr_type PARAMS ((tree, int));
extern tree get_aggr_from_typedef PARAMS ((tree, int));
extern tree get_type_value PARAMS ((tree));

View File

@ -178,6 +178,8 @@ static tree start_cleanup_fn PARAMS ((void));
static void end_cleanup_fn PARAMS ((void));
static tree cp_make_fname_decl PARAMS ((tree, const char *, int));
static void initialize_predefined_identifiers PARAMS ((void));
static tree check_special_function_return_type
PARAMS ((special_function_kind, tree, tree, tree));
#if defined (DEBUG_CP_BINDING_LEVELS)
static void indent PARAMS ((void));
@ -9298,6 +9300,54 @@ create_array_type_for_decl (name, type, size)
return build_cplus_array_type (type, itype);
}
/* Check that it's OK to declare a function with the indicated TYPE.
SFK indicates the kind of special function (if any) that this
function is. CTYPE is the class of which this function is a
member. OPTYPE is the type given in a conversion operator
declaration. Returns the actual return type of the function; that
may be different than TYPE if an error occurs, or for certain
special functions. */
static tree
check_special_function_return_type (sfk, type, ctype, optype)
special_function_kind sfk;
tree type;
tree ctype;
tree optype;
{
switch (sfk)
{
case sfk_constructor:
if (type)
cp_error ("return type specification for constructor invalid");
/* In the old ABI, we return `this'; in the new ABI we don't
bother. */
type = flag_new_abi ? void_type_node : build_pointer_type (ctype);
break;
case sfk_destructor:
if (type)
cp_error ("return type specification for destructor invalid");
type = void_type_node;
break;
case sfk_conversion:
if (type && !same_type_p (type, optype))
cp_error ("operator `%T' declared to return `%T'", optype, type);
else if (type)
cp_pedwarn ("return type specified for `operator %T'", optype);
type = optype;
break;
default:
my_friendly_abort (20000408);
break;
}
return type;
}
/* Given declspecs and a declarator,
determine the name and type of the object declared
and construct a ..._DECL node for it.
@ -9358,8 +9408,6 @@ create_array_type_for_decl (name, type, size)
May return void_type_node if the declarator turned out to be a friend.
See grokfield for details. */
enum return_types { return_normal, return_ctor, return_dtor, return_conversion };
tree
grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
tree declspecs;
@ -9398,7 +9446,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
/* Keep track of what sort of function is being processed
so that we can warn about default return values, or explicit
return values which do not match prescribed defaults. */
enum return_types return_type = return_normal;
special_function_kind sfk = sfk_none;
tree dname = NULL_TREE;
tree ctype = current_class_type;
@ -9448,7 +9496,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
my_friendly_assert (flags == NO_SPECIAL, 152);
flags = DTOR_FLAG;
return_type = return_dtor;
sfk = sfk_destructor;
if (TREE_CODE (name) == TYPE_DECL)
TREE_OPERAND (decl, 0) = name = constructor_name (name);
my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 153);
@ -9547,7 +9595,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
&& decl != NULL_TREE && flags != DTOR_FLAG
&& decl == constructor_name (ctype))
{
return_type = return_ctor;
sfk = sfk_constructor;
ctor_return_type = ctype;
}
ctype = NULL_TREE;
@ -9595,7 +9643,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
my_friendly_assert (flags == NO_SPECIAL, 154);
flags = TYPENAME_FLAG;
ctor_return_type = TREE_TYPE (dname);
return_type = return_conversion;
sfk = sfk_conversion;
}
name = operator_name_string (dname);
}
@ -9659,7 +9707,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
if (TREE_CODE (decl) == IDENTIFIER_NODE
&& constructor_name (ctype) == decl)
{
return_type = return_ctor;
sfk = sfk_constructor;
ctor_return_type = ctype;
}
else if (TREE_CODE (decl) == BIT_NOT_EXPR
@ -9667,7 +9715,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
&& (constructor_name (ctype) == TREE_OPERAND (decl, 0)
|| constructor_name_full (ctype) == TREE_OPERAND (decl, 0)))
{
return_type = return_dtor;
sfk = sfk_destructor;
ctor_return_type = ctype;
flags = DTOR_FLAG;
TREE_OPERAND (decl, 0) = constructor_name (ctype);
@ -9883,58 +9931,35 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
defaulted_int = 1;
}
if (type == NULL_TREE)
if (sfk != sfk_none)
type = check_special_function_return_type (sfk, type,
ctor_return_type,
ctor_return_type);
else if (type == NULL_TREE)
{
int is_main;
explicit_int = -1;
if (return_type == return_dtor)
type = void_type_node;
else if (return_type == return_ctor)
type = build_pointer_type (ctor_return_type);
else if (return_type == return_conversion)
type = ctor_return_type;
else
{
/* We handle `main' specially here, because 'main () { }' is so
common. With no options, it is allowed. With -Wreturn-type,
it is a warning. It is only an error with -pedantic-errors. */
int is_main = (funcdef_flag
&& MAIN_NAME_P (dname)
&& ctype == NULL_TREE
&& in_namespace == NULL_TREE
&& current_namespace == global_namespace);
is_main = (funcdef_flag
&& MAIN_NAME_P (dname)
&& ctype == NULL_TREE
&& in_namespace == NULL_TREE
&& current_namespace == global_namespace);
if (in_system_header || flag_ms_extensions)
/* Allow it, sigh. */;
else if (pedantic || ! is_main)
cp_pedwarn ("ISO C++ forbids declaration of `%s' with no type",
name);
else if (warn_return_type)
cp_warning ("ISO C++ forbids declaration of `%s' with no type",
name);
if (in_system_header || flag_ms_extensions)
/* Allow it, sigh. */;
else if (pedantic || ! is_main)
cp_pedwarn ("ISO C++ forbids declaration of `%s' with no type",
name);
else if (warn_return_type)
cp_warning ("ISO C++ forbids declaration of `%s' with no type",
name);
type = integer_type_node;
}
}
else if (return_type == return_dtor)
{
error ("return type specification for destructor invalid");
type = void_type_node;
}
else if (return_type == return_ctor)
{
error ("return type specification for constructor invalid");
type = build_pointer_type (ctor_return_type);
}
else if (return_type == return_conversion)
{
if (!same_type_p (type, ctor_return_type))
cp_error ("operator `%T' declared to return `%T'",
ctor_return_type, type);
else
cp_pedwarn ("return type specified for `operator %T'",
ctor_return_type);
type = ctor_return_type;
type = integer_type_node;
}
ctype = NULL_TREE;
@ -10079,7 +10104,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
type = build_complex_type (type);
}
if (return_type == return_conversion
if (sfk == sfk_conversion
&& (RIDBIT_SETP (RID_CONST, specbits)
|| RIDBIT_SETP (RID_VOLATILE, specbits)
|| RIDBIT_SETP (RID_RESTRICT, specbits)))
@ -10376,7 +10401,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
&& (friendp == 0 || dname == current_class_name))
ctype = current_class_type;
if (ctype && return_type == return_conversion)
if (ctype && sfk == sfk_conversion)
TYPE_HAS_CONVERSION (ctype) = 1;
if (ctype && constructor_name (ctype) == dname)
{
@ -10435,7 +10460,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
if (RIDBIT_ANY_SET (tmp_bits))
error ("return value type specifier for constructor ignored");
}
type = build_pointer_type (ctype);
if (decl_context == FIELD)
{
if (! member_function_or_else (ctype,
@ -10443,7 +10467,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
flags))
return void_type_node;
TYPE_HAS_CONSTRUCTOR (ctype) = 1;
if (return_type != return_ctor)
if (sfk != sfk_constructor)
return NULL_TREE;
}
}
@ -13532,7 +13556,12 @@ start_function (declspecs, declarator, attrs, flags)
dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
DECL_CONTEXT (dtor_label) = current_function_decl;
}
else if (DECL_CONSTRUCTOR_P (decl1))
/* Under the old ABI we return `this' from constructors, so we make
ordinary `return' statements in constructors jump to CTOR_LABEL;
from there we return `this'. Under the new ABI, we don't bother
with any of this. By not setting CTOR_LABEL the remainder of the
machinery is automatically disabled. */
else if (!flag_new_abi && DECL_CONSTRUCTOR_P (decl1))
{
ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
DECL_CONTEXT (ctor_label) = current_function_decl;
@ -13764,7 +13793,8 @@ static void
finish_constructor_body ()
{
/* Any return from a constructor will end up here. */
add_tree (build_min_nt (LABEL_STMT, ctor_label));
if (ctor_label)
add_tree (build_min_nt (LABEL_STMT, ctor_label));
/* Clear CTOR_LABEL so that finish_return_stmt knows to really
generate the return, rather than a goto to CTOR_LABEL. */

View File

@ -79,6 +79,45 @@ void init_init_processing ()
ggc_add_tree_root (&BI_header_size, 1);
}
/* We are about to generate some complex initialization code.
Conceptually, it is all a single expression. However, we may want
to include conditionals, loops, and other such statement-level
constructs. Therefore, we build the initialization code inside a
statement-expression. This function starts such an expression.
STMT_EXPR_P and COMPOUND_STMT_P are filled in by this function;
pass them back to finish_init_stmts when the expression is
complete. */
void
begin_init_stmts (stmt_expr_p, compound_stmt_p)
tree *stmt_expr_p;
tree *compound_stmt_p;
{
*stmt_expr_p = begin_stmt_expr ();
*compound_stmt_p = begin_compound_stmt (/*has_no_scope=*/1);
}
/* Finish out the statement-expression begun by the previous call to
begin_init_stmts. Returns the statement-expression itself. */
tree
finish_init_stmts (stmt_expr, compound_stmt)
tree stmt_expr;
tree compound_stmt;
{
finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
stmt_expr = finish_stmt_expr (stmt_expr);
/* To avoid spurious warnings about unused values, we set
TREE_USED. */
if (stmt_expr)
TREE_USED (stmt_expr) = 1;
return stmt_expr;
}
/* Constructors */
/* Called from initialize_vtbl_ptrs via dfs_walk. */
static tree
@ -132,8 +171,6 @@ initialize_vtbl_ptrs (type, addr)
expand_indirect_vtbls_init (TYPE_BINFO (type), addr);
}
/* 348 - 351 */
/* Subroutine of emit_base_init. */
static void
@ -240,8 +277,6 @@ perform_member_init (member, name, init, explicit)
}
}
extern int warn_reorder;
/* Subroutine of emit_member_init. */
static tree
@ -485,7 +520,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. */
tree
void
emit_base_init (t)
tree t;
{
@ -494,9 +529,8 @@ emit_base_init (t)
tree rbase_init_list, vbase_init_list;
tree t_binfo = TYPE_BINFO (t);
tree binfos = BINFO_BASETYPES (t_binfo);
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
tree stmt_expr;
tree compound_stmt;
int i;
int n_baseclasses = BINFO_N_BASETYPES (t_binfo);
mem_init_list = sort_member_init (t);
current_member_init_list = NULL_TREE;
@ -504,8 +538,6 @@ emit_base_init (t)
sort_base_init (t, &rbase_init_list, &vbase_init_list);
current_base_init_list = NULL_TREE;
begin_init_stmts (&stmt_expr, &compound_stmt);
/* First, initialize the virtual base classes, if we are
constructing the most-derived object. */
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
@ -618,25 +650,6 @@ emit_base_init (t)
}
mem_init_list = TREE_CHAIN (mem_init_list);
}
/* 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
an assignment to `this'. Called only when such an assignment
is actually noted. */
void
check_base_init (t)
tree t;
{
tree member;
for (member = TYPE_FIELDS (t); member; member = TREE_CHAIN (member))
if (DECL_NAME (member) && TREE_USED (member))
cp_error ("field `%D' used before initialized (after assignment to `this')",
member);
}
/* This code sets up the virtual function tables appropriate for
@ -983,43 +996,6 @@ expand_member_init (exp, name, init)
}
}
/* We are about to generate some complex initialization code.
Conceptually, it is all a single expression. However, we may want
to include conditionals, loops, and other such statement-level
constructs. Therefore, we build the initialization code inside a
statement-expression. This function starts such an expression.
STMT_EXPR_P and COMPOUND_STMT_P are filled in by this function;
pass them back to finish_init_stmts when the expression is
complete. */
void
begin_init_stmts (stmt_expr_p, compound_stmt_p)
tree *stmt_expr_p;
tree *compound_stmt_p;
{
*stmt_expr_p = begin_stmt_expr ();
*compound_stmt_p = begin_compound_stmt (/*has_no_scope=*/1);
}
/* Finish out the statement-expression begun by the previous call to
begin_init_stmts. Returns the statement-expression itself. */
tree
finish_init_stmts (stmt_expr, compound_stmt)
tree stmt_expr;
tree compound_stmt;
{
finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
stmt_expr = finish_stmt_expr (stmt_expr);
/* To avoid spurious warnings about unused values, we set
TREE_USED. */
if (stmt_expr)
TREE_USED (stmt_expr) = 1;
return stmt_expr;
}
/* This is like `expand_member_init', only it stores one aggregate
value into another.
@ -1268,39 +1244,6 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, flags)
expand_default_init (binfo, true_exp, exp, init, flags);
}
/* Report an error if NAME is not the name of a user-defined,
aggregate type. If OR_ELSE is nonzero, give an error message. */
int
is_aggr_typedef (name, or_else)
tree name;
int or_else;
{
tree type;
if (name == error_mark_node)
return 0;
if (IDENTIFIER_HAS_TYPE_VALUE (name))
type = IDENTIFIER_TYPE_VALUE (name);
else
{
if (or_else)
cp_error ("`%T' is not an aggregate typedef", name);
return 0;
}
if (! IS_AGGR_TYPE (type)
&& TREE_CODE (type) != TEMPLATE_TYPE_PARM
&& TREE_CODE (type) != TEMPLATE_TEMPLATE_PARM)
{
if (or_else)
cp_error ("`%T' is not an aggregate type", type);
return 0;
}
return 1;
}
/* Report an error if TYPE is not a user-defined, aggregate type. If
OR_ELSE is nonzero, give an error message. */
@ -2413,8 +2356,7 @@ build_new_1 (exp)
flags |= LOOKUP_HAS_IN_CHARGE;
}
if (use_java_new)
rval = save_expr (rval);
rval = save_expr (rval);
newrval = rval;
if (newrval && TREE_CODE (TREE_TYPE (newrval)) == POINTER_TYPE)
@ -2426,10 +2368,7 @@ build_new_1 (exp)
if (newrval == NULL_TREE || newrval == error_mark_node)
return error_mark_node;
/* Java constructors compiled by jc1 do not return this. */
if (use_java_new)
newrval = build (COMPOUND_EXPR, TREE_TYPE (newrval),
newrval, rval);
newrval = build (COMPOUND_EXPR, TREE_TYPE (rval), newrval, rval);
rval = newrval;
TREE_HAS_CONSTRUCTOR (rval) = 1;
}

View File

@ -1235,7 +1235,7 @@ setup_vtbl_ptr ()
add_tree (ctor_stmt);
/* And actually initialize the base-classes and members. */
finish_expr_stmt (emit_base_init (current_class_type));
emit_base_init (current_class_type);
}
}
else if (DECL_DESTRUCTOR_P (current_function_decl)

View File

@ -6796,9 +6796,9 @@ check_return_expr (retval)
/* You can't return a value from a constructor. */
error ("returning a value from a constructor");
/* Constructors actually always return `this', even though in C++
you can't return a value from a constructor. */
if (DECL_CONSTRUCTOR_P (current_function_decl))
/* Under the old ABI, constructors actually always return `this',
even though in C++ you can't return a value from a constructor. */
if (!flag_new_abi && DECL_CONSTRUCTOR_P (current_function_decl))
retval = current_class_ptr;
/* When no explicit return-value is given in a function with a named