📄 cp-init.c
字号:
error_with_aggr_type (binfo, "in base initialization for class `%s',"); error_with_aggr_type (type, "invalid initializer to constructor for type `%s'"); return; } } else { if (init == NULL_TREE) my_friendly_assert (parms == NULL_TREE, 210); if (parms == NULL_TREE && TREE_VIA_VIRTUAL (binfo)) error_with_aggr_type (binfo, "virtual baseclass `%s' does not have default initializer"); else { error_with_aggr_type (binfo, "in base initialization for class `%s',"); /* This will make an error message for us. */ build_method_call (exp, constructor_name (type), parms, binfo, (TYPE_USES_VIRTUAL_BASECLASSES (type) ? LOOKUP_NORMAL|LOOKUP_HAS_IN_CHARGE : LOOKUP_NORMAL)); } return; } /* Constructor has been called, but vtables may be for TYPE rather than for FOR_TYPE. */}/* 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. FLAGS is just passes to `build_method_call'. See that function for its description. */static voidexpand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags) tree binfo; tree true_exp, exp; tree init; int alias_this; int flags;{ tree type = TREE_TYPE (exp); tree init_type = NULL_TREE; tree rval; my_friendly_assert (init != error_mark_node && type != error_mark_node, 211); /* Use a function returning the desired type to initialize EXP for us. If the function is a constructor, and its first argument is NULL_TREE, know that it was meant for us--just slide exp on in and expand the constructor. Constructors now come as TARGET_EXPRs. */ if (init) { tree init_list = NULL_TREE; if (TREE_CODE (init) == TREE_LIST) { init_list = init; if (TREE_CHAIN (init) == NULL_TREE) init = TREE_VALUE (init); } init_type = TREE_TYPE (init); if (TREE_CODE (init) != TREE_LIST) { if (TREE_CODE (init_type) == ERROR_MARK) return;#if 0 /* These lines are found troublesome 5/11/89. */ if (TREE_CODE (init_type) == REFERENCE_TYPE) init_type = TREE_TYPE (init_type);#endif /* This happens when we use C++'s functional cast notation. If the types match, then just use the TARGET_EXPR directly. Otherwise, we need to create the initializer separately from the object being initialized. */ if (TREE_CODE (init) == TARGET_EXPR) { if (init_type == type) { if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == RESULT_DECL) /* Unify the initialization targets. */ DECL_RTL (TREE_OPERAND (init, 0)) = DECL_RTL (exp); else DECL_RTL (TREE_OPERAND (init, 0)) = expand_expr (exp, 0, 0, 0); expand_expr_stmt (init); return; } else { init = TREE_OPERAND (init, 1); init = build (CALL_EXPR, init_type, TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), 0); TREE_SIDE_EFFECTS (init) = 1;#if 0 TREE_RAISES (init) = ??#endif if (init_list) TREE_VALUE (init_list) = init; } } if (init_type == type && TREE_CODE (init) == CALL_EXPR#if 0 /* It is legal to directly initialize from a CALL_EXPR without going through X(X&), apparently. */ && ! TYPE_GETS_INIT_REF (type)#endif ) { /* A CALL_EXPR is a legitimate form of initialization, so we should not print this warning message. */#if 0 /* Should have gone away due to 5/11/89 change. */ if (TREE_CODE (TREE_TYPE (init)) == REFERENCE_TYPE) init = convert_from_reference (init);#endif expand_assignment (exp, init, 0, 0); if (exp == DECL_RESULT (current_function_decl)) { /* Failing this assertion means that the return value from receives multiple initializations. */ my_friendly_assert (DECL_INITIAL (exp) == NULL_TREE || DECL_INITIAL (exp) == error_mark_node, 212); DECL_INITIAL (exp) = init; } return; } else if (init_type == type && TREE_CODE (init) == COND_EXPR) { /* Push value to be initialized into the cond, where possible. Avoid spurious warning messages when initializing the result of this function. */ TREE_OPERAND (init, 1) = build_modify_expr (exp, INIT_EXPR, TREE_OPERAND (init, 1)); if (exp == DECL_RESULT (current_function_decl)) DECL_INITIAL (exp) = NULL_TREE; TREE_OPERAND (init, 2) = build_modify_expr (exp, INIT_EXPR, TREE_OPERAND (init, 2)); if (exp == DECL_RESULT (current_function_decl)) DECL_INITIAL (exp) = init; expand_expr (init, const0_rtx, VOIDmode, 0); free_temp_slots (); return; } } /* We did not know what we were initializing before. Now we do. */ if (TREE_CODE (init) == TARGET_EXPR) { tree tmp = TREE_OPERAND (TREE_OPERAND (init, 1), 1); if (TREE_CODE (TREE_VALUE (tmp)) == NOP_EXPR && TREE_OPERAND (TREE_VALUE (tmp), 0) == integer_zero_node) { /* In order for this to work for RESULT_DECLs, if their type has a constructor, then they must be BLKmode so that they will be meaningfully addressable. */ tree arg = build_unary_op (ADDR_EXPR, exp, 0); init = TREE_OPERAND (init, 1); init = build (CALL_EXPR, build_pointer_type (TREE_TYPE (init)), TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), 0); TREE_SIDE_EFFECTS (init) = 1;#if 0 TREE_RAISES (init) = ??#endif TREE_VALUE (TREE_OPERAND (init, 1)) = convert_pointer_to (TREE_TYPE (TREE_TYPE (TREE_VALUE (tmp))), arg); if (alias_this) { expand_assignment (current_function_decl, init, 0, 0); return; } if (exp == DECL_RESULT (current_function_decl)) { if (DECL_INITIAL (DECL_RESULT (current_function_decl))) fatal ("return value from function receives multiple initializations"); DECL_INITIAL (exp) = init; } expand_expr_stmt (init); return; } } /* Handle this case: when calling a constructor: xyzzy foo(bar); which really means: xyzzy foo = bar; Ugh! We can also be called with an initializer for an object which has virtual functions, but no constructors. In that case, we perform the assignment first, then initialize the virtual function table pointer fields. */ if (! TYPE_NEEDS_CONSTRUCTING (type)) { if (init_list && TREE_CHAIN (init_list)) { warning ("initializer list being treated as compound expression"); init = convert (TREE_TYPE (exp), build_compound_expr (init_list)); if (init == error_mark_node) return; } if (TREE_CODE (exp) == VAR_DECL && TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init) && flag_pic == 0) store_init_value (exp, init); else expand_assignment (exp, init, 0, 0); if (TYPE_VIRTUAL_P (type)) expand_recursive_init (binfo, true_exp, exp, init, CLASSTYPE_BASE_INIT_LIST (type), alias_this); return; } /* See whether we can go through a type conversion operator. This wins over going through a non-existent constructor. If there is a constructor, it is ambiguous. */ if (TREE_CODE (init) != TREE_LIST) { tree ttype = TREE_CODE (init_type) == REFERENCE_TYPE ? TREE_TYPE (init_type) : init_type; if (ttype != type && IS_AGGR_TYPE (ttype)) { tree rval = build_type_conversion (CONVERT_EXPR, type, init, 0); if (rval) { /* See if there is a constructor for``type'' that takes a ``ttype''-typed object. */ tree parms = build_tree_list (NULL_TREE, init); tree as_cons = NULL_TREE; if (TYPE_HAS_CONSTRUCTOR (type)) as_cons = build_method_call (exp, constructor_name (type), parms, binfo, LOOKUP_SPECULATIVELY); if (as_cons != NULL_TREE && as_cons != error_mark_node) { tree name = TYPE_NAME (type); if (TREE_CODE (name) == TYPE_DECL) name = DECL_NAME (name); /* ANSI C++ June 5 1992 WP 12.3.2.6.1 */ error ("ambiguity between conversion to `%s' and constructor", IDENTIFIER_POINTER (name)); } else expand_assignment (exp, rval, 0, 0); return; } } } } /* Handle default copy constructors here, does not matter if there is a constructor or not. */ if (type == init_type && IS_AGGR_TYPE (type) && init && TREE_CODE (init) != TREE_LIST) expand_default_init (binfo, true_exp, exp, type, init, alias_this, flags); /* Not sure why this is here... */ else if (TYPE_HAS_CONSTRUCTOR (type)) expand_default_init (binfo, true_exp, exp, type, init, alias_this, flags); else if (TREE_CODE (type) == ARRAY_TYPE) { if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (type))) expand_vec_init (exp, exp, array_type_nelts (type), init, 0); else if (TYPE_VIRTUAL_P (TREE_TYPE (type))) sorry ("arrays of objects with virtual functions but no constructors"); } else expand_recursive_init (binfo, true_exp, exp, init, CLASSTYPE_BASE_INIT_LIST (type), alias_this);}/* A pointer which holds the initializer. First call to expand_aggr_init gets this value pointed to, and sets it to init_null. */static tree *init_ptr, init_null;/* Subroutine of expand_recursive_init: ADDR is the address of the expression being initialized. INIT_LIST is the cons-list of initializations to be performed. ALIAS_THIS is its same, lovable self. */static voidexpand_recursive_init_1 (binfo, true_exp, addr, init_list, alias_this) tree binfo, true_exp, addr; tree init_list; int alias_this;{ while (init_list) { if (TREE_PURPOSE (init_list)) { if (TREE_CODE (TREE_PURPOSE (init_list)) == FIELD_DECL) { tree member = TREE_PURPOSE (init_list); tree subexp = build_indirect_ref (convert_pointer_to (TREE_VALUE (init_list), addr), 0); tree member_base = build (COMPONENT_REF, TREE_TYPE (member), subexp, member); if (IS_AGGR_TYPE (TREE_TYPE (member))) expand_aggr_init (member_base, DECL_INITIAL (member), 0); else if (TREE_CODE (TREE_TYPE (member)) == ARRAY_TYPE && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (member))) { member_base = save_expr (default_conversion (member_base)); expand_vec_init (member, member_base, array_type_nelts (TREE_TYPE (member)), DECL_INITIAL (member), 0); } else expand_expr_stmt (build_modify_expr (member_base, INIT_EXPR, DECL_INITIAL (member))); } else if (TREE_CODE (TREE_PURPOSE (init_list)) == TREE_LIST) { expand_recursive_init_1 (binfo, true_exp, addr, TREE_PURPOSE (init_list), alias_this); expand_recursive_init_1 (binfo, true_exp, addr, TREE_VALUE (init_list), alias_this); } else if (TREE_CODE (TREE_PURPOSE (init_list)) == ERROR_MARK) { /* Only initialize the virtual function tables if we are initializing the ultimate users of those vtables. */ if (TREE_VALUE (init_list)) { expand_expr_stmt (build_virtual_init (binfo, TREE_VALUE (init_list), addr)); if (TREE_VALUE (init_list) == binfo && TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))) expand_expr_stmt (build_vbase_vtables_init (binfo, binfo, true_exp, addr, 1)); } } else my_friendly_abort (49); } else if (TREE_VALUE (init_list) && TREE_CODE (TREE_VALUE (init_list)) == TREE_VEC) { tree subexp = build_indirect_ref (convert_pointer_to (TREE_VALUE (init_list), addr), 0); expand_aggr_init_1 (binfo, true_exp, subexp, *init_ptr, alias_this && BINFO_OFFSET_ZEROP (TREE_VALUE (init_list)), LOOKUP_PROTECTED_OK|LOOKUP_COMPLAIN); /* INIT_PTR is used up. */ init_ptr = &init_null; } else my_friendly_abort (50); init_list = TREE_CHAIN (init_list); }}/* Initialize EXP with INIT. Type EXP does not have a constructor, but it has a baseclass with a constructor or a virtual function table which needs initializing. INIT_LIST is a cons-list describing what parts of EXP actually need to be initialized. INIT is given to the *unique*, first constructor within INIT_LIST. If there are multiple first constructors, such as with multiple inheritance, INIT must be zero or an ambiguity error is reported. ALIAS_THIS is passed from `expand_aggr_init'. See comments there. */static voidexpand_recursive_init (binfo, true_exp, exp, init, init_list, alias_this) tree binfo, true_exp, exp, init; tree init_list; int alias_this;{ tree *old_init_ptr = init_ptr; tree addr = build_unary_op (ADDR_EXPR, exp, 0); init_ptr = &init; if (true_exp == exp && TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))) { expand_aggr_vbase_init (binfo, exp, addr, init_list); expand_expr_stmt (build_vbase_vtables_init (binfo, binfo, true_exp, addr, 1)); } expand_recursive_init_1 (binfo, true_exp, addr, init_list, alias_this); if (*init_ptr) { tree type = TREE_TYPE (exp); if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); if (IS_AGGR_TYPE (type)) error_with_aggr_type (type, "unexpected argument to constructor `%s'"); else error ("unexpected argument to constructor"); } init_ptr = old_init_ptr;}/* Report an error if NAME is not the name of a user-defined, aggregate type. If OR_ELSE is nonzero, give an error message. */int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -