📄 init.c
字号:
{ tree base_binfo = TREE_VEC_ELT (binfos, i); int pos; if (TREE_VIA_VIRTUAL (base_binfo)) continue; for (x = current_base_init_list, pos = 0; x; x = TREE_CHAIN (x), ++pos) { tree binfo = TREE_PURPOSE (x); if (binfo == NULL_TREE) continue; if (binfo == base_binfo) { if (warn_reorder) { if (pos < last_pos) { cp_warning_at ("base initializers for `%#T'", last_base); cp_warning_at (" and `%#T'", BINFO_TYPE (binfo)); warning (" will be re-ordered to match inheritance order"); } last_pos = pos; last_base = BINFO_TYPE (binfo); } /* Make sure we won't try to work on this init again. */ TREE_PURPOSE (x) = NULL_TREE; x = build_tree_list (binfo, TREE_VALUE (x)); goto got_it; } } /* If we didn't find BASE_BINFO in the list, create a dummy entry so the two lists (RBASES and the list of bases) will be symmetrical. */ x = build_tree_list (NULL_TREE, NULL_TREE); got_it: rbases = chainon (rbases, x); } *rbase_ptr = rbases; *vbase_ptr = vbases;}/* Invoke a base-class destructor. REF is the object being destroyed, BINFO is the base class, and DTOR_ARG indicates whether the base class should invoke delete. */treebuild_base_dtor_call (ref, binfo, dtor_arg) tree ref, binfo, dtor_arg;{ tree args = NULL_TREE; tree vlist = lookup_name (vlist_identifier, 0); tree call, decr; if (TYPE_USES_PVBASES (BINFO_TYPE (binfo))) { args = expr_tree_cons (NULL_TREE, vlist, args); dtor_arg = build (BIT_IOR_EXPR, integer_type_node, dtor_arg, build_int_2 (4, 0)); dtor_arg = fold (dtor_arg); } args = expr_tree_cons (NULL_TREE, dtor_arg, args); call = build_scoped_method_call (ref, binfo, dtor_identifier, args); if (!TYPE_USES_PVBASES (BINFO_TYPE (binfo))) /* For plain inheritance, do not try to adjust __vlist. */ return call; /* Now decrement __vlist by the number of slots consumed by the base dtor. */ decr = build_int_2 (pvbasecount (BINFO_TYPE (binfo), 0), 0); decr = build_binary_op (MINUS_EXPR, vlist, decr); decr = build_modify_expr (vlist, NOP_EXPR, decr); return build (COMPOUND_EXPR, void_type_node, call, decr);}/* Return the number of vlist entries needed to initialize TYPE, depending on whether it is IN_CHARGE. */static intpvbasecount (type, in_charge) tree type; int in_charge;{ int i; int result = 0; tree vbase; for (vbase = (CLASSTYPE_VBASECLASSES (type)); vbase; vbase = TREE_CHAIN (vbase)) { result += list_length (CLASSTYPE_VFIELDS (BINFO_TYPE (vbase))); if (in_charge) result += pvbasecount (BINFO_TYPE (vbase), 0); } for (i=0; i < CLASSTYPE_N_BASECLASSES (type); i++) { tree base = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), i); if (TREE_VIA_VIRTUAL (base)) continue; result += pvbasecount (BINFO_TYPE (base), 0); } return result;}voidinit_vlist (t) tree t;{ char *name; tree expr; tree vlist = lookup_name (vlist_identifier, 0); name = alloca (strlen (VLIST_NAME_FORMAT) + TYPE_ASSEMBLER_NAME_LENGTH (t) + 2); sprintf (name, VLIST_NAME_FORMAT, TYPE_ASSEMBLER_NAME_STRING (t)); expr = get_identifier (name); expr = lookup_name (expr, 0); expr = build1 (ADDR_EXPR, TREE_TYPE (vlist), expr); if (DECL_DESTRUCTOR_FOR_PVBASE_P (current_function_decl)) /* Move to the end of the vlist. */ expr = build_binary_op (PLUS_EXPR, expr, build_int_2 (pvbasecount (t, 1), 0)); expand_expr_stmt (build_modify_expr (vlist, NOP_EXPR, expr));}/* Perform whatever initializations 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_EXPR. 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. */extern tree base_init_expr, rtl_expr_chain;voidemit_base_init (t, immediately) tree t; int immediately;{ tree member; tree mem_init_list; 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 expr = NULL_TREE; tree vlist = lookup_name (vlist_identifier, 0); if (! immediately) { int momentary; do_pending_stack_adjust (); /* Make the RTL_EXPR node temporary, not momentary, so that rtl_expr_chain doesn't become garbage. */ momentary = suspend_momentary (); expr = make_node (RTL_EXPR); resume_momentary (momentary); start_sequence_for_rtl_expr (expr); } 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)); mem_init_list = sort_member_init (t); current_member_init_list = NULL_TREE; sort_base_init (t, &rbase_init_list, &vbase_init_list); current_base_init_list = NULL_TREE; /* First, initialize the virtual base classes, if we are constructing the most-derived object. */ if (TYPE_USES_VIRTUAL_BASECLASSES (t)) { tree first_arg = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl)); construct_virtual_bases (t, current_class_ref, current_class_ptr, vbase_init_list, first_arg); } /* Now, perform initialization of non-virtual base classes. */ for (i = 0; i < n_baseclasses; i++) { tree base_binfo = TREE_VEC_ELT (binfos, i); tree init = void_list_node; if (TREE_VIA_VIRTUAL (base_binfo)) continue; my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo, 999); if (TREE_PURPOSE (rbase_init_list)) init = TREE_VALUE (rbase_init_list); else if (TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (base_binfo))) { init = NULL_TREE; if (extra_warnings && copy_args_p (current_function_decl)) cp_warning ("base class `%#T' should be explicitly initialized in the copy constructor", BINFO_TYPE (base_binfo)); } if (init != void_list_node) { expand_start_target_temps (); member = convert_pointer_to_real (base_binfo, current_class_ptr); expand_aggr_init_1 (base_binfo, NULL_TREE, build_indirect_ref (member, NULL_PTR), init, LOOKUP_NORMAL); expand_end_target_temps (); free_temp_slots (); } expand_cleanup_for_base (base_binfo, vlist, NULL_TREE); rbase_init_list = TREE_CHAIN (rbase_init_list); } /* Initialize all the virtual function table fields that do come from virtual base classes. */ if (TYPE_USES_VIRTUAL_BASECLASSES (t)) expand_indirect_vtbls_init (t_binfo, current_class_ref, current_class_ptr); /* Initialize all the virtual function table fields that do not come from virtual base classes. */ expand_direct_vtbls_init (t_binfo, t_binfo, 1, 1, current_class_ptr); for (member = TYPE_FIELDS (t); member; member = TREE_CHAIN (member)) { tree init, name; int from_init_list; /* 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; /* See if we had a user-specified member initialization. */ if (TREE_PURPOSE (mem_init_list)) { name = TREE_PURPOSE (mem_init_list); init = TREE_VALUE (mem_init_list); from_init_list = 1;#if 0 if (TREE_CODE (name) == COMPONENT_REF) name = DECL_NAME (TREE_OPERAND (name, 1));#else /* Also see if it's ever a COMPONENT_REF here. If it is, we need to do `expand_assignment (name, init, 0, 0);' and a continue. */ my_friendly_assert (TREE_CODE (name) != COMPONENT_REF, 349);#endif } else { name = DECL_NAME (member); init = DECL_INITIAL (member); from_init_list = 0; /* Effective C++ rule 12. */ if (warn_ecpp && init == NULL_TREE && !DECL_ARTIFICIAL (member) && TREE_CODE (TREE_TYPE (member)) != ARRAY_TYPE) cp_warning ("`%D' should be initialized in the member initialization list", member); } perform_member_init (member, name, init, from_init_list); mem_init_list = TREE_CHAIN (mem_init_list); } /* Now initialize any members from our bases. */ while (mem_init_list) { tree name, init, field; if (TREE_PURPOSE (mem_init_list)) { name = TREE_PURPOSE (mem_init_list); init = TREE_VALUE (mem_init_list); /* XXX: this may need the COMPONENT_REF operand 0 check if it turns out we actually get them. */ field = IDENTIFIER_CLASS_VALUE (name); /* If one member shadows another, get the outermost one. */ if (TREE_CODE (field) == TREE_LIST) { field = TREE_VALUE (field); if (decl_type_context (field) != current_class_type) cp_error ("field `%D' not in immediate context", field); }#if 0 /* It turns out if you have an anonymous union in the class, a member from it can end up not being on the list of fields (rather, the type is), and therefore won't be seen by the for loop above. */ /* The code in this for loop is derived from a general loop which had this check in it. Theoretically, we've hit every initialization for the list of members in T, so we shouldn't have anything but these left in this list. */ my_friendly_assert (DECL_FIELD_CONTEXT (field) != t, 351);#endif perform_member_init (field, name, init, 1); } mem_init_list = TREE_CHAIN (mem_init_list); } if (! immediately) { do_pending_stack_adjust (); my_friendly_assert (base_init_expr == 0, 207); base_init_expr = expr; TREE_TYPE (expr) = void_type_node; RTL_EXPR_RTL (expr) = const0_rtx; RTL_EXPR_SEQUENCE (expr) = get_insns (); rtl_expr_chain = tree_cons (NULL_TREE, expr, rtl_expr_chain); end_sequence (); TREE_SIDE_EFFECTS (expr) = 1; } /* All the implicit try blocks we built up will be zapped when we come to a real binding contour boundary. */}/* Check that all fields are properly initialized after an assignment to `this'. */voidcheck_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 the pointer DECL. It is a one-ply initialization. BINFO is the exact type that DECL is supposed to be. In multiple inheritance, this might mean "C's A" if C : A, B. */static voidexpand_virtual_init (binfo, decl) tree binfo, decl;{ tree type = BINFO_TYPE (binfo); tree vtbl, vtbl_ptr; tree vtype, vtype_binfo; /* This code is crusty. Should be simple, like: vtbl = BINFO_VTABLE (binfo); */ vtype = DECL_CONTEXT (CLASSTYPE_VFIELD (type)); vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0); vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (CLASSTYPE_VFIELD (type)), binfo)); assemble_external (vtbl); TREE_USED (vtbl) = 1; vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl); decl = convert_pointer_to_real (vtype_binfo, decl); vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL_PTR), vtype); if (vtbl_ptr == error_mark_node) return; /* Have to convert VTBL since array sizes may be different. */ vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0); expand_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl));}/* If an exception is thrown in a constructor, those base classes already constructed must be destroyed. This function creates the cleanup for BINFO, which has just been constructed. If FLAG is non-NULL, it is a DECL which is non-zero when this base needs to be destroyed. */static voidexpand_cleanup_for_base (binfo, vlist, flag) tree binfo; tree vlist; tree flag;{ tree expr; if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo))) { /* All cleanups must be on the function_obstack. */ push_obstacks_nochange (); resume_temporary_allocation (); /* Call the destructor. */ expr = build_base_dtor_call (current_class_ref, binfo, integer_zero_node); if (flag) expr = fold (build (COND_EXPR, void_type_node, truthvalue_conversion (flag), expr, integer_zero_node)); pop_obstacks (); add_partial_entry (expr); } if (TYPE_USES_PVBASES (BINFO_TYPE (binfo))) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -