📄 class.c
字号:
/* Functions related to building classes and their related objects. Copyright (C) 1987, 1992, 1993, 1994, 1995 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;};tree current_class_decl, C_C_D; /* PARM_DECL: the class instance variable *//* 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. */static tree get_vfield_name PROTO((tree));tree the_null_vtable_entry;/* 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;char *dont_allow_type_definitions;/* 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 class.c and 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);}/* 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. */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 = resolves_to_fixed_type_p (expr, &nonnull); tree null_expr = 0, nonnull_expr; tree basetype; tree offset = integer_zero_node; if (nonnull == 0 && (alias_this && flag_this_is_variable <= 0)) nonnull = 1; /* 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) */ /* Do this, until we can undo any previous conversions. See net35.C for a testcase. */ fixed_type_p = complete_type_p (expr); 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 int flag_assume_nonnull_objects; 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 (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 = convert (type, offset); expr = build1 (NOP_EXPR, type, expr); /* 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 return build1 (NOP_EXPR, type, expr);}/* Virtual function things. *//* Virtual functions to be dealt with after laying out our base classes. We do all overrides after we layout virtual base classes. */static tree pending_hard_virtuals;static int doing_hard_virtuals;/* 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;{ if (flag_vtable_thunks) { HOST_WIDE_INT idelta = TREE_INT_CST_LOW (delta); extern tree make_thunk (); if (idelta) { pfn = build1 (ADDR_EXPR, vtable_entry_type, make_thunk (pfn, idelta)); TREE_READONLY (pfn) = 1; TREE_CONSTANT (pfn) = 1; }#ifdef GATHER_STATISTICS n_vtable_entries += 1;#endif return pfn; } else { extern int flag_huge_objects; 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 (delta_type_node)) < TREE_INT_CST_LOW (delta)) || (TREE_INT_CST_LOW (delta) < TREE_INT_CST_LOW (TYPE_MIN_VALUE (delta_type_node)))) if (flag_huge_objects) sorry ("object size exceeds built-in limit for virtual function table implementation"); else sorry ("object size exceeds normal limit for virtual function table implementation, recompile all source and use -fhuge-objects"); 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. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -