📄 cp-init.c
字号:
expand_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"); error_with_aggr_type (type, "(type `%s' uses multiple inheritance)"); 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); 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 a CONSTRUCTOR, then we emit a warning message, explaining that such initializations are illegal. 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) tree exp, init; int alias_this;{ tree type = TREE_TYPE (exp); int was_const = TREE_READONLY (exp); if (init == error_mark_node) return; TREE_READONLY (exp) = 0; if (TREE_CODE (type) == ARRAY_TYPE) { /* Must arrange to initialize each element of EXP from elements of INIT. */ int was_const_elts = TYPE_READONLY (TREE_TYPE (type)); tree itype = init ? TREE_TYPE (init) : NULL_TREE; if (was_const_elts) { tree atype = build_cplus_array_type (TYPE_MAIN_VARIANT (TREE_TYPE (type)), TYPE_DOMAIN (type)); if (init && (TREE_TYPE (exp) == TREE_TYPE (init))) TREE_TYPE (init) = atype; TREE_TYPE (exp) = atype; } 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_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 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); expand_aggr_init_1 (TYPE_BINFO (type), exp, exp, init, alias_this, LOOKUP_NORMAL); TREE_READONLY (exp) = was_const;}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; int xxref_init_possible; if (init == NULL_TREE || TREE_CODE (init) == TREE_LIST) { parms = init; if (parms) init = TREE_VALUE (parms); } else if (TREE_CODE (init) == INDIRECT_REF && TREE_HAS_CONSTRUCTOR (init)) { convert_for_initialization (exp, type, init, 0, 0, 0, 0); expand_expr_stmt (TREE_OPERAND (init, 0)); return; } else parms = build_tree_list (NULL_TREE, init); if (TYPE_HAS_INIT_REF (type) || init == NULL_TREE || TREE_CHAIN (parms) != NULL_TREE) xxref_init_possible = 0; else { xxref_init_possible = LOOKUP_SPECULATIVELY; flags &= ~LOOKUP_COMPLAIN; } 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; } /* ARM $7.1.1: "[register] may be ignored and in most implementations it will be ignored if the address of the variable is taken." Since we're likely to do just that in the ctor call, clear this. */ DECL_REGISTER (exp) = 0; rval = build_method_call (exp, constructor_name (type), parms, binfo, flags|xxref_init_possible); if (rval == NULL_TREE && xxref_init_possible) { /* It is an error to implement a default copy constructor if (see ARM 12.8 for details) ... one case being if another copy constructor already exists. */ tree init_type = TREE_TYPE (init); if (TREE_CODE (init_type) == REFERENCE_TYPE) init_type = TREE_TYPE (init_type); if (TYPE_MAIN_VARIANT (init_type) == TYPE_MAIN_VARIANT (type) || (IS_AGGR_TYPE (init_type) && UNIQUELY_DERIVED_FROM_P (type, init_type))) { if (type == BINFO_TYPE (binfo) && TYPE_USES_VIRTUAL_BASECLASSES (type)) { tree addr = build_unary_op (ADDR_EXPR, exp, 0); expand_aggr_vbase_init (binfo, exp, addr, NULL_TREE); expand_expr_stmt (build_vbase_vtables_init (binfo, binfo, exp, addr, 1)); } expand_expr_stmt (build_modify_expr (exp, INIT_EXPR, init)); return; } else rval = build_method_call (exp, constructor_name (type), parms, binfo, flags); } /* Private, protected, or otherwise unavailable. */ if (rval == error_mark_node && (flags&LOOKUP_COMPLAIN)) error_with_aggr_type (binfo, "in base initialization for class `%s'"); /* A valid initialization using constructor. */ else if (rval != error_mark_node && rval != NULL_TREE) { /* 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); } else if (parms && TREE_CHAIN (parms) == NULL_TREE) { /* If we are initializing one aggregate value from another, and though there are constructors, and none accept the initializer, just do a bitwise copy. The above sounds wrong, ``If a class has any copy constructor defined, the default copy constructor will not be generated.'' 12.8 Copying Class Objects (mrs) @@ This should reject initializer which a constructor @@ rejected on visibility gounds, but there is @@ no way right now to recognize that case with @@ just `error_mark_node'. */ tree itype; init = TREE_VALUE (parms); itype = TREE_TYPE (init); if (TREE_CODE (itype) == REFERENCE_TYPE) { init = convert_from_reference (init); itype = TREE_TYPE (init); } itype = TYPE_MAIN_VARIANT (itype); /* This is currently how the default X(X&) constructor is implemented. */ if (comptypes (TYPE_MAIN_VARIANT (type), itype, 0)) {#if 0 warning ("bitwise copy in initialization of type `%s'", TYPE_NAME_STRING (type));#endif rval = build (INIT_EXPR, type, exp, init); expand_expr_stmt (rval); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -