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 + -
显示快捷键?