📄 cp-class.c
字号:
/* Functions related to building classes and their related objects. Copyright (C) 1987, 1992 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, 675 Mass Ave, Cambridge, MA 02139, USA. *//* High-level class interface. */#include "config.h"#include "tree.h"#include <stdio.h>#include "cp-tree.h"#include "flags.h"#include "cp-class.h"#ifdef DEBUG_CP_BINDING_LEVELS#include "cp-decl.h"#endif#include "obstack.h"#define obstack_chunk_alloc xmalloc#define obstack_chunk_free freeextern struct obstack permanent_obstack;/* in decl.c. */extern tree lookup_tag_current_binding_level ();/* in method.c. */extern void do_inline_function_hair ();/* 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;};tree current_class_decl, C_C_D; /* PARM_DECL: the class instance variable */tree current_vtable_decl;/* 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 */static tree prev_class_type; /* _TYPE: the previous type that was a class */static tree get_vtable_name (), get_vfield_name ();tree the_null_vtable_entry;/* Way of stacking language names. */tree *current_lang_base, *current_lang_stack;static 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;/* Variables shared between cp-class.c and cp-call.c. */int 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;/* Virtual baseclass things. */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), 0, 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; tree expr; tree path; int alias_this;{ register int changed = 0; tree last = NULL_TREE, last_virtual = NULL_TREE; int nonnull = 0; int fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull); tree null_expr = 0, nonnull_expr; tree basetype; tree offset = integer_zero_node; 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; while (path) { tree r = copy_node (path); BINFO_INHERITANCE_CHAIN (r) = reverse_path; reverse_path = r; path = BINFO_INHERITANCE_CHAIN (path); } path = reverse_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) { extern tree flag_assume_nonnull_objects; tree ind; if (last) nonnull_expr = convert_pointer_to (last, nonnull_expr); ind = build_indirect_ref (nonnull_expr, 0); nonnull_expr = build_vbase_pointer (ind, last_virtual); if (nonnull == 0 && !flag_assume_nonnull_objects && null_expr == NULL_TREE) { null_expr = build1 (NOP_EXPR, TYPE_POINTER_TO (last_virtual), integer_zero_node); expr = build (COND_EXPR, TYPE_POINTER_TO (last_virtual), build (EQ_EXPR, integer_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 { error_with_aggr_type (last_virtual, "cannot cast up from virtual baseclass `%s'"); 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 (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)) basetype = intype; else { tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (intype), 0); basetype = last; 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 0 /* why unconditionally set this? (mrs) see deja-gnu/g++.mike/net15.C for a test case. */ code = PLUS_EXPR;#endif } if (TREE_INT_CST_LOW (offset)) { /* 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 legal value to which we may add. */ if (nonnull == 0 && (alias_this == 0 || flag_this_is_variable > 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, integer_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. *//* Virtual functions to be dealt with after laying out our base classes. Usually this is used only when classes have virtual baseclasses, but it can happen also when classes have non-virtual baseclasses if the derived class overrides baseclass functions at different offsets. */static tree pending_hard_virtuals;static int doing_hard_virtuals;/* The names of the entries in the virtual table structure. */static tree delta_name, pfn_name;/* Temporary binfo list to memoize lookups of the left-most non-virtual baseclass B in a lattice topped by T. B can appear multiple times in the lattice. TREE_PURPOSE is B's TYPE_MAIN_VARIANT. TREE_VALUE is the path by which B is reached from T. TREE_TYPE is B's real type. If TREE_TYPE is NULL_TREE, it means that B was reached via a virtual baseclass. N.B.: This list consists of nodes on the temporary obstack. */static tree leftmost_baseclasses;/* 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. Note that the index (DELTA2) in the virtual function table is always 0. */treebuild_vtable_entry (delta, pfn) tree delta, pfn;{ tree elems = tree_cons (NULL_TREE, delta, tree_cons (NULL_TREE, integer_zero_node, build_tree_list (NULL_TREE, pfn))); tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems); /* DELTA is constructed by `size_int', which means it may be an unsigned quantity on some platforms. Therefore, we cannot use `int_fits_type_p', because when DELTA is really negative, `force_fit_type' will make it look like a very large number. */ if ((TREE_INT_CST_LOW (TYPE_MAX_VALUE (short_integer_type_node)) < TREE_INT_CST_LOW (delta)) || (TREE_INT_CST_LOW (delta) < TREE_INT_CST_LOW (TYPE_MIN_VALUE (short_integer_type_node)))) sorry ("object size exceeds built-in limit for virtual function table implementation"); TREE_CONSTANT (entry) = 1; TREE_STATIC (entry) = 1; TREE_READONLY (entry) = 1;#ifdef GATHER_STATISTICS n_vtable_entries += 1;#endif return entry;}/* Given an object INSTANCE, return an expression which yields the virtual function corresponding to INDEX. There are many special cases for INSTANCE which we take care of here, mainly to avoid creating extra tree nodes when we don't have to. */treebuild_vfn_ref (ptr_to_instptr, instance, index) tree *ptr_to_instptr, instance; tree index;{ extern int building_cleanup; tree vtbl, aref; tree basetype = TREE_TYPE (instance); if (TREE_CODE (basetype) == REFERENCE_TYPE) basetype = TREE_TYPE (basetype); if (instance == C_C_D) { if (current_vtable_decl == NULL_TREE || current_vtable_decl == error_mark_node || !UNIQUELY_DERIVED_FROM_P (DECL_FCONTEXT (CLASSTYPE_VFIELD (current_class_type)), basetype)) vtbl = build_indirect_ref (build_vfield_ref (instance, basetype)); else vtbl = current_vtable_decl; } else { if (optimize) { /* Try to figure out what a reference refers to, and access its virtual function table directly. */ tree ref = NULL_TREE; if (TREE_CODE (instance) == INDIRECT_REF && TREE_CODE (TREE_TYPE (TREE_OPERAND (instance, 0))) == REFERENCE_TYPE) ref = TREE_OPERAND (instance, 0); else if (TREE_CODE (TREE_TYPE (instance)) == REFERENCE_TYPE) ref = instance; if (ref && TREE_CODE (ref) == VAR_DECL && DECL_INITIAL (ref)) { tree init = DECL_INITIAL (ref); while (TREE_CODE (init) == NOP_EXPR || TREE_CODE (init) == NON_LVALUE_EXPR) init = TREE_OPERAND (init, 0); if (TREE_CODE (init) == ADDR_EXPR) { init = TREE_OPERAND (init, 0); if (IS_AGGR_TYPE (TREE_TYPE (init)) && (TREE_CODE (init) == PARM_DECL || TREE_CODE (init) == VAR_DECL)) instance = init; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -