📄 init.c
字号:
expand_expr_stmt (rval); return; } 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, ctor_identifier, 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_ptr); expand_assignment (current_class_ptr, 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. 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; 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_CODE (exp) == VAR_DECL && TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init)) { tree t = store_init_value (exp, init); if (!t) { expand_decl_init (exp); return; } t = build (INIT_EXPR, type, exp, init); TREE_SIDE_EFFECTS (t) = 1; expand_expr_stmt (t); return; } if (init && ! flag_ansi_overloading) { 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 (init_type == error_mark_node) return; /* 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 (TYPE_MAIN_VARIANT (init_type) == TYPE_MAIN_VARIANT (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, NULL_RTX, VOIDmode, EXPAND_NORMAL); expand_expr_stmt (init); return; } } if (init_type == type && TREE_CODE (init) == CALL_EXPR) { /* A CALL_EXPR is a legitimate form of initialization, so we should not print this warning message. */ 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; TREE_SIDE_EFFECTS (init) = 1; expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL); 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 (tmp && 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), NULL_TREE); TREE_SIDE_EFFECTS (init) = 1; 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! More useful for this case: xyzzy *foo = new xyzzy (bar); */ if (! TYPE_NEEDS_CONSTRUCTING (type) && ! IS_AGGR_TYPE (type)) { if (init_list && TREE_CHAIN (init_list)) { warning ("initializer list being treated as compound expression"); init = cp_convert (type, build_compound_expr (init_list)); if (init == error_mark_node) return; } expand_assignment (exp, init, 0, 0); return; } /* If this is copy-initialization, see whether we can go through a type conversion operator. */ if (TREE_CODE (init) != TREE_LIST && (flags & LOOKUP_ONLYCONVERTING)) { 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, 1); if (rval) { /* See if there is a constructor for``type'' that takes a ``ttype''-typed object. */ tree parms = build_expr_list (NULL_TREE, init); tree as_cons = NULL_TREE; if (TYPE_HAS_CONSTRUCTOR (type)) as_cons = build_method_call (exp, ctor_identifier, parms, binfo, LOOKUP_SPECULATIVELY|LOOKUP_NO_CONVERSION); if (as_cons != NULL_TREE && as_cons != error_mark_node) /* ANSI C++ June 5 1992 WP 12.3.2.6.1 */ cp_error ("ambiguity between conversion to `%T' and constructor", type); else if (rval != error_mark_node) expand_aggr_init_1 (binfo, true_exp, exp, rval, alias_this, flags); return; } } } } /* We know that expand_default_init can handle everything we want at this point. */ expand_default_init (binfo, true_exp, exp, init, alias_this, flags);}/* Report an error if NAME is not the name of a user-defined, aggregate type. If OR_ELSE is nonzero, give an error message. */intis_aggr_typedef (name, or_else) tree name; int or_else;{ tree type; if (name == error_mark_node) return 0; if (IDENTIFIER_HAS_TYPE_VALUE (name)) type = IDENTIFIER_TYPE_VALUE (name); else { if (or_else) cp_error ("`%T' is not an aggregate typedef", name); return 0; } if (! IS_AGGR_TYPE (type) && TREE_CODE (type) != TEMPLATE_TYPE_PARM) { if (or_else) cp_error ("`%T' is not an aggregate type", type); return 0; } return 1;}/* Report an error if TYPE is not a user-defined, aggregate type. If OR_ELSE is nonzero, give an error message. */intis_aggr_type (type, or_else) tree type; int or_else;{ if (type == error_mark_node) return 0; if (! IS_AGGR_TYPE (type) && TREE_CODE (type) != TEMPLATE_TYPE_PARM) { if (or_else) cp_error ("`%T' is not an aggregate type", type); return 0; } return 1;}/* Like is_aggr_typedef, but returns typedef if successful. */treeget_aggr_from_typedef (name, or_else) tree name; int or_else;{ tree type; if (name == error_mark_node) return NULL_TREE; if (IDENTIFIER_HAS_TYPE_VALUE (name)) type = IDENTIFIER_TYPE_VALUE (name); else { if (or_else) cp_error ("`%T' fails to be an aggregate typedef", name); return NULL_TREE; } if (! IS_AGGR_TYPE (type) && TREE_CODE (type) != TEMPLATE_TYPE_PARM) { if (or_else) cp_error ("type `%T' is of non-aggregate type", type); return NULL_TREE; } return type;}treeget_type_value (name) tree name;{ if (name == error_mark_node) return NULL_TREE; if (IDENTIFIER_HAS_TYPE_VALUE (name)) return IDENTIFIER_TYPE_VALUE (name); else return NULL_TREE;} /* This code could just as well go in `class.c', but is placed here for modularity. *//* For an expression of the form TYPE :: NAME (PARMLIST), build the appropriate function call. */treebuild_member_call (type, name, parmlist) tree type, name, parmlist;{ tree t; tree method_name; int dtor = 0; int dont_use_this = 0; tree basetype_path, decl; if (type == std_node) return build_x_function_call (do_scoped_id (name, 0), parmlist, current_class_ref); if (TREE_CODE (name) != TEMPLATE_ID_EXPR) method_name = name; else method_name = TREE_OPERAND (name, 0); if (TREE_CODE (method_name) == BIT_NOT_EXPR) { method_name = TREE_OPERAND (method_name, 0); dtor = 1; } /* This shouldn't be here, and build_member_call shouldn't appear in parse.y! (mrs) */ if (type && TREE_CODE (type) == IDENTIFIER_NODE && get_aggr_from_typedef (type, 0) == 0) { tree ns = lookup_name (type, 0); if (ns && TREE_CODE (ns) == NAMESPACE_DECL) { return build_x_function_call (build_offset_ref (type, name), parmlist, current_class_ref); } } if (type == NULL_TREE || ! is_aggr_type (type, 1)) return error_mark_node; /* An operator we did not like. */ if (name == NULL_TREE) return error_mark_node; if (dtor) { cp_error ("cannot call destructor `%T::~%T' without object", type, method_name); return error_mark_node; } /* No object? Then just fake one up, and let build_method_call figure out what to do. */ if (current_class_type == 0 || get_base_distance (type, current_class_type, 0, &basetype_path) == -1) dont_use_this = 1; if (dont_use_this) { basetype_path = TYPE_BINFO (type); decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node); } else if (current_class_ptr == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -