📄 init.c
字号:
/* Handle initialization things in C++. Copyright (C) 1987, 89, 92-98, 1999 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, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. *//* High-level class interface. */#include "config.h"#include "system.h"#include "tree.h"#include "rtl.h"#include "cp-tree.h"#include "flags.h"#include "output.h"#include "except.h"#include "expr.h"#include "toplev.h"/* 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;static void expand_aggr_vbase_init_1 PROTO((tree, tree, tree, tree));static void construct_virtual_bases PROTO((tree, tree, tree, tree, tree));static void expand_aggr_init_1 PROTO((tree, tree, tree, tree, int));static void expand_default_init PROTO((tree, tree, tree, tree, int));static tree build_vec_delete_1 PROTO((tree, tree, tree, tree, tree, int));static void perform_member_init PROTO((tree, tree, tree, int));static void sort_base_init PROTO((tree, tree *, tree *));static tree build_builtin_delete_call PROTO((tree));static int member_init_ok_or_else PROTO((tree, tree, const char *));static void expand_virtual_init PROTO((tree, tree));static tree sort_member_init PROTO((tree));static tree initializing_context PROTO((tree));static void expand_vec_init_try_block PROTO((tree));static void expand_vec_init_catch_clause PROTO((tree, tree, tree, tree));static tree build_java_class_ref PROTO((tree));static void expand_cleanup_for_base PROTO((tree, tree, tree));static int pvbasecount PROTO((tree, int));/* Cache the identifier nodes for the magic field of a new cookie. */static tree nc_nelts_field_id;static tree minus_one;/* Set up local variable for this file. MUST BE CALLED AFTER INIT_DECL_PROCESSING. */static tree BI_header_type, BI_header_size;void init_init_processing (){ tree fields[1]; minus_one = build_int_2 (-1, -1); /* Define the structure that holds header information for arrays allocated via operator new. */ BI_header_type = make_lang_type (RECORD_TYPE); nc_nelts_field_id = get_identifier ("nelts"); fields[0] = build_lang_field_decl (FIELD_DECL, nc_nelts_field_id, sizetype); finish_builtin_type (BI_header_type, "__new_cookie", fields, 0, double_type_node); BI_header_size = size_in_bytes (BI_header_type);}/* Subroutine of emit_base_init. For BINFO, initialize all the virtual function table pointers, except those that come from virtual base classes. Initialize binfo's vtable pointer, if INIT_SELF is true. CAN_ELIDE is true when we know that all virtual function table pointers in all bases have been initialized already, probably because their constructors have just be run. ADDR is the pointer to the object whos vtables we are going to initialize. REAL_BINFO is usually the same as BINFO, except when addr is not of pointer to the type of the real derived type that we want to initialize for. This is the case when addr is a pointer to a sub object of a complete object, and we only want to do part of the complete object's initialization of vtable pointers. This is done for all virtual table pointers in virtual base classes. REAL_BINFO is used to find the BINFO_VTABLE that we initialize with. BINFO is used for conversions of addr to subobjects. BINFO_TYPE (real_binfo) must be BINFO_TYPE (binfo). Relies upon binfo being inside TYPE_BINFO (TREE_TYPE (TREE_TYPE (addr))). */voidexpand_direct_vtbls_init (real_binfo, binfo, init_self, can_elide, addr) tree real_binfo, binfo, addr; int init_self, can_elide;{ tree real_binfos = BINFO_BASETYPES (real_binfo); tree binfos = BINFO_BASETYPES (binfo); int i, n_baselinks = real_binfos ? TREE_VEC_LENGTH (real_binfos) : 0; for (i = 0; i < n_baselinks; i++) { tree real_base_binfo = TREE_VEC_ELT (real_binfos, i); tree base_binfo = TREE_VEC_ELT (binfos, i); int is_not_base_vtable = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo)); if (! TREE_VIA_VIRTUAL (real_base_binfo)) expand_direct_vtbls_init (real_base_binfo, base_binfo, is_not_base_vtable, can_elide, addr); }#if 0 /* Before turning this on, make sure it is correct. */ if (can_elide && ! BINFO_MODIFIED (binfo)) return;#endif /* Should we use something besides CLASSTYPE_VFIELDS? */ if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (real_binfo))) { tree base_ptr = convert_pointer_to_real (binfo, addr); expand_virtual_init (real_binfo, base_ptr); }}/* 348 - 351 *//* Subroutine of emit_base_init. */static voidperform_member_init (member, name, init, explicit) tree member, name, init; int explicit;{ tree decl; tree type = TREE_TYPE (member); expand_start_target_temps (); if (TYPE_NEEDS_CONSTRUCTING (type) || (init && TYPE_HAS_CONSTRUCTOR (type))) { /* Since `init' is already a TREE_LIST on the current_member_init_list, only build it into one if we aren't already a list. */ if (init != NULL_TREE && TREE_CODE (init) != TREE_LIST) init = build_expr_list (NULL_TREE, init); decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit); if (explicit && TREE_CODE (type) == ARRAY_TYPE && init != NULL_TREE && TREE_CHAIN (init) == NULL_TREE && TREE_CODE (TREE_TYPE (TREE_VALUE (init))) == ARRAY_TYPE) { /* Initialization of one array from another. */ expand_vec_init (TREE_OPERAND (decl, 1), decl, array_type_nelts (type), TREE_VALUE (init), 1); } else expand_aggr_init (decl, init, 0); } else { if (init == NULL_TREE) { if (explicit) { /* default-initialization. */ if (AGGREGATE_TYPE_P (type)) init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE); else if (TREE_CODE (type) == REFERENCE_TYPE) { cp_error ("default-initialization of `%#D', which has reference type", member); init = error_mark_node; } else init = integer_zero_node; } /* member traversal: note it leaves init NULL */ else if (TREE_CODE (TREE_TYPE (member)) == REFERENCE_TYPE) cp_pedwarn ("uninitialized reference member `%D'", member); } else if (TREE_CODE (init) == TREE_LIST) { /* There was an explicit member initialization. Do some work in that case. */ if (TREE_CHAIN (init)) { warning ("initializer list treated as compound expression"); init = build_compound_expr (init); } else init = TREE_VALUE (init); } /* We only build this with a null init if we got it from the current_member_init_list. */ if (init || explicit) { decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit); expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init)); } } expand_end_target_temps (); free_temp_slots (); if (TYPE_NEEDS_DESTRUCTOR (type)) { tree expr; /* All cleanups must be on the function_obstack. */ push_obstacks_nochange (); resume_temporary_allocation (); expr = build_component_ref (current_class_ref, name, NULL_TREE, explicit); expr = build_delete (type, expr, integer_zero_node, LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); if (expr != error_mark_node) add_partial_entry (expr); pop_obstacks (); }}extern int warn_reorder;/* Subroutine of emit_member_init. */static treesort_member_init (t) tree t;{ tree x, member, name, field; tree init_list = NULL_TREE; int last_pos = 0; tree last_field = NULL_TREE; for (member = TYPE_FIELDS (t); member ; member = TREE_CHAIN (member)) { int pos; /* member could be, for example, a CONST_DECL for an enumerated tag; we don't want to try to initialize that, since it already has a value. */ if (TREE_CODE (member) != FIELD_DECL || !DECL_NAME (member)) continue; for (x = current_member_init_list, pos = 0; x; x = TREE_CHAIN (x), ++pos) { /* If we cleared this out, then pay no attention to it. */ if (TREE_PURPOSE (x) == NULL_TREE) continue; name = TREE_PURPOSE (x);#if 0 /* This happens in templates, since the IDENTIFIER is replaced with the COMPONENT_REF in tsubst_expr. */ field = (TREE_CODE (name) == COMPONENT_REF ? TREE_OPERAND (name, 1) : IDENTIFIER_CLASS_VALUE (name));#else /* Let's find out when this happens. */ my_friendly_assert (TREE_CODE (name) != COMPONENT_REF, 348); field = IDENTIFIER_CLASS_VALUE (name);#endif /* If one member shadows another, get the outermost one. */ if (TREE_CODE (field) == TREE_LIST) field = TREE_VALUE (field); if (field == member) { if (warn_reorder) { if (pos < last_pos) { cp_warning_at ("member initializers for `%#D'", last_field); cp_warning_at (" and `%#D'", field); warning (" will be re-ordered to match declaration order"); } last_pos = pos; last_field = field; } /* Make sure we won't try to work on this init again. */ TREE_PURPOSE (x) = NULL_TREE; x = build_tree_list (name, TREE_VALUE (x)); goto got_it; } } /* If we didn't find MEMBER in the list, create a dummy entry so the two lists (INIT_LIST and the list of members) will be symmetrical. */ x = build_tree_list (NULL_TREE, NULL_TREE); got_it: init_list = chainon (init_list, x); } /* Initializers for base members go at the end. */ for (x = current_member_init_list ; x ; x = TREE_CHAIN (x)) { name = TREE_PURPOSE (x); if (name) { if (purpose_member (name, init_list)) { cp_error ("multiple initializations given for member `%D'", IDENTIFIER_CLASS_VALUE (name)); continue; } init_list = chainon (init_list, build_tree_list (name, TREE_VALUE (x))); TREE_PURPOSE (x) = NULL_TREE; } } return init_list;}static voidsort_base_init (t, rbase_ptr, vbase_ptr) tree t, *rbase_ptr, *vbase_ptr;{ tree binfos = BINFO_BASETYPES (TYPE_BINFO (t)); int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0; int i; tree x; tree last; /* For warn_reorder. */ int last_pos = 0; tree last_base = NULL_TREE; tree rbases = NULL_TREE; tree vbases = NULL_TREE; /* First walk through and splice out vbase and invalid initializers. Also replace names with binfos. */ last = tree_cons (NULL_TREE, NULL_TREE, current_base_init_list); for (x = TREE_CHAIN (last); x; x = TREE_CHAIN (x)) { tree basetype = TREE_PURPOSE (x); tree binfo = NULL_TREE; if (basetype == NULL_TREE) { /* Initializer for single base class. Must not use multiple inheritance or this is ambiguous. */ switch (n_baseclasses) { case 0: cp_error ("`%T' does not have a base class to initialize", current_class_type); return; case 1: break; default: cp_error ("unnamed initializer ambiguous for `%T' which uses multiple inheritance", current_class_type); return; } binfo = TREE_VEC_ELT (binfos, 0); } else if (is_aggr_type (basetype, 1)) { binfo = binfo_or_else (basetype, 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)) { tree v = CLASSTYPE_VBASECLASSES (t); while (BINFO_TYPE (v) != BINFO_TYPE (binfo)) v = TREE_CHAIN (v); vbases = tree_cons (v, TREE_VALUE (x), vbases); continue; } else { /* 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) { cp_error ("`%T' is not an immediate base class of `%T'", basetype, current_class_type); continue; } } } else my_friendly_abort (365); TREE_PURPOSE (x) = binfo; TREE_CHAIN (last) = x; last = x; } TREE_CHAIN (last) = NULL_TREE; /* Now walk through our regular bases and make sure they're initialized. */ for (i = 0; i < n_baseclasses; ++i)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -