📄 cp-init.c
字号:
/* Handle initialization things in C++. Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com)This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. *//* High-level class interface. */#include "config.h"#include "tree.h"#include "rtl.h"#include "cp-tree.h"#include "flags.h"#define NULL 0/* In C++, structures with well-defined constructors are initialized by those constructors, unasked. CURRENT_BASE_INIT_LIST holds a list of stmts for a BASE_INIT term in the grammar. This list has one element for each base class which must be initialized. The list elements are [basename, init], with type basetype. This allows the possibly anachronistic form (assuming d : a, b, c) "d (int a) : c(a+5), b (a-4), a (a+3)" where each successive term can be handed down the constructor line. Perhaps this was not intended. */tree current_base_init_list, current_member_init_list;void emit_base_init ();void check_base_init ();static void expand_aggr_vbase_init ();void expand_member_init ();void expand_aggr_init ();static void expand_aggr_init_1 ();static void expand_recursive_init_1 ();static void expand_recursive_init ();tree expand_vec_init ();tree build_vec_delete ();static void add_friend (), add_friends ();int is_aggr_typedef ();/* Cache _builtin_new and _builtin_delete exprs. */static tree BIN, BID;#ifdef SOStree get_linktable_name (), get_dtable_name (), get_sos_dtable ();static tree __sosFindCode, __sosLookup, __sosImport;static tree build_dynamic_new ();#endifstatic tree minus_one;/* Set up local variable for this file. MUST BE CALLED AFTER INIT_DECL_PROCESSING. */tree BI_header_type, BI_header_size;void init_init_processing (){ tree op_id; tree fields[2]; /* Define implicit `operator new' and `operator delete' functions. */ BIN = default_conversion (TREE_VALUE (IDENTIFIER_GLOBAL_VALUE (ansi_opname[(int) NEW_EXPR]))); TREE_USED (TREE_OPERAND (BIN, 0)) = 0; BID = default_conversion (TREE_VALUE (IDENTIFIER_GLOBAL_VALUE (ansi_opname[(int) DELETE_EXPR]))); TREE_USED (TREE_OPERAND (BID, 0)) = 0; minus_one = build_int_2 (-1, -1); op_id = ansi_opname[(int) NEW_EXPR]; IDENTIFIER_GLOBAL_VALUE (op_id) = BIN; op_id = ansi_opname[(int) DELETE_EXPR]; IDENTIFIER_GLOBAL_VALUE (op_id) = BID;#ifdef SOS if (flag_all_virtual == 2) { __sosFindCode = default_conversion (lookup_name (get_identifier ("sosFindCode"), 0)); __sosLookup = default_conversion (lookup_name (get_identifier ("sosLookup"), 0)); __sosImport = default_conversion (lookup_name (get_identifier ("sosImport"), 0)); }#endif /* Define the structure that holds header information for arrays allocated via operator new. */ BI_header_type = make_lang_type (RECORD_TYPE); fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("nelts"), sizetype); fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("ptr_2comp"), ptr_type_node); finish_builtin_type (BI_header_type, "__new_cookie", fields, 1, double_type_node); BI_header_size = size_in_bytes (BI_header_type);}/* Recursive subroutine of emit_base_init. For main type T, recursively initialize the vfields of the base type PARENT. RECURSE is non-zero when this function is being called recursively. */static voidinit_vfields (t, parent, recurse) tree t, parent; int recurse;{ tree vfields; /* Initialize all the virtual function table fields that do not come from virtual base classes. */ vfields = CLASSTYPE_VFIELDS (parent); while (vfields) { tree basetype = VF_DERIVED_VALUE (vfields) ? TYPE_MAIN_VARIANT (VF_DERIVED_VALUE (vfields)) : VF_BASETYPE_VALUE (vfields); /* If the vtable installed by the constructor was not the right one, fix that here. */ if (TREE_ADDRESSABLE (vfields) && CLASSTYPE_NEEDS_VIRTUAL_REINIT (basetype) && (recurse > 0 || TYPE_HAS_CONSTRUCTOR (basetype) /* BASE_INIT_LIST has already initialized the immediate basetypes. */ || get_base_distance (basetype, t, 0, 0) > 1)) { tree binfo = binfo_value (basetype, t, 0); if ((recurse != 0 && (binfo != binfo_value (basetype, parent, 0))) || (recurse == 0 && BINFO_VTABLE (binfo) != TYPE_BINFO_VTABLE (basetype))) { tree ptr = convert_pointer_to (binfo, current_class_decl); expand_expr_stmt (build_virtual_init (TYPE_BINFO (t), binfo, ptr)); } init_vfields (t, basetype, recurse+1); } vfields = TREE_CHAIN (vfields); }}/* Perform whatever initialization have yet to be done on the base class of the class variable. These actions are in the global variable CURRENT_BASE_INIT_LIST. Such an action could be NULL_TREE, meaning that the user has explicitly called the base class constructor with no arguments. If there is a need for a call to a constructor, we must surround that call with a pushlevel/poplevel pair, since we are technically at the PARM level of scope. Argument IMMEDIATELY, if zero, forces a new sequence to be generated to contain these new insns, so it can be emitted later. This sequence is saved in the global variable BASE_INIT_INSNS. Otherwise, the insns are emitted into the current sequence. Note that emit_base_init does *not* initialize virtual base classes. That is done specially, elsewhere. */ voidemit_base_init (t, immediately) tree t; int immediately;{ extern tree in_charge_identifier; tree member, decl, vbases; tree init_list; int pass, start; tree t_binfo = TYPE_BINFO (t); tree binfos = BINFO_BASETYPES (t_binfo); int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0; tree fields_to_unmark = NULL_TREE; if (! immediately) { do_pending_stack_adjust (); start_sequence (); } if (write_symbols == NO_DEBUG) /* As a matter of principle, `start_sequence' should do this. */ emit_note (0, -1); else /* Always emit a line number note so we can step into constructors. */ emit_line_note_force (DECL_SOURCE_FILE (current_function_decl), DECL_SOURCE_LINE (current_function_decl)); /* In this case, we always need IN_CHARGE_NODE, because we have to know whether to deallocate or not before exiting. */ if (flag_handle_exceptions == 2 && lookup_name (in_charge_identifier, 0) == NULL_TREE) { tree in_charge_node = pushdecl (build_decl (VAR_DECL, in_charge_identifier, integer_type_node)); store_init_value (in_charge_node, build (EQ_EXPR, integer_type_node, current_class_decl, integer_zero_node)); expand_decl (in_charge_node); expand_decl_init (in_charge_node); } start = ! TYPE_USES_VIRTUAL_BASECLASSES (t); for (pass = start; pass < 2; pass++) { tree vbase_init_list = NULL_TREE; for (init_list = current_base_init_list; init_list; init_list = TREE_CHAIN (init_list)) { tree basename = TREE_PURPOSE (init_list); tree binfo; tree init = TREE_VALUE (init_list); if (basename == NULL_TREE) { /* Initializer for single base class. Must not use multiple inheritance or this is ambiguous. */ switch (n_baseclasses) { case 0: error ("type `%s' does not have a base class to initialize", IDENTIFIER_POINTER (current_class_name)); return; case 1: break; default: error ("unnamed initializer ambiguous for type `%s' which uses multiple inheritance", IDENTIFIER_POINTER (current_class_name)); return; } binfo = TREE_VEC_ELT (binfos, 0); } else if (is_aggr_typedef (basename, 1)) { binfo = binfo_or_else (IDENTIFIER_TYPE_VALUE (basename), t); if (binfo == NULL_TREE) continue; /* Virtual base classes are special cases. Their initializers are recorded with this constructor, and they are used when this constructor is the top-level constructor called. */ if (! TREE_VIA_VIRTUAL (binfo)) { /* Otherwise, if it is not an immediate base class, complain. */ for (i = n_baseclasses-1; i >= 0; i--) if (BINFO_TYPE (binfo) == BINFO_TYPE (TREE_VEC_ELT (binfos, i))) break; if (i < 0) { error ("type `%s' is not an immediate base class of type `%s'", IDENTIFIER_POINTER (basename), IDENTIFIER_POINTER (current_class_name)); continue; } } } else continue; /* The base initialization list goes up to the first base class which can actually use it. */ if (pass == start) { char *msgp = (! TYPE_HAS_CONSTRUCTOR (BINFO_TYPE (binfo))) ? "cannot pass initialization up to class `%s'" : 0; while (! TYPE_HAS_CONSTRUCTOR (BINFO_TYPE (binfo)) && BINFO_BASETYPES (binfo) != NULL_TREE && TREE_VEC_LENGTH (BINFO_BASETYPES (binfo)) == 1) { /* ?? This should be fixed in RENO by forcing default constructors to exist. */ SET_BINFO_BASEINIT_MARKED (binfo); binfo = BINFO_BASETYPE (binfo, 0); } if (TYPE_HAS_CONSTRUCTOR (BINFO_TYPE (binfo))) { if (msgp) { if (pedantic) error_with_aggr_type (binfo, msgp); else msgp = 0; } } else { msgp = "no constructor found for initialization of `%s'"; error (msgp, IDENTIFIER_POINTER (basename)); } if (BINFO_BASEINIT_MARKED (binfo)) { msgp = "class `%s' initializer already specified"; error (msgp, IDENTIFIER_POINTER (basename)); } if (msgp) continue; SET_BINFO_BASEINIT_MARKED (binfo); if (TREE_VIA_VIRTUAL (binfo)) { vbase_init_list = tree_cons (init, BINFO_TYPE (binfo), vbase_init_list); continue; } if (pass == 0) continue; } else if (TREE_VIA_VIRTUAL (binfo)) continue; member = convert_pointer_to (binfo, current_class_decl); expand_aggr_init_1 (t_binfo, 0, build_indirect_ref (member, 0), init, BINFO_OFFSET_ZEROP (binfo), LOOKUP_PROTECTED_OK|LOOKUP_COMPLAIN); if (flag_handle_exceptions == 2 && TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo))) { cplus_expand_start_try (1); push_exception_cleanup (member); } } if (pass == 0) { tree first_arg = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl)); tree vbases; if (DECL_NAME (current_function_decl) == NULL_TREE && TREE_CHAIN (first_arg) != NULL_TREE) { /* If there are virtual baseclasses without initialization specified, and this is a default X(X&) constructor, build the initialization list so that each virtual baseclass of the new object is initialized from the virtual baseclass of the incoming arg. */ tree init_arg = build_unary_op (ADDR_EXPR, TREE_CHAIN (first_arg), 0); for (vbases = CLASSTYPE_VBASECLASSES (t); vbases; vbases = TREE_CHAIN (vbases)) { if (BINFO_BASEINIT_MARKED (vbases) == 0) { member = convert_pointer_to (vbases, init_arg); if (member == init_arg) member = TREE_CHAIN (first_arg); else TREE_TYPE (member) = build_reference_type (BINFO_TYPE (vbases)); vbase_init_list = tree_cons (convert_from_reference (member), vbases, vbase_init_list); SET_BINFO_BASEINIT_MARKED (vbases); } } } expand_start_cond (first_arg, 0); expand_aggr_vbase_init (t_binfo, C_C_D, current_class_decl, vbase_init_list); expand_expr_stmt (build_vbase_vtables_init (t_binfo, t_binfo, C_C_D, current_class_decl, 1)); expand_end_cond (); } } current_base_init_list = NULL_TREE; /* Now, perform default initialization of all base classes which have not yet been initialized, and unmark baseclasses which have been initialized. */ for (i = 0; i < n_baseclasses; i++) { tree base = current_class_decl; tree base_binfo = TREE_VEC_ELT (binfos, i); if (TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (base_binfo))) { if (! TREE_VIA_VIRTUAL (base_binfo) && ! BINFO_BASEINIT_MARKED (base_binfo)) { tree ref; if (BINFO_OFFSET_ZEROP (base_binfo)) base = build1 (NOP_EXPR, TYPE_POINTER_TO (BINFO_TYPE (base_binfo)), current_class_decl); else base = build (PLUS_EXPR, TYPE_POINTER_TO (BINFO_TYPE (base_binfo)), current_class_decl, BINFO_OFFSET (base_binfo)); ref = build_indirect_ref (base, 0); expand_aggr_init_1 (t_binfo, 0, ref, NULL_TREE, BINFO_OFFSET_ZEROP (base_binfo), LOOKUP_PROTECTED_OK|LOOKUP_COMPLAIN); if (flag_handle_exceptions == 2 && TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo))) { cplus_expand_start_try (1); push_exception_cleanup (base); } } } CLEAR_BINFO_BASEINIT_MARKED (base_binfo); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -