method.c
来自「GCC编译器源代码」· C语言 代码 · 共 2,227 行 · 第 1/4 页
C
2,227 行
if (DECL_CHAIN (fndecl) == NULL_TREE) { warning ("methods cannot be converted to function pointers"); return fndecl; } else { error ("ambiguous request for method pointer `%s'", IDENTIFIER_POINTER (name)); return error_mark_node; } } } if (flag_labels_ok && IDENTIFIER_LABEL_VALUE (name)) { return IDENTIFIER_LABEL_VALUE (name); } return error_mark_node; } type = TREE_TYPE (value); if (TREE_CODE (value) == FIELD_DECL) { if (current_class_ptr == NULL_TREE) { error ("request for member `%s' in static member function", IDENTIFIER_POINTER (DECL_NAME (value))); return error_mark_node; } TREE_USED (current_class_ptr) = 1; /* Mark so that if we are in a constructor, and then find that this field was initialized by a base initializer, we can emit an error message. */ TREE_USED (value) = 1; value = build_component_ref (current_class_ref, name, NULL_TREE, 1); } else if (really_overloaded_fn (value)) {#if 0 tree t = get_first_fn (value); for (; t; t = DECL_CHAIN (t)) { if (TREE_CODE (t) == TEMPLATE_DECL) continue; assemble_external (t); TREE_USED (t) = 1; }#endif } else if (TREE_CODE (value) == TREE_LIST) { /* Ambiguous reference to base members, possibly other cases?. */ tree t = value; while (t && TREE_CODE (t) == TREE_LIST) { mark_used (TREE_VALUE (t)); t = TREE_CHAIN (t); } } else mark_used (value); if (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == PARM_DECL) { tree context = decl_function_context (value); if (context != NULL_TREE && context != current_function_decl && ! TREE_STATIC (value)) { cp_error ("use of %s from containing function", (TREE_CODE (value) == VAR_DECL ? "`auto' variable" : "parameter")); cp_error_at (" `%#D' declared here", value); value = error_mark_node; } } if (TREE_CODE_CLASS (TREE_CODE (value)) == 'd' && DECL_NONLOCAL (value)) { if (DECL_LANG_SPECIFIC (value) && DECL_CLASS_CONTEXT (value) != current_class_type) { tree path, access; register tree context = (TREE_CODE (value) == FUNCTION_DECL && DECL_VIRTUAL_P (value)) ? DECL_CLASS_CONTEXT (value) : DECL_CONTEXT (value); get_base_distance (context, current_class_type, 0, &path); if (path) { access = compute_access (path, value); if (access != access_public_node) { if (TREE_CODE (value) == VAR_DECL) error ("static member `%s' is %s", IDENTIFIER_POINTER (name), TREE_PRIVATE (value) ? "private" : "from a private base class"); else error ("enum `%s' is from private base class", IDENTIFIER_POINTER (name)); return error_mark_node; } } } } else if (TREE_CODE (value) == TREE_LIST && TREE_NONLOCAL_FLAG (value)) { if (type == 0) { error ("request for member `%s' is ambiguous in multiple inheritance lattice", IDENTIFIER_POINTER (name)); return error_mark_node; } return value; } if (TREE_CODE (type) == REFERENCE_TYPE && ! processing_template_decl) value = convert_from_reference (value); return value;}static char *thunk_printable_name (decl) tree decl;{ return "<thunk function>";}treemake_thunk (function, delta) tree function; int delta;{ char buffer[250]; tree thunk_id; tree thunk; char *func_name; tree func_decl; if (TREE_CODE (function) != ADDR_EXPR) abort (); func_decl = TREE_OPERAND (function, 0); if (TREE_CODE (func_decl) != FUNCTION_DECL) abort (); func_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (func_decl)); if (delta<=0) sprintf (buffer, "__thunk_%d_%s", -delta, func_name); else sprintf (buffer, "__thunk_n%d_%s", delta, func_name); thunk_id = get_identifier (buffer); thunk = IDENTIFIER_GLOBAL_VALUE (thunk_id); if (thunk && TREE_CODE (thunk) != THUNK_DECL) { cp_error ("implementation-reserved name `%D' used", thunk_id); IDENTIFIER_GLOBAL_VALUE (thunk_id) = thunk = NULL_TREE; } if (thunk == NULL_TREE) { thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (func_decl)); TREE_READONLY (thunk) = TREE_READONLY (func_decl); TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (func_decl); comdat_linkage (thunk); TREE_SET_CODE (thunk, THUNK_DECL); DECL_INITIAL (thunk) = function; THUNK_DELTA (thunk) = delta; DECL_EXTERNAL (thunk) = 1; DECL_ARTIFICIAL (thunk) = 1; /* So that finish_file can write out any thunks that need to be: */ pushdecl_top_level (thunk); } return thunk;}/* Emit the definition of a C++ multiple inheritance vtable thunk. */voidemit_thunk (thunk_fndecl) tree thunk_fndecl;{ tree function = TREE_OPERAND (DECL_INITIAL (thunk_fndecl), 0); int delta = THUNK_DELTA (thunk_fndecl); if (TREE_ASM_WRITTEN (thunk_fndecl)) return; TREE_ASM_WRITTEN (thunk_fndecl) = 1; TREE_ADDRESSABLE (function) = 1; mark_used (function); if (current_function_decl) abort (); TREE_SET_CODE (thunk_fndecl, FUNCTION_DECL); {#ifdef ASM_OUTPUT_MI_THUNK char *fnname; current_function_decl = thunk_fndecl; /* Make sure we build up its RTL before we go onto the temporary obstack. */ make_function_rtl (thunk_fndecl); temporary_allocation (); DECL_RESULT (thunk_fndecl) = build_decl (RESULT_DECL, 0, integer_type_node); fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0); init_function_start (thunk_fndecl, input_filename, lineno); assemble_start_function (thunk_fndecl, fnname); ASM_OUTPUT_MI_THUNK (asm_out_file, thunk_fndecl, delta, function); assemble_end_function (thunk_fndecl, fnname); permanent_allocation (1); current_function_decl = 0;#else /* ASM_OUTPUT_MI_THUNK */ /* If we don't have the necessary macro for efficient thunks, generate a thunk function that just makes a call to the real function. Unfortunately, this doesn't work for varargs. */ tree a, t; if (varargs_function_p (function)) cp_error ("generic thunk code fails for method `%#D' which uses `...'", function); /* Set up clone argument trees for the thunk. */ t = NULL_TREE; for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a)) { tree x = copy_node (a); TREE_CHAIN (x) = t; DECL_CONTEXT (x) = thunk_fndecl; t = x; } a = nreverse (t); DECL_ARGUMENTS (thunk_fndecl) = a; DECL_RESULT (thunk_fndecl) = NULL_TREE; DECL_LANG_SPECIFIC (thunk_fndecl) = DECL_LANG_SPECIFIC (function); copy_lang_decl (thunk_fndecl); DECL_INTERFACE_KNOWN (thunk_fndecl) = 1; DECL_NOT_REALLY_EXTERN (thunk_fndecl) = 1; start_function (NULL_TREE, thunk_fndecl, NULL_TREE, 1); store_parm_decls (); current_function_is_thunk = 1; /* Build up the call to the real function. */ t = build_int_2 (delta, -1 * (delta < 0)); TREE_TYPE (t) = signed_type (sizetype); t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t)); t = expr_tree_cons (NULL_TREE, t, NULL_TREE); for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a)) t = expr_tree_cons (NULL_TREE, a, t); t = nreverse (t); t = build_call (function, TREE_TYPE (TREE_TYPE (function)), t); c_expand_return (t); finish_function (lineno, 0, 0); /* Don't let the backend defer this function. */ if (DECL_DEFER_OUTPUT (thunk_fndecl)) { output_inline_function (thunk_fndecl); permanent_allocation (1); }#endif /* ASM_OUTPUT_MI_THUNK */ } TREE_SET_CODE (thunk_fndecl, THUNK_DECL);}/* Code for synthesizing methods which have default semantics defined. *//* For the anonymous union in TYPE, return the member that is at least as large as the rest of the members, so we can copy it. */static treelargest_union_member (type) tree type;{ tree f, type_size = TYPE_SIZE (type); for (f = TYPE_FIELDS (type); f; f = TREE_CHAIN (f)) if (simple_cst_equal (DECL_SIZE (f), type_size) == 1) return f; /* We should always find one. */ my_friendly_abort (323); return NULL_TREE;}/* Generate code for default X(X&) constructor. */static voiddo_build_copy_constructor (fndecl) tree fndecl;{ tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); tree t; clear_last_expr (); push_momentary (); if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) parm = TREE_CHAIN (parm); parm = convert_from_reference (parm); if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)) { t = build (INIT_EXPR, void_type_node, current_class_ref, parm); TREE_SIDE_EFFECTS (t) = 1; cplus_expand_expr_stmt (t); } else { tree fields = TYPE_FIELDS (current_class_type); int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type); tree binfos = TYPE_BINFO_BASETYPES (current_class_type); int i; for (t = CLASSTYPE_VBASECLASSES (current_class_type); t; t = TREE_CHAIN (t)) { tree basetype = BINFO_TYPE (t); tree p = convert_to_reference (build_reference_type (basetype), parm, CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE); p = convert_from_reference (p); if (p == error_mark_node) cp_error ("in default copy constructor"); else current_base_init_list = tree_cons (basetype, p, current_base_init_list); } for (i = 0; i < n_bases; ++i) { tree p, basetype = TREE_VEC_ELT (binfos, i); if (TREE_VIA_VIRTUAL (basetype)) continue; basetype = BINFO_TYPE (basetype); p = convert_to_reference (build_reference_type (basetype), parm, CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE); if (p == error_mark_node) cp_error ("in default copy constructor"); else { p = convert_from_reference (p); current_base_init_list = tree_cons (basetype, p, current_base_init_list); } } for (; fields; fields = TREE_CHAIN (fields)) { tree init, t; tree field = fields; if (TREE_CODE (field) != FIELD_DECL) continue; init = parm; if (DECL_NAME (field)) { if (VFIELD_NAME_P (DECL_NAME (field))) continue; if (VBASE_NAME_P (DECL_NAME (field))) continue; /* True for duplicate members. */ if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field) continue; } else if ((t = TREE_TYPE (field)) != NULL_TREE && TREE_CODE (t) == UNION_TYPE && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)) && TYPE_FIELDS (t) != NULL_TREE) { do { init = build (COMPONENT_REF, t, init, field); field = largest_union_member (t); } while ((t = TREE_TYPE (field)) != NULL_TREE && TREE_CODE (t) == UNION_TYPE && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)) && TYPE_FIELDS (t) != NULL_TREE); } else continue; init = build (COMPONENT_REF, TREE_TYPE (field), init, field); init = build_tree_list (NULL_TREE, init); current_member_init_list = tree_cons (DECL_NAME (field), init, current_member_init_list); } current_member_init_list = nreverse (current_member_init_list); current_base_init_list = nreverse (current_base_init_list); setup_vtbl_ptr (); } pop_momentary ();}static voiddo_build_assign_ref (fndecl) tree fndecl;{ tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); clear_last_expr (); push_momentary (); parm = convert_from_reference (parm); if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)) { tree t = build (MODIFY_EXPR, void_type_node, current_class_ref, parm); TREE_SIDE_EFFECTS (t) = 1; cplus_expand_expr_stmt (t); } else { tree fields = TYPE_FIELDS (current_class_type); int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type); tree binfos = TYPE_BINFO_BASETYPES (current_class_type); int i; for (i = 0; i < n_bases; ++i) { tree basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, i)); tree p = convert_to_reference (build_reference_type (basetype), parm, CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE); p = convert_from_reference (p); p = build_member_call (basetype, ansi_opname [MODIFY_EXPR], build_expr_list (NULL_TREE, p)); expand_expr_stmt (p); } for (; fields; fields = TREE_CHAIN (fields)) { tree comp, init, t; tree field = fields; if (TREE_CODE (field) != FIELD_DECL) continue; if (TREE_READONLY (field)) { if (DECL_NAME (field)) cp_error ("non-static const member `%#D', can't use default assignment operator", field); else cp_error ("non-static const member in type `%T', can't use default assignment operator", current_class_type); continue; } else if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE) { if (DECL_NAME (field)) cp_error ("non-static reference member `%#D', can't use default assignment operator", field); else cp_error ("non-static reference member in type `%T', can't use default assignment operator", current_class_type); continue; } comp = current_class_ref; init = parm; if (DECL_NAME (field)) { if (VFIELD_NAME_P (DECL_NAME (field))) continue; if (VBASE_NAME_P (DECL_NAME (field))) continue; /* True for duplicate members. */ if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field) continue; } else if ((t = TREE_TYPE (field)) != NULL_TREE && TREE_CODE (t) == UNION_TYPE && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)) && TYPE_FIELDS (t) != NULL_TREE) { do { comp = build (COMPONENT_REF, t, comp, field); init = build (COMPONENT_REF, t, init, field); field = largest_union_member (t); } while ((t = TREE_TYPE (field)) != NULL_TREE && TREE_CODE (t) == UNION_TYPE && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)) && TYPE_FIELDS (t) != NULL_TREE); } else continue; comp = build (COMPONENT_REF, TREE_TYPE (field), comp, field); init = build (COMPONENT_REF, TREE_TYPE (field), init, field); expand_expr_stmt (build_modify_expr (comp, NOP_EXPR, init)); } } c_expand_return (current_class_ref); pop_momentary ();}voidsynthesize_method (fndecl) tree fndecl;{ int nested = (current_function_decl != NULL_TREE); tree context = hack_decl_function_context (fndecl); if (at_eof) import_export_decl (fndecl); if (! context) push_to_top_level (); else if (nested) push_cp_function_context (context); interface_unknown = 1; start_function (NULL_TREE, fndecl, NULL_TREE, 1); store_parm_decls (); if (DECL_NAME (fndecl) == ansi_opname[MODIFY_EXPR]) do_build_assign_ref (fndecl); else if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl))) ; else { tree arg_chain = FUNCTION_ARG_CHAIN (fndecl); if (DECL_CONSTRUCTOR_FOR_VBASE_P (fndecl)) arg_chain = TREE_CHAIN (arg_chain); if (arg_chain != void_list_node) do_build_copy_constructor (fndecl); else if (TYPE_NEEDS_CONSTRUCTING (current_class_type)) setup_vtbl_ptr (); } finish_function (lineno, 0, nested); extract_interface_info (); if (! context) pop_from_top_level (); else if (nested) pop_cp_function_context (context);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?