diff options
author | Mark Mitchell <mark@codesourcery.com> | 2000-04-09 04:28:33 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 2000-04-09 04:28:33 +0000 |
commit | 3dbc07b651f517fa2d07de91473a30b4216d091b (patch) | |
tree | 6f1b0dea92e2a38ea78ec4706a12cc4f332eeedf | |
parent | 4eaf5996ad3b761bfb2abd6d65f78b43c4f9a4e5 (diff) | |
download | gcc-3dbc07b651f517fa2d07de91473a30b4216d091b.zip gcc-3dbc07b651f517fa2d07de91473a30b4216d091b.tar.gz gcc-3dbc07b651f517fa2d07de91473a30b4216d091b.tar.bz2 |
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
-rw-r--r-- | gcc/cp/ChangeLog | 25 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 19 | ||||
-rw-r--r-- | gcc/cp/decl.c | 150 | ||||
-rw-r--r-- | gcc/cp/init.c | 149 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 2 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 6 |
6 files changed, 175 insertions, 176 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4b56953..3d8776e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 83863a5..1688ee2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c9d1d96..8585288 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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); - - 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); + 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); - 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. */ diff --git a/gcc/cp/init.c b/gcc/cp/init.c index a437a52..8da9d82 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -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; } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index b2aef8a..6801456 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 74f16b7..bce12ad 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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 |