📄 init.c
字号:
}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 CNAME :: NAME (PARMLIST), build the appropriate function call. */treebuild_member_call (cname, name, parmlist) tree cname, name, parmlist;{ tree type, t; tree method_name = name; int dtor = 0; int dont_use_this = 0; tree basetype_path, decl; if (TREE_CODE (method_name) == BIT_NOT_EXPR) { method_name = TREE_OPERAND (method_name, 0); dtor = 1; } if (TREE_CODE (cname) == SCOPE_REF) cname = resolve_scope_to_name (NULL_TREE, cname); /* This shouldn't be here, and build_member_call shouldn't appear in parse.y! (mrs) */ if (cname && get_aggr_from_typedef (cname, 0) == 0 && TREE_CODE (cname) == IDENTIFIER_NODE) { tree ns = lookup_name (cname, 0); if (ns && TREE_CODE (ns) == NAMESPACE_DECL) { return build_x_function_call (build_offset_ref (cname, name), parmlist, current_class_decl); } } if (cname == NULL_TREE || ! (type = get_aggr_from_typedef (cname, 1))) return error_mark_node; /* An operator we did not like. */ if (name == NULL_TREE) return error_mark_node; if (dtor) {#if 0 /* Everything can explicitly call a destructor; see 12.4 */ if (! TYPE_HAS_DESTRUCTOR (type)) cp_error ("type `%#T' does not have a destructor", type); else#endif 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_decl == 0) { dont_use_this = 1; decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node); } else { tree olddecl = current_class_decl; tree oldtype = TREE_TYPE (TREE_TYPE (olddecl)); if (oldtype != type) { tree newtype = build_type_variant (type, TYPE_READONLY (oldtype), TYPE_VOLATILE (oldtype)); decl = convert_force (build_pointer_type (newtype), olddecl, 0); } else decl = olddecl; } decl = build_indirect_ref (decl, NULL_PTR); if (method_name == constructor_name (type) || method_name == constructor_name_full (type)) return build_functional_cast (type, parmlist); if (t = lookup_fnfields (basetype_path, method_name, 0)) return build_method_call (decl, method_name, parmlist, basetype_path, LOOKUP_NORMAL|LOOKUP_NONVIRTUAL); if (TREE_CODE (name) == IDENTIFIER_NODE && ((t = lookup_field (TYPE_BINFO (type), name, 1, 0)))) { if (t == error_mark_node) return error_mark_node; if (TREE_CODE (t) == FIELD_DECL) { if (dont_use_this) { cp_error ("invalid use of non-static field `%D'", t); return error_mark_node; } decl = build (COMPONENT_REF, TREE_TYPE (t), decl, t); } else if (TREE_CODE (t) == VAR_DECL) decl = t; else { cp_error ("invalid use of member `%D'", t); return error_mark_node; } if (TYPE_LANG_SPECIFIC (TREE_TYPE (decl)) && TYPE_OVERLOADS_CALL_EXPR (TREE_TYPE (decl))) return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, decl, parmlist, NULL_TREE); return build_function_call (decl, parmlist); } else { cp_error ("no method `%T::%D'", type, name); return error_mark_node; }}/* Build a reference to a member of an aggregate. This is not a C++ `&', but really something which can have its address taken, and then act as a pointer to member, for example CNAME :: FIELD can have its address taken by saying & CNAME :: FIELD. @@ Prints out lousy diagnostics for operator <typename> @@ fields. @@ This function should be rewritten and placed in search.c. */treebuild_offset_ref (cname, name) tree cname, name;{ tree decl, type, fnfields, fields, t = error_mark_node; tree basetypes = NULL_TREE; int dtor = 0; if (TREE_CODE (cname) == SCOPE_REF) cname = resolve_scope_to_name (NULL_TREE, cname); /* Handle namespace names fully here. */ if (TREE_CODE (cname) == IDENTIFIER_NODE && get_aggr_from_typedef (cname, 0) == 0) { tree ns = lookup_name (cname, 0); tree val; if (ns && TREE_CODE (ns) == NAMESPACE_DECL) { val = lookup_namespace_name (ns, name); if (val) return val; cp_error ("namespace `%D' has no member named `%D'", ns, name); return error_mark_node; } } if (cname == NULL_TREE || ! is_aggr_typedef (cname, 1)) return error_mark_node; type = IDENTIFIER_TYPE_VALUE (cname); if (TREE_CODE (name) == BIT_NOT_EXPR) { dtor = 1; name = TREE_OPERAND (name, 0); } if (TYPE_SIZE (type) == 0) { t = IDENTIFIER_CLASS_VALUE (name); if (t == 0) { cp_error ("incomplete type `%T' does not have member `%D'", type, name); return error_mark_node; } if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == CONST_DECL) { TREE_USED (t) = 1; return t; } if (TREE_CODE (t) == FIELD_DECL) sorry ("use of member in incomplete aggregate type"); else if (TREE_CODE (t) == FUNCTION_DECL) sorry ("use of member function in incomplete aggregate type"); else my_friendly_abort (52); return error_mark_node; }#if 0 if (TREE_CODE (name) == TYPE_EXPR) /* Pass a TYPE_DECL to build_component_type_expr. */ return build_component_type_expr (TYPE_NAME (TREE_TYPE (cname)), name, NULL_TREE, 1);#endif if (current_class_type == 0 || get_base_distance (type, current_class_type, 0, &basetypes) == -1) { basetypes = TYPE_BINFO (type); decl = build1 (NOP_EXPR, IDENTIFIER_TYPE_VALUE (cname), error_mark_node); } else if (current_class_decl == 0) decl = build1 (NOP_EXPR, IDENTIFIER_TYPE_VALUE (cname), error_mark_node); else decl = C_C_D; fnfields = lookup_fnfields (basetypes, name, 1); fields = lookup_field (basetypes, name, 0, 0); if (fields == error_mark_node || fnfields == error_mark_node) return error_mark_node; /* A lot of this logic is now handled in lookup_field and lookup_fnfield. */ if (fnfields) { basetypes = TREE_PURPOSE (fnfields); /* Go from the TREE_BASELINK to the member function info. */ t = TREE_VALUE (fnfields); if (fields) { if (DECL_FIELD_CONTEXT (fields) == DECL_FIELD_CONTEXT (t)) { error ("ambiguous member reference: member `%s' defined as both field and function", IDENTIFIER_POINTER (name)); return error_mark_node; } if (UNIQUELY_DERIVED_FROM_P (DECL_FIELD_CONTEXT (fields), DECL_FIELD_CONTEXT (t))) ; else if (UNIQUELY_DERIVED_FROM_P (DECL_FIELD_CONTEXT (t), DECL_FIELD_CONTEXT (fields))) t = fields; else { error ("ambiguous member reference: member `%s' derives from distinct classes in multiple inheritance lattice"); return error_mark_node; } } if (t == TREE_VALUE (fnfields)) { extern int flag_save_memoized_contexts; if (DECL_CHAIN (t) == NULL_TREE || dtor) { enum access_type access; /* unique functions are handled easily. */ unique: access = compute_access (basetypes, t); if (access == access_protected) { cp_error_at ("member function `%#D' is protected", t); error ("in this context"); return error_mark_node; } if (access == access_private) { cp_error_at ("member function `%#D' is private", t); error ("in this context"); return error_mark_node; } assemble_external (t); return build (OFFSET_REF, TREE_TYPE (t), decl, t); } /* overloaded functions may need more work. */ if (cname == name) { if (TYPE_HAS_DESTRUCTOR (type) && DECL_CHAIN (DECL_CHAIN (t)) == NULL_TREE) { t = DECL_CHAIN (t); goto unique; } } /* FNFIELDS is most likely allocated on the search_obstack, which will go away after this class scope. If we need to save this value for later (either for memoization or for use as an initializer for a static variable), then do so here. ??? The smart thing to do for the case of saving initializers is to resolve them before we're done with this scope. */ if (!TREE_PERMANENT (fnfields) && ((flag_save_memoized_contexts && global_bindings_p ()) || ! allocation_temporary_p ())) fnfields = copy_list (fnfields); for (t = TREE_VALUE (fnfields); t; t = DECL_CHAIN (t)) assemble_external (t); t = build_tree_list (error_mark_node, fnfields); TREE_TYPE (t) = build_offset_type (type, unknown_type_node); return t; } } /* Now that we know we are looking for a field, see if we have access to that field. Lookup_field will give us the error message. */ t = lookup_field (basetypes, name, 1, 0); if (t == error_mark_node) return error_mark_node; if (t == NULL_TREE) { cp_error ("`%D' is not a member of type `%T'", name, type); return error_mark_node; } if (TREE_CODE (t) == TYPE_DECL) { TREE_USED (t) = 1; return t; } /* static class members and class-specific enum values can be returned without further ado. */ if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == CONST_DECL) { assemble_external (t); TREE_USED (t) = 1; return t; } if (TREE_CODE (t) == FIELD_DECL && DECL_BIT_FIELD (t)) { cp_error ("illegal pointer to bit field `%D'", t); return error_mark_node; } /* static class functions too. */ if (TREE_CODE (t) == FUNCTION_DECL && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE) my_friendly_abort (53); /* In member functions, the form `cname::name' is no longer equivalent to `this->cname::name'. */ return build (OFFSET_REF, build_offset_type (type, TREE_TYPE (t)), decl, t);}/* Given an object EXP and a member function reference MEMBER, return the address of the actual member function. */treeget_member_function (exp_addr_ptr, exp, member) tree *exp_addr_ptr; tree exp, member;{ tree ctype = TREE_TYPE (exp); tree function = save_expr (build_unary_op (ADDR_EXPR, member, 0)); if (TYPE_VIRTUAL_P (ctype) || (flag_all_virtual == 1 && TYPE_OVERLOADS_METHOD_CALL_EXPR (ctype))) { tree e0, e1, e3; tree exp_addr; /* Save away the unadulterated `this' pointer. */ exp_addr = save_expr (*exp_addr_ptr); /* Cast function to signed integer. */ e0 = build1 (NOP_EXPR, integer_type_node, function); /* There is a hack here that takes advantage of twos complement arithmetic, and the fact that there are more than one UNITS to the WORD. If the high bit is set for the `function', then we pretend it is a virtual function, and the array indexing will knock this bit out the top, leaving a valid index. */ if (UNITS_PER_WORD <= 1) my_friendly_abort (54); e1 = build (GT_EXPR, boolean_type_node, e0, integer_zero_node); e1 = build_compound_expr (tree_cons (NULL_TREE, exp_addr, build_tree_list (NULL_TREE, e1))); e1 = save_expr (e1); if (TREE_SIDE_EFFECTS (*exp_addr_ptr)) { exp = build_indirect_ref (exp_addr, NULL_PTR); *exp_addr_ptr = exp_addr; } /* This is really hairy: if the function pointer is a pointer to a non-virtual member function, then we can't go mucking with the `this' pointer (any more than we already have to this point). If it is a pointer to a virtual member function, then we have to adjust the `this' pointer according to what the virtual function table tells us. */ e3 = build_vfn_ref (exp_addr_ptr, exp, e0); my_friendly_assert (e3 != error_mark_node, 213); /* Change this pointer type from `void *' to the type it is really sup
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -