📄 init.c
字号:
/* Increment vlist by number of base's vbase classes. */ expr = build_int_2 (pvbasecount (BINFO_TYPE (binfo), 0), 0); expr = build_binary_op (PLUS_EXPR, vlist, expr); expr = build_modify_expr (vlist, NOP_EXPR, expr); expand_expr_stmt (expr); }}/* Subroutine of `expand_aggr_vbase_init'. BINFO is the binfo of the type that is being initialized. INIT_LIST is the list of initializers for the virtual baseclass. */static voidexpand_aggr_vbase_init_1 (binfo, exp, addr, init_list) tree binfo, exp, addr, init_list;{ tree init = purpose_member (binfo, init_list); tree ref = build_indirect_ref (addr, NULL_PTR); expand_start_target_temps (); if (init) init = TREE_VALUE (init); /* Call constructors, but don't set up vtables. */ expand_aggr_init_1 (binfo, exp, ref, init, LOOKUP_COMPLAIN); expand_end_target_temps (); free_temp_slots ();}/* Construct the virtual base-classes of THIS_REF (whose address is THIS_PTR). The object has the indicated TYPE. The construction actually takes place only if FLAG is non-zero. INIT_LIST is list of initialization for constructor to perform. */static voidconstruct_virtual_bases (type, this_ref, this_ptr, init_list, flag) tree type; tree this_ref; tree this_ptr; tree init_list; tree flag;{ tree vbases; tree result; tree vlist = NULL_TREE; /* If there are no virtual baseclasses, we shouldn't even be here. */ my_friendly_assert (TYPE_USES_VIRTUAL_BASECLASSES (type), 19990621); /* First set the pointers in our object that tell us where to find our virtual baseclasses. */ expand_start_cond (flag, 0); if (TYPE_USES_PVBASES (type)) { init_vlist (type); vlist = lookup_name (vlist_identifier, 0); } result = init_vbase_pointers (type, this_ptr); if (result) expand_expr_stmt (build_compound_expr (result)); expand_end_cond (); /* Now, run through the baseclasses, initializing each. */ for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; vbases = TREE_CHAIN (vbases)) { tree tmp = purpose_member (vbases, result); /* If there are virtual base classes with destructors, we need to emit cleanups to destroy them if an exception is thrown during the construction process. These exception regions (i.e., the period during which the cleanups must occur) begin from the time the construction is complete to the end of the function. If we create a conditional block in which to initialize the base-classes, then the cleanup region for the virtual base begins inside a block, and ends outside of that block. This situation confuses the sjlj exception-handling code. Therefore, we do not create a single conditional block, but one for each initialization. (That way the cleanup regions always begin in the outer block.) We trust the back-end to figure out that the FLAG will not change across initializations, and avoid doing multiple tests. */ expand_start_cond (flag, 0); expand_aggr_vbase_init_1 (vbases, this_ref, TREE_OPERAND (TREE_VALUE (tmp), 0), init_list); expand_end_cond (); expand_cleanup_for_base (vbases, vlist, flag); }}/* Find the context in which this FIELD can be initialized. */static treeinitializing_context (field) tree field;{ tree t = DECL_CONTEXT (field); /* Anonymous union members can be initialized in the first enclosing non-anonymous union context. */ while (t && ANON_UNION_TYPE_P (t)) t = TYPE_CONTEXT (t); return t;}/* Function to give error message if member initialization specification is erroneous. FIELD is the member we decided to initialize. TYPE is the type for which the initialization is being performed. FIELD must be a member of TYPE. MEMBER_NAME is the name of the member. */static intmember_init_ok_or_else (field, type, member_name) tree field; tree type; const char *member_name;{ if (field == error_mark_node) return 0; if (field == NULL_TREE || initializing_context (field) != type) { cp_error ("class `%T' does not have any field named `%s'", type, member_name); return 0; } if (TREE_STATIC (field)) { cp_error ("field `%#D' is static; only point of initialization is its declaration", field); return 0; } return 1;}/* If NAME is a viable field name for the aggregate DECL, and PARMS is a viable parameter list, then expand an _EXPR which describes this initialization. Note that we do not need to chase through the class's base classes to look for NAME, because if it's in that list, it will be handled by the constructor for that base class. We do not yet have a fixed-point finder to instantiate types being fed to overloaded constructors. If there is a unique constructor, then argument types can be got from that one. If INIT is non-NULL, then it the initialization should be placed in `current_base_init_list', where it will be processed by `emit_base_init'. */voidexpand_member_init (exp, name, init) tree exp, name, init;{ tree basetype = NULL_TREE, field; tree type; if (exp == NULL_TREE) return; /* complain about this later */ type = TYPE_MAIN_VARIANT (TREE_TYPE (exp)); if (name && TREE_CODE (name) == TYPE_DECL) { basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name)); name = DECL_NAME (name); } if (name == NULL_TREE && IS_AGGR_TYPE (type)) switch (CLASSTYPE_N_BASECLASSES (type)) { case 0: error ("base class initializer specified, but no base class to initialize"); return; case 1: basetype = TYPE_BINFO_BASETYPE (type, 0); break; default: error ("initializer for unnamed base class ambiguous"); cp_error ("(type `%T' uses multiple inheritance)", type); return; } my_friendly_assert (init != NULL_TREE, 0); /* The grammar should not allow fields which have names that are TYPENAMEs. Therefore, if the field has a non-NULL TREE_TYPE, we may assume that this is an attempt to initialize a base class member of the current type. Otherwise, it is an attempt to initialize a member field. */ if (init == void_type_node) init = NULL_TREE; if (name == NULL_TREE || basetype) { tree base_init; if (name == NULL_TREE) {#if 0 if (basetype) name = TYPE_IDENTIFIER (basetype); else { error ("no base class to initialize"); return; }#endif } else if (basetype != type && ! current_template_parms && ! vec_binfo_member (basetype, TYPE_BINFO_BASETYPES (type)) && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type))) { if (IDENTIFIER_CLASS_VALUE (name)) goto try_member; if (TYPE_USES_VIRTUAL_BASECLASSES (type)) cp_error ("type `%T' is not an immediate or virtual basetype for `%T'", basetype, type); else cp_error ("type `%T' is not an immediate basetype for `%T'", basetype, type); return; } if (purpose_member (basetype, current_base_init_list)) { cp_error ("base class `%T' already initialized", basetype); return; } if (warn_reorder && current_member_init_list) { cp_warning ("base initializer for `%T'", basetype); warning (" will be re-ordered to precede member initializations"); } base_init = build_tree_list (basetype, init); current_base_init_list = chainon (current_base_init_list, base_init); } else { tree member_init; try_member: field = lookup_field (type, name, 1, 0); if (! member_init_ok_or_else (field, type, IDENTIFIER_POINTER (name))) return; if (purpose_member (name, current_member_init_list)) { cp_error ("field `%D' already initialized", field); return; } member_init = build_tree_list (name, init); current_member_init_list = chainon (current_member_init_list, member_init); }}/* This is like `expand_member_init', only it stores one aggregate value into another. INIT comes in two flavors: it is either a value which is to be stored in EXP, or it is a parameter list to go to a constructor, which will operate on EXP. If INIT is not a parameter list for a constructor, then set LOOKUP_ONLYCONVERTING. If FLAGS is LOOKUP_ONLYCONVERTING then it is the = init form of the initializer, if FLAGS is 0, then it is the (init) form. If `init' is a CONSTRUCTOR, then we emit a warning message, explaining that such initializations are invalid. ALIAS_THIS is nonzero iff we are initializing something which is essentially an alias for current_class_ref. In this case, the base constructor may move it on us, and we must keep track of such deviations. If INIT resolves to a CALL_EXPR which happens to return something of the type we are looking for, then we know that we can safely use that call to perform the initialization. The virtual function table pointer cannot be set up here, because we do not really know its type. Virtual baseclass pointers are also set up here. This never calls operator=(). When initializing, nothing is CONST. A default copy constructor may have to be used to perform the initialization. A constructor or a conversion operator may have to be used to perform the initialization, but not both, as it would be ambiguous. */voidexpand_aggr_init (exp, init, flags) tree exp, init; int flags;{ tree type = TREE_TYPE (exp); int was_const = TREE_READONLY (exp); int was_volatile = TREE_THIS_VOLATILE (exp); if (init == error_mark_node) return; TREE_READONLY (exp) = 0; TREE_THIS_VOLATILE (exp) = 0; if (init && TREE_CODE (init) != TREE_LIST) flags |= LOOKUP_ONLYCONVERTING; if (TREE_CODE (type) == ARRAY_TYPE) { /* Must arrange to initialize each element of EXP from elements of INIT. */ tree itype = init ? TREE_TYPE (init) : NULL_TREE; if (CP_TYPE_QUALS (type) != TYPE_UNQUALIFIED) { TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type); if (init) TREE_TYPE (init) = TYPE_MAIN_VARIANT (itype); } if (init && TREE_TYPE (init) == NULL_TREE) { /* Handle bad initializers like: class COMPLEX { public: double re, im; COMPLEX(double r = 0.0, double i = 0.0) {re = r; im = i;}; ~COMPLEX() {}; }; int main(int argc, char **argv) { COMPLEX zees(1.0, 0.0)[10]; } */ error ("bad array initializer"); return; } expand_vec_init (exp, exp, array_type_nelts (type), init, init && same_type_p (TREE_TYPE (init), TREE_TYPE (exp))); TREE_READONLY (exp) = was_const; TREE_THIS_VOLATILE (exp) = was_volatile; TREE_TYPE (exp) = type; if (init) TREE_TYPE (init) = itype; return; } if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL) /* just know that we've seen something for this node */ TREE_USED (exp) = 1;#if 0 /* If initializing from a GNU C CONSTRUCTOR, consider the elts in the constructor as parameters to an implicit GNU C++ constructor. */ if (init && TREE_CODE (init) == CONSTRUCTOR && TYPE_HAS_CONSTRUCTOR (type) && TREE_TYPE (init) == type) init = CONSTRUCTOR_ELTS (init);#endif TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type); expand_aggr_init_1 (TYPE_BINFO (type), exp, exp, init, LOOKUP_NORMAL|flags); TREE_TYPE (exp) = type; TREE_READONLY (exp) = was_const; TREE_THIS_VOLATILE (exp) = was_volatile;}static treeno_vlist_base_init (rval, exp, init, binfo, flags) tree rval, exp, init, binfo; int flags;{ tree nrval, func, parms; /* Obtain the vlist-expecting ctor. */ func = rval; my_friendly_assert (TREE_CODE (func) == CALL_EXPR, 20000131); func = TREE_OPERAND (func, 0); my_friendly_assert (TREE_CODE (func) == ADDR_EXPR, 20000132); func = TREE_OPERAND (func, 0); my_friendly_assert (TREE_CODE (func) == FUNCTION_DECL, 20000133); /* If we have already seen a definition for the wrapped function, we don't need to declare it weak. Also, declare_weak will complain if we do. */ if (!TREE_ASM_WRITTEN (func)) declare_weak (func); if (init == NULL_TREE || (TREE_CODE (init) == TREE_LIST && ! TREE_TYPE (init))) { parms = init; if (parms) init = TREE_VALUE (parms); } else parms = build_expr_list (NULL_TREE, init); flags &= ~LOOKUP_HAS_VLIST; parms = expr_tree_cons (NULL_TREE, integer_zero_node, parms); flags |= LOOKUP_HAS_IN_CHARGE; nrval = build_method_call (exp, ctor_identifier, parms, binfo, flags); func = build (NE_EXPR, boolean_type_node, func, null_pointer_node); nrval = build (COND_EXPR, void_type_node, func, rval, nrval); return nrval;} static voidexpand_default_init (binfo, true_exp, exp, init, flags) tree binfo; tree true_exp, exp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -