📄 init.c
字号:
/* 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;{ extern tree ptr_type_node; /* should be in tree.h */ tree basetype = NULL_TREE, field; tree parm; tree rval, type; tree actual_name; if (exp == NULL_TREE) return; /* complain about this later */ type = TYPE_MAIN_VARIANT (TREE_TYPE (exp)); 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; } if (init) { /* 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 || IDENTIFIER_HAS_TYPE_VALUE (name)) { tree base_init; if (name == NULL_TREE) {/* if (basetype) name = TYPE_IDENTIFIER (basetype); else { error ("no base class to initialize"); return; }*/ } else { basetype = IDENTIFIER_TYPE_VALUE (name); if (basetype != type && ! binfo_member (basetype, TYPE_BINFO (type)) && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type))) { if (IDENTIFIER_CLASS_VALUE (name)) goto try_member; if (TYPE_USES_VIRTUAL_BASECLASSES (type)) error ("type `%s' is not an immediate or virtual basetype for `%s'", IDENTIFIER_POINTER (name), TYPE_NAME_STRING (type)); else error ("type `%s' is not an immediate basetype for `%s'", IDENTIFIER_POINTER (name), TYPE_NAME_STRING (type)); return; } } if (purpose_member (name, current_base_init_list)) { error ("base class `%s' already initialized", IDENTIFIER_POINTER (name)); return; } base_init = build_tree_list (name, init); TREE_TYPE (base_init) = basetype; 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)) { error ("field `%s' already initialized", IDENTIFIER_POINTER (name)); return; } member_init = build_tree_list (name, init); TREE_TYPE (member_init) = TREE_TYPE (field); current_member_init_list = chainon (current_member_init_list, member_init); } return; } else if (name == NULL_TREE) { compiler_error ("expand_member_init: name == NULL_TREE"); return; } basetype = type; field = lookup_field (basetype, name, 0, 0); if (! member_init_ok_or_else (field, basetype, IDENTIFIER_POINTER (name))) return; /* now see if there is a constructor for this type which will take these args. */ if (TYPE_HAS_CONSTRUCTOR (TREE_TYPE (field))) { tree parmtypes, fndecl; if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL) { /* just know that we've seen something for this node */ DECL_INITIAL (exp) = error_mark_node; TREE_USED (exp) = 1; } type = TYPE_MAIN_VARIANT (TREE_TYPE (field)); actual_name = TYPE_IDENTIFIER (type); parm = build_component_ref (exp, name, 0, 0); /* Now get to the constructor. */ fndecl = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 0); /* Get past destructor, if any. */ if (TYPE_HAS_DESTRUCTOR (type)) fndecl = DECL_CHAIN (fndecl); if (fndecl) my_friendly_assert (TREE_CODE (fndecl) == FUNCTION_DECL, 209); /* If the field is unique, we can use the parameter types to guide possible type instantiation. */ if (DECL_CHAIN (fndecl) == NULL_TREE) { /* There was a confusion here between FIELD and FNDECL. The following code should be correct, but abort is here to make sure. */ my_friendly_abort (48); parmtypes = FUNCTION_ARG_CHAIN (fndecl); } else { parmtypes = NULL_TREE; fndecl = NULL_TREE; } init = convert_arguments (parm, parmtypes, NULL_TREE, fndecl, LOOKUP_NORMAL); if (init == NULL_TREE || TREE_TYPE (init) != error_mark_node) rval = build_method_call (NULL_TREE, actual_name, init, NULL_TREE, LOOKUP_NORMAL); else return; if (rval != error_mark_node) { /* Now, fill in the first parm with our guy */ TREE_VALUE (TREE_OPERAND (rval, 1)) = build_unary_op (ADDR_EXPR, parm, 0); TREE_TYPE (rval) = ptr_type_node; TREE_SIDE_EFFECTS (rval) = 1; } } else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (field))) { parm = build_component_ref (exp, name, 0, 0); expand_aggr_init (parm, NULL_TREE, 0, 0); rval = error_mark_node; } /* Now initialize the member. It does not have to be of aggregate type to receive initialization. */ if (rval != error_mark_node) expand_expr_stmt (rval);}/* 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 C_C_D. 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, alias_this, flags) tree exp, init; int alias_this; 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 (TYPE_READONLY (TREE_TYPE (type)) || TYPE_VOLATILE (TREE_TYPE (type))) { 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 && comptypes (TREE_TYPE (init), TREE_TYPE (exp), 1)); 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, alias_this, LOOKUP_NORMAL|flags); TREE_TYPE (exp) = type; TREE_READONLY (exp) = was_const; TREE_THIS_VOLATILE (exp) = was_volatile;}static voidexpand_default_init (binfo, true_exp, exp, type, init, alias_this, flags) tree binfo; tree true_exp, exp; tree type; tree init; int alias_this; int flags;{ /* It fails because there may not be a constructor which takes its own type as the first (or only parameter), but which does take other types via a conversion. So, if the thing initializing the expression is a unit element of type X, first try X(X&), followed by initialization by X. If neither of these work out, then look hard. */ tree rval; tree parms; if (init == NULL_TREE || (TREE_CODE (init) == TREE_LIST && ! TREE_TYPE (init))) { parms = init; if (parms) init = TREE_VALUE (parms); } else if (TREE_CODE (init) == INDIRECT_REF && TREE_HAS_CONSTRUCTOR (init) && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (init))) { rval = convert_for_initialization (exp, type, init, 0, 0, 0, 0); TREE_USED (rval) = 1; expand_expr_stmt (rval); return; } else parms = build_tree_list (NULL_TREE, init); if (TYPE_USES_VIRTUAL_BASECLASSES (type)) { if (true_exp == exp) parms = tree_cons (NULL_TREE, integer_one_node, parms); else parms = tree_cons (NULL_TREE, integer_zero_node, parms); flags |= LOOKUP_HAS_IN_CHARGE; } if (init && TREE_CHAIN (parms) == NULL_TREE && TYPE_HAS_TRIVIAL_INIT_REF (type) && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (init))) { rval = build (INIT_EXPR, type, exp, init); TREE_SIDE_EFFECTS (rval) = 1; expand_expr_stmt (rval); } else { if (flags & LOOKUP_ONLYCONVERTING) flags |= LOOKUP_NO_CONVERSION; rval = build_method_call (exp, constructor_name_full (type), parms, binfo, flags); /* Private, protected, or otherwise unavailable. */ if (rval == error_mark_node) { if (flags & LOOKUP_COMPLAIN) cp_error ("in base initialization for %sclass `%T'", TREE_VIA_VIRTUAL (binfo) ? "virtual base " : "", binfo); } else if (rval == NULL_TREE) my_friendly_abort (361); else { /* p. 222: if the base class assigns to `this', then that value is used in the derived class. */ if ((flag_this_is_variable & 1) && alias_this) { TREE_TYPE (rval) = TREE_TYPE (current_class_decl); expand_assignment (current_class_decl, rval, 0, 0); } else expand_expr_stmt (rval); } }}/* This function is responsible for initializing EXP with INIT (if any). BINFO is the binfo of the type for who we are performing the initialization. For example, if W is a virtual base class of A and B, and C : A, B. If we are initializing B, then W must contain B's W vtable, whereas were we initializing C, W must contain C's W vtable. TRUE_EXP is nonzero if it is the true expression being initialized. In this case, it may be EXP, or may just contain EXP. The reason we need this is because if EXP is a base element of TRUE_EXP, we don't necessarily know by looking at EXP where its virtual baseclass fields should really be pointing. But we do know from TRUE_EXP. In constructors, we don't know anything about the value being initialized. ALIAS_THIS serves the same purpose it serves for expand_aggr_init.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -