rtti.c
来自「GCC编译器源代码」· C语言 代码 · 共 1,395 行 · 第 1/3 页
C
1,395 行
/* RunTime Type Identification Copyright (C) 1995, 1996 Free Software Foundation, Inc. Mostly written by Jason Merrill (jason@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. */#include "config.h"#include <stdio.h>#include "tree.h"#include "cp-tree.h"#include "flags.h"#include "output.h"#include "assert.h"#ifndef INT_TYPE_SIZE#define INT_TYPE_SIZE BITS_PER_WORD#endifextern struct obstack permanent_obstack;static tree call_void_fn PROTO((char *));static tree build_headof_sub PROTO((tree));static tree build_headof PROTO((tree));static tree get_tinfo_var PROTO((tree));static tree get_typeid_1 PROTO((tree));static tree ifnonnull PROTO((tree, tree));static tree build_dynamic_cast_1 PROTO((tree, tree));static void expand_si_desc PROTO((tree, tree));static void expand_class_desc PROTO((tree, tree));static void expand_attr_desc PROTO((tree, tree));static void expand_ptr_desc PROTO((tree, tree));static void expand_generic_desc PROTO((tree, tree, char *));static tree throw_bad_cast PROTO((void));static tree throw_bad_typeid PROTO((void));tree type_info_type_node;tree tinfo_fn_id;tree tinfo_fn_type;voidinit_rtti_processing (){ type_info_type_node = xref_tag (class_type_node, get_identifier ("type_info"), NULL_TREE, 1); tinfo_fn_id = get_identifier ("__tf"); tinfo_fn_type = build_function_type (build_reference_type (build_type_variant (type_info_type_node, 1, 0)), void_list_node);}/* Given a pointer to an object with at least one virtual table pointer somewhere, return a pointer to a possible sub-object that has a virtual table pointer in it that is the vtable parent for that sub-object. */static treebuild_headof_sub (exp) tree exp;{ tree type = TREE_TYPE (TREE_TYPE (exp)); tree basetype = CLASSTYPE_RTTI (type); tree binfo = get_binfo (basetype, type, 0); exp = convert_pointer_to_real (binfo, exp); return exp;}/* Given the expression EXP of type `class *', return the head of the object pointed to by EXP with type cv void*, if the class has any virtual functions (TYPE_VIRTUAL_P), else just return the expression. */static treebuild_headof (exp) tree exp;{ tree type = TREE_TYPE (exp); tree aref; tree offset; if (TREE_CODE (type) != POINTER_TYPE) { error ("`headof' applied to non-pointer type"); return error_mark_node; } type = TREE_TYPE (type); if (!TYPE_VIRTUAL_P (type)) return exp; /* If we don't have rtti stuff, get to a sub-object that does. */ if (!CLASSTYPE_VFIELDS (TREE_TYPE (TREE_TYPE (exp)))) exp = build_headof_sub (exp); /* We use this a couple of times below, protect it. */ exp = save_expr (exp); aref = build_vtbl_ref (build_indirect_ref (exp, NULL_PTR), integer_zero_node); if (flag_vtable_thunks) offset = aref; else offset = build_component_ref (aref, delta_identifier, NULL_TREE, 0); type = build_type_variant (ptr_type_node, TREE_READONLY (exp), TREE_THIS_VOLATILE (exp)); return build (PLUS_EXPR, type, exp, cp_convert (ptrdiff_type_node, offset));}/* Build a call to a generic entry point taking and returning void. */static treecall_void_fn (name) char *name;{ tree d = get_identifier (name); tree type; if (IDENTIFIER_GLOBAL_VALUE (d)) d = IDENTIFIER_GLOBAL_VALUE (d); else { push_obstacks (&permanent_obstack, &permanent_obstack); type = build_function_type (void_type_node, void_list_node); d = build_lang_decl (FUNCTION_DECL, d, type); DECL_EXTERNAL (d) = 1; TREE_PUBLIC (d) = 1; DECL_ARTIFICIAL (d) = 1; pushdecl_top_level (d); make_function_rtl (d); assemble_external (d); pop_obstacks (); } return build_call (d, void_type_node, NULL_TREE);}/* Get a bad_cast node for the program to throw... See libstdc++/exception.cc for __throw_bad_cast */static treethrow_bad_cast (){ return call_void_fn ("__throw_bad_cast");}static treethrow_bad_typeid (){ return call_void_fn ("__throw_bad_typeid");}/* Return the type_info function associated with the expression EXP. If EXP is a reference to a polymorphic class, return the dynamic type; otherwise return the static type of the expression. */treeget_tinfo_fn_dynamic (exp) tree exp;{ tree type; if (exp == error_mark_node) return error_mark_node; if (type_unknown_p (exp)) { error ("typeid of overloaded function"); return error_mark_node; } type = TREE_TYPE (exp); /* peel back references, so they match. */ if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); /* Peel off cv qualifiers. */ type = TYPE_MAIN_VARIANT (type); /* If exp is a reference to polymorphic type, get the real type_info. */ if (TYPE_VIRTUAL_P (type) && ! resolves_to_fixed_type_p (exp, 0)) { /* build reference to type_info from vtable. */ tree t; if (! flag_rtti) warning ("taking dynamic typeid of object without -frtti"); /* If we don't have rtti stuff, get to a sub-object that does. */ if (! CLASSTYPE_VFIELDS (type)) { exp = build_unary_op (ADDR_EXPR, exp, 0); exp = build_headof_sub (exp); exp = build_indirect_ref (exp, NULL_PTR); } if (flag_vtable_thunks) t = build_vfn_ref ((tree *) 0, exp, integer_one_node); else t = build_vfn_ref ((tree *) 0, exp, integer_zero_node); TREE_TYPE (t) = build_pointer_type (tinfo_fn_type); return t; } /* otherwise return the type_info for the static type of the expr. */ return get_tinfo_fn (TYPE_MAIN_VARIANT (type));}treebuild_typeid (exp) tree exp;{ exp = get_tinfo_fn_dynamic (exp); exp = build_call (exp, TREE_TYPE (tinfo_fn_type), NULL_TREE); return convert_from_reference (exp);} treebuild_x_typeid (exp) tree exp;{ tree cond = NULL_TREE; tree type = TREE_TYPE (tinfo_fn_type); int nonnull; if (processing_template_decl) return build_min_nt (TYPEID_EXPR, exp); if (TREE_CODE (exp) == INDIRECT_REF && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE && TYPE_VIRTUAL_P (TREE_TYPE (exp)) && ! resolves_to_fixed_type_p (exp, &nonnull) && ! nonnull) { exp = stabilize_reference (exp); cond = cp_convert (boolean_type_node, TREE_OPERAND (exp, 0)); } exp = get_tinfo_fn_dynamic (exp); if (exp == error_mark_node) return error_mark_node; exp = build_call (exp, type, NULL_TREE); if (cond) { tree bad = throw_bad_typeid (); bad = build_compound_expr (expr_tree_cons (NULL_TREE, bad, build_expr_list (NULL_TREE, cp_convert (type, integer_zero_node)))); exp = build (COND_EXPR, type, cond, exp, bad); } return convert_from_reference (exp);}static treeget_tinfo_var (type) tree type;{ tree tname = build_overload_with_type (get_identifier ("__ti"), type); tree tdecl, arrtype; int size; if (IDENTIFIER_GLOBAL_VALUE (tname)) return IDENTIFIER_GLOBAL_VALUE (tname); /* Figure out how much space we need to allocate for the type_info object. If our struct layout or the type_info classes are changed, this will need to be modified. */ if (TYPE_VOLATILE (type) || TYPE_READONLY (type)) size = 3 * POINTER_SIZE + INT_TYPE_SIZE; else if (TREE_CODE (type) == POINTER_TYPE && ! (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE || TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)) size = 3 * POINTER_SIZE; else if (IS_AGGR_TYPE (type)) { if (CLASSTYPE_N_BASECLASSES (type) == 0) size = 2 * POINTER_SIZE; else if (! TYPE_USES_COMPLEX_INHERITANCE (type) && (TREE_VIA_PUBLIC (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0)))) size = 3 * POINTER_SIZE; else size = 3 * POINTER_SIZE + TYPE_PRECISION (sizetype); } else size = 2 * POINTER_SIZE; push_obstacks (&permanent_obstack, &permanent_obstack); /* The type for a character array of the appropriate size. */ arrtype = build_cplus_array_type (unsigned_char_type_node, build_index_type (size_int (size / BITS_PER_UNIT - 1))); tdecl = build_decl (VAR_DECL, tname, arrtype); TREE_PUBLIC (tdecl) = 1; DECL_EXTERNAL (tdecl) = 1; DECL_ARTIFICIAL (tdecl) = 1; pushdecl_top_level (tdecl); cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0); pop_obstacks (); return tdecl;}treeget_tinfo_fn (type) tree type;{ tree name; tree d; if (TREE_CODE (type) == OFFSET_TYPE) type = TREE_TYPE (type); if (TREE_CODE (type) == METHOD_TYPE) type = build_function_type (TREE_TYPE (type), TREE_CHAIN (TYPE_ARG_TYPES (type))); name = build_overload_with_type (tinfo_fn_id, type); if (IDENTIFIER_GLOBAL_VALUE (name)) return IDENTIFIER_GLOBAL_VALUE (name); push_obstacks (&permanent_obstack, &permanent_obstack); d = build_lang_decl (FUNCTION_DECL, name, tinfo_fn_type); DECL_EXTERNAL (d) = 1; TREE_PUBLIC (d) = 1; DECL_ARTIFICIAL (d) = 1; DECL_NOT_REALLY_EXTERN (d) = 1; DECL_MUTABLE_P (d) = 1; TREE_TYPE (name) = copy_to_permanent (type); pushdecl_top_level (d); make_function_rtl (d); assemble_external (d); mark_inline_for_output (d); if (at_eof) import_export_decl (d); pop_obstacks (); return d;}static treeget_typeid_1 (type) tree type;{ tree t = build_call (get_tinfo_fn (type), TREE_TYPE (tinfo_fn_type), NULL_TREE); return convert_from_reference (t);} /* Return the type_info object for TYPE, creating it if necessary. */treeget_typeid (type) tree type;{ if (type == error_mark_node) return error_mark_node; if (processing_template_decl) return build_min_nt (TYPEID_EXPR, type); /* If the type of the type-id is a reference type, the result of the typeid expression refers to a type_info object representing the referenced type. */ if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); /* The top-level cv-qualifiers of the lvalue expression or the type-id that is the operand of typeid are always ignored. */ type = TYPE_MAIN_VARIANT (type); return get_typeid_1 (type);}/* Check whether TEST is null before returning RESULT. If TEST is used in RESULT, it must have previously had a save_expr applied to it. */static treeifnonnull (test, result) tree test, result;{ return build (COND_EXPR, TREE_TYPE (result), build (EQ_EXPR, boolean_type_node, test, integer_zero_node), cp_convert (TREE_TYPE (result), integer_zero_node), result);}/* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working paper. */static treebuild_dynamic_cast_1 (type, expr) tree type, expr;{ enum tree_code tc = TREE_CODE (type); tree exprtype = TREE_TYPE (expr); enum tree_code ec; tree dcast_fn; if (type == error_mark_node || expr == error_mark_node) return error_mark_node; if (processing_template_decl) { tree t = build_min (DYNAMIC_CAST_EXPR, type, expr); return t; } assert (exprtype != NULL_TREE); ec = TREE_CODE (exprtype); switch (tc) { case POINTER_TYPE: if (ec == REFERENCE_TYPE) { expr = convert_from_reference (expr); exprtype = TREE_TYPE (expr); ec = TREE_CODE (exprtype); } if (ec != POINTER_TYPE) goto fail; if (TREE_CODE (TREE_TYPE (exprtype)) != RECORD_TYPE) goto fail; if (TYPE_SIZE (complete_type (TREE_TYPE (exprtype))) == NULL_TREE) goto fail; if (TREE_READONLY (TREE_TYPE (exprtype)) && ! TYPE_READONLY (TREE_TYPE (type))) goto fail; if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node) break; /* else fall through */ case REFERENCE_TYPE: if (TREE_CODE (TREE_TYPE (type)) != RECORD_TYPE)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?