📄 class.c
字号:
/* Functions related to building classes and their related objects. Copyright (C) 1987, 92-97, 1998, 1999 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com)This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. *//* High-level class interface. */#include "config.h"#include "system.h"#include "tree.h"#include "cp-tree.h"#include "flags.h"#include "rtl.h"#include "output.h"#include "toplev.h"#include "splay-tree.h"#include "obstack.h"#define obstack_chunk_alloc xmalloc#define obstack_chunk_free free/* This is how we tell when two virtual member functions are really the same. */#define SAME_FN(FN1DECL, FN2DECL) (DECL_ASSEMBLER_NAME (FN1DECL) == DECL_ASSEMBLER_NAME (FN2DECL))extern void set_class_shadows PROTO ((tree));/* The number of nested classes being processed. If we are not in the scope of any class, this is zero. */int current_class_depth;/* In order to deal with nested classes, we keep a stack of classes. The topmost entry is the innermost class, and is the entry at index CURRENT_CLASS_DEPTH */typedef struct class_stack_node { /* The name of the class. */ tree name; /* The _TYPE node for the class. */ tree type; /* The access specifier pending for new declarations in the scope of this class. */ tree access; /* If were defining TYPE, the names used in this class. */ splay_tree names_used;}* class_stack_node_t;/* The stack itself. This is an dynamically resized array. The number of elements allocated is CURRENT_CLASS_STACK_SIZE. */static int current_class_stack_size;static class_stack_node_t current_class_stack;/* When we're processing a member function, current_class_ptr is the PARM_DECL for the `this' pointer. The current_class_ref is an expression for `*this'. */tree current_class_ptr, current_class_ref;/* The following two can be derived from the previous one */tree current_class_name; /* IDENTIFIER_NODE: name of current class */tree current_class_type; /* _TYPE: the type of the current class */tree current_access_specifier;tree previous_class_type; /* _TYPE: the previous type that was a class */tree previous_class_values; /* TREE_LIST: copy of the class_shadowed list when leaving an outermost class scope. *//* The obstack on which the cached class declarations are kept. */static struct obstack class_cache_obstack;/* The first object allocated on that obstack. We can use obstack_free with tis value to free the entire obstack. */char *class_cache_firstobj;struct base_info;static tree get_vfield_name PROTO((tree));static void finish_struct_anon PROTO((tree));static tree build_vbase_pointer PROTO((tree, tree));static tree build_vtable_entry PROTO((tree, tree));static tree get_vtable_name PROTO((tree));static tree get_derived_offset PROTO((tree, tree));static tree get_basefndecls PROTO((tree, tree));static void set_rtti_entry PROTO((tree, tree, tree));static tree build_vtable PROTO((tree, tree));static void prepare_fresh_vtable PROTO((tree, tree));static tree prepare_ctor_vtable PROTO((tree, tree, tree));static void fixup_vtable_deltas1 PROTO((tree, tree));static void fixup_vtable_deltas PROTO((tree, int, tree));static tree finish_one_ctor_vtable PROTO((tree, tree, tree, tree));static tree prepend_ctor_vfields_for_vbase PROTO((tree, tree, tree, tree, int, tree));static tree finish_ctor_vtables_for_vbases PROTO((tree, tree, tree));static tree finish_ctor_vtables_1 PROTO((tree, tree));static tree prepend_vbase_vfields PROTO((tree, int, tree));static void finish_ctor_vtables PROTO((tree));static void finish_vtbls PROTO((tree, int, tree));static void modify_vtable_entry PROTO((tree, tree, tree));static tree get_vtable_entry_n PROTO((tree, unsigned HOST_WIDE_INT));static void add_virtual_function PROTO((tree *, tree *, int *, tree, tree));static tree delete_duplicate_fields_1 PROTO((tree, tree));static void delete_duplicate_fields PROTO((tree));static void finish_struct_bits PROTO((tree, int));static int alter_access PROTO((tree, tree, tree, tree));static void handle_using_decl PROTO((tree, tree, tree, tree));static int overrides PROTO((tree, tree));static int strictly_overrides PROTO((tree, tree));static void merge_overrides PROTO((tree, tree, int, tree));static void override_one_vtable PROTO((tree, tree, tree));static void mark_overriders PROTO((tree, tree));static void check_for_override PROTO((tree, tree));static tree get_class_offset_1 PROTO((tree, tree, tree, tree, tree));static tree get_class_offset PROTO((tree, tree, tree, tree));static void modify_one_vtable PROTO((tree, tree, tree, tree));static void modify_all_vtables PROTO((tree, tree, tree));static void modify_all_direct_vtables PROTO((tree, int, tree, tree, tree));static void modify_all_indirect_vtables PROTO((tree, int, int, tree, tree, tree));static int finish_base_struct PROTO((tree, struct base_info *));static void finish_struct_methods PROTO((tree));static void maybe_warn_about_overly_private_class PROTO ((tree));static tree make_method_vec PROTO((int));static void free_method_vec PROTO((tree));static tree add_implicitly_declared_members PROTO((tree, int, int, int));static tree fixed_type_or_null PROTO((tree, int *));static tree resolve_address_of_overloaded_function PROTO((tree, tree, int, int, tree));static void build_vtable_entry_ref PROTO((tree, tree, tree));/* Way of stacking language names. */tree *current_lang_base, *current_lang_stack;int current_lang_stacksize;/* Names of languages we recognize. */tree lang_name_c, lang_name_cplusplus, lang_name_java;tree current_lang_name;/* When layout out an aggregate type, the size of the basetypes (virtual and non-virtual) is passed to layout_record via this node. */static tree base_layout_decl;/* Constants used for access control. */tree access_default_node; /* 0 */tree access_public_node; /* 1 */tree access_protected_node; /* 2 */tree access_private_node; /* 3 */tree access_default_virtual_node; /* 4 */tree access_public_virtual_node; /* 5 */tree access_protected_virtual_node; /* 6 */tree access_private_virtual_node; /* 7 *//* Variables shared between class.c and call.c. */#ifdef GATHER_STATISTICSint n_vtables = 0;int n_vtable_entries = 0;int n_vtable_searches = 0;int n_vtable_elems = 0;int n_convert_harshness = 0;int n_compute_conversion_costs = 0;int n_build_method_call = 0;int n_inner_fields_searched = 0;#endif/* Virtual baseclass things. */static treebuild_vbase_pointer (exp, type) tree exp, type;{ char *name; FORMAT_VBASE_NAME (name, type); return build_component_ref (exp, get_identifier (name), NULL_TREE, 0);}#if 0/* Is the type of the EXPR, the complete type of the object? If we are going to be wrong, we must be conservative, and return 0. */static intcomplete_type_p (expr) tree expr;{ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (expr)); while (1) { switch (TREE_CODE (expr)) { case SAVE_EXPR: case INDIRECT_REF: case ADDR_EXPR: case NOP_EXPR: case CONVERT_EXPR: expr = TREE_OPERAND (expr, 0); continue; case CALL_EXPR: if (! TREE_HAS_CONSTRUCTOR (expr)) break; /* fall through... */ case VAR_DECL: case FIELD_DECL: if (TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && IS_AGGR_TYPE (TREE_TYPE (TREE_TYPE (expr))) && TYPE_MAIN_VARIANT (TREE_TYPE (expr)) == type) return 1; /* fall through... */ case TARGET_EXPR: case PARM_DECL: if (IS_AGGR_TYPE (TREE_TYPE (expr)) && TYPE_MAIN_VARIANT (TREE_TYPE (expr)) == type) return 1; /* fall through... */ case PLUS_EXPR: default: break; } break; } return 0;}#endif/* Build multi-level access to EXPR using hierarchy path PATH. CODE is PLUS_EXPR if we are going with the grain, and MINUS_EXPR if we are not (in which case, we cannot traverse virtual baseclass links). TYPE is the type we want this path to have on exit. NONNULL is non-zero if we know (for any reason) that EXPR is not, in fact, zero. */treebuild_vbase_path (code, type, expr, path, nonnull) enum tree_code code; tree type, expr, path; int nonnull;{ register int changed = 0; tree last = NULL_TREE, last_virtual = NULL_TREE; int fixed_type_p; tree null_expr = 0, nonnull_expr; tree basetype; tree offset = integer_zero_node; if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE) return build1 (NOP_EXPR, type, expr); /* If -fthis-is-variable, we might have set nonnull incorrectly. We don't care enough to get this right, so just clear it. */ if (flag_this_is_variable > 0) nonnull = 0; /* We could do better if we had additional logic to convert back to the unconverted type (the static type of the complete object), and then convert back to the type we want. Until that is done, we only optimize if the complete type is the same type as expr has. */ fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull); if (!fixed_type_p && TREE_SIDE_EFFECTS (expr)) expr = save_expr (expr); nonnull_expr = expr; if (BINFO_INHERITANCE_CHAIN (path)) path = reverse_path (path); basetype = BINFO_TYPE (path); while (path) { if (TREE_VIA_VIRTUAL (path)) { last_virtual = BINFO_TYPE (path); if (code == PLUS_EXPR) { changed = ! fixed_type_p; if (changed) { tree ind; /* We already check for ambiguous things in the caller, just find a path. */ if (last) { tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (nonnull_expr))), 0); nonnull_expr = convert_pointer_to_real (binfo, nonnull_expr); } ind = build_indirect_ref (nonnull_expr, NULL_PTR); nonnull_expr = build_vbase_pointer (ind, last_virtual); if (nonnull == 0 && TREE_CODE (type) == POINTER_TYPE && null_expr == NULL_TREE) { null_expr = build1 (NOP_EXPR, build_pointer_type (last_virtual), integer_zero_node); expr = build (COND_EXPR, build_pointer_type (last_virtual), build (EQ_EXPR, boolean_type_node, expr, integer_zero_node), null_expr, nonnull_expr); } } /* else we'll figure out the offset below. */ /* Happens in the case of parse errors. */ if (nonnull_expr == error_mark_node) return error_mark_node; } else { cp_error ("cannot cast up from virtual baseclass `%T'", last_virtual); return error_mark_node; } } last = path; path = BINFO_INHERITANCE_CHAIN (path); } /* LAST is now the last basetype assoc on the path. */ /* A pointer to a virtual base member of a non-null object is non-null. Therefore, we only need to test for zeroness once. Make EXPR the canonical expression to deal with here. */ if (null_expr) { TREE_OPERAND (expr, 2) = nonnull_expr; TREE_TYPE (expr) = TREE_TYPE (TREE_OPERAND (expr, 1)) = TREE_TYPE (nonnull_expr); } else expr = nonnull_expr; /* If we go through any virtual base pointers, make sure that casts to BASETYPE from the last virtual base class use the right value for BASETYPE. */ if (changed) { tree intype = TREE_TYPE (TREE_TYPE (expr)); if (TYPE_MAIN_VARIANT (intype) != BINFO_TYPE (last)) { tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (intype), 0); offset = BINFO_OFFSET (binfo); } } else { if (last_virtual) { offset = BINFO_OFFSET (binfo_member (last_virtual, CLASSTYPE_VBASECLASSES (basetype))); offset = size_binop (PLUS_EXPR, offset, BINFO_OFFSET (last)); } else offset = BINFO_OFFSET (last); } if (TREE_INT_CST_LOW (offset)) { /* Bash types to make the backend happy. */ offset = cp_convert (type, offset);#if 0 /* This shouldn't be necessary. (mrs) */ expr = build1 (NOP_EXPR, type, expr);#endif /* If expr might be 0, we need to preserve that zeroness. */ if (nonnull == 0) { if (null_expr) TREE_TYPE (null_expr) = type; else null_expr = build1 (NOP_EXPR, type, integer_zero_node); if (TREE_SIDE_EFFECTS (expr)) expr = save_expr (expr); return build (COND_EXPR, type, build (EQ_EXPR, boolean_type_node, expr, integer_zero_node), null_expr, build (code, type, expr, offset)); } else return build (code, type, expr, offset); } /* Cannot change the TREE_TYPE of a NOP_EXPR here, since it may be used multiple times in initialization of multiple inheritance. */ if (null_expr) { TREE_TYPE (expr) = type; return expr; } else return build1 (NOP_EXPR, type, expr);}/* Virtual function things. *//* Build an entry in the virtual function table. DELTA is the offset for the `this' pointer. PFN is an ADDR_EXPR containing a pointer to the virtual function.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -