📄 class.c
字号:
/* Functions related to building classes and their related objects. Copyright (C) 1987, 92, 93, 94, 95, 96, 1997 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 "tree.h"#include <stdio.h>#include "cp-tree.h"#include "flags.h"#include "rtl.h"#include "output.h"#include "obstack.h"#define obstack_chunk_alloc xmalloc#define obstack_chunk_free freeextern struct obstack permanent_obstack;/* 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));/* Way of stacking class types. */static tree *current_class_base, *current_class_stack;static int current_class_stacksize;int current_class_depth;struct class_level{ /* The previous class level. */ struct class_level *level_chain; /* The class instance variable, as a PARM_DECL. */ tree decl; /* The class instance variable, as an object. */ tree object; /* The virtual function table pointer for the class instance variable. */ tree vtable_decl; /* Name of the current class. */ tree name; /* Type of the current class. */ tree type; /* Flags for this class level. */ int this_is_variable; int memoized_lookups; int save_memoized; int unused;};/* The current_class_ptr is the pointer to the current class. current_class_ref is the actual current class. */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 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. */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 int complete_type_p PROTO((tree));static int typecode_p PROTO((tree, enum tree_code));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 void fixup_vtable_deltas1 PROTO((tree, tree));static void fixup_vtable_deltas PROTO((tree, int, tree));static void grow_method PROTO((tree, 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 tree add_virtual_function PROTO((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));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 maybe_fixup_vptrs PROTO((tree, 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 void build_class_init_list PROTO((tree));static int finish_base_struct PROTO((tree, struct base_info *, 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;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_private_virtual_node; /* 6 *//* 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; name = (char *) alloca (TYPE_NAME_LENGTH (type) + sizeof (VBASE_NAME) + 1); sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (type)); return build_component_ref (exp, get_identifier (name), NULL_TREE, 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;}/* 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. ALIAS_THIS is non-zero if EXPR in an expression involving `this'. */treebuild_vbase_path (code, type, expr, path, alias_this) enum tree_code code; tree type, expr, path; int alias_this;{ register int changed = 0; tree last = NULL_TREE, last_virtual = NULL_TREE; int nonnull = 0; 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 (nonnull == 0 && (alias_this && flag_this_is_variable <= 0)) nonnull = 1;#if 0 /* We need 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, or until we can recognize when that is, we cannot do the short cut logic. (mrs) */ fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);#else /* Do this, until we can undo any previous conversions. See net35.C for a testcase. */ fixed_type_p = complete_type_p (expr);#endif if (!fixed_type_p && TREE_SIDE_EFFECTS (expr)) expr = save_expr (expr); nonnull_expr = expr; if (BINFO_INHERITANCE_CHAIN (path)) { tree reverse_path = NULL_TREE; push_expression_obstack (); while (path) { tree r = copy_node (path); BINFO_INHERITANCE_CHAIN (r) = reverse_path; reverse_path = r; path = BINFO_INHERITANCE_CHAIN (path); } path = reverse_path; pop_obstacks (); } 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 || !flag_assume_nonnull_objects) && 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 /* For multiple inheritance: if `this' can be set by any function, then it could be 0 on entry to any function. Preserve such zeroness here. Otherwise, only in the case of constructors need we worry, and in those cases, it will be zero, or initialized to some valid value to which we may add. */ 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -