rtti.c

来自「GCC编译器源代码」· C语言 代码 · 共 1,395 行 · 第 1/3 页

C
1,395
字号
	goto fail;      if (TYPE_SIZE (complete_type (TREE_TYPE (type))) == NULL_TREE)	goto fail;      break;      /* else fall through */    default:      goto fail;    }  /* Apply trivial conversion T -> T& for dereferenced ptrs.  */  if (ec == RECORD_TYPE)    {      exprtype = build_type_variant (exprtype, TREE_READONLY (expr),				     TREE_THIS_VOLATILE (expr));      exprtype = build_reference_type (exprtype);      expr = convert_to_reference (exprtype, expr, CONV_IMPLICIT,				   LOOKUP_NORMAL, NULL_TREE);      ec = REFERENCE_TYPE;    }  if (tc == REFERENCE_TYPE)    {      if (ec != REFERENCE_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 is an unambiguous accessible base class of *exprtype,     convert statically.  */  {    int distance;    tree path;    distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (exprtype), 1,				  &path);    if (distance >= 0)      return build_vbase_path (PLUS_EXPR, type, expr, path, 0);  }  /* Otherwise *exprtype must be a polymorphic class (have a vtbl).  */  if (TYPE_VIRTUAL_P (TREE_TYPE (exprtype)))    {      tree expr1;      /* if TYPE is `void *', return pointer to complete object.  */      if (tc == POINTER_TYPE	  && TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)	{	  /* if b is an object, dynamic_cast<void *>(&b) == (void *)&b.  */	  if (TREE_CODE (expr) == ADDR_EXPR	      && TREE_CODE (TREE_OPERAND (expr, 0)) == VAR_DECL	      && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE)	    return build1 (NOP_EXPR, type, expr);	  /* Since expr is used twice below, save it.  */	  expr = save_expr (expr);	  expr1 = build_headof (expr);	  if (TREE_TYPE (expr1) != type)	    expr1 = build1 (NOP_EXPR, type, expr1);	  return ifnonnull (expr, expr1);	}      else	{	  tree retval;          tree result, td1, td2, td3, elems, expr2; 	  /* If we got here, we can't convert statically.  Therefore,	     dynamic_cast<D&>(b) (b an object) cannot succeed.  */	  if (ec == REFERENCE_TYPE)	    {	      if (TREE_CODE (expr) == VAR_DECL		  && TREE_CODE (TREE_TYPE (expr)) == RECORD_TYPE)		{		  cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed",			      expr, type);		  return throw_bad_cast ();		}	    }	  /* Ditto for dynamic_cast<D*>(&b).  */	  else if (TREE_CODE (expr) == ADDR_EXPR)	    {	      tree op = TREE_OPERAND (expr, 0);	      if (TREE_CODE (op) == VAR_DECL		  && TREE_CODE (TREE_TYPE (op)) == RECORD_TYPE)		{		  cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed",			      expr, type);		  retval = build_int_2 (0, 0); 		  TREE_TYPE (retval) = type; 		  return retval;		}	    }	  /* Since expr is used twice below, save it.  */	  expr = save_expr (expr);	  expr1 = expr;	  if (tc == REFERENCE_TYPE)	    expr1 = build_unary_op (ADDR_EXPR, expr1, 0);	  /* Build run-time conversion.  */	  expr2 = build_headof (expr1);	  if (ec == POINTER_TYPE)	    td1 = get_tinfo_fn_dynamic (build_indirect_ref (expr, NULL_PTR));	  else	    td1 = get_tinfo_fn_dynamic (expr);	  td1 = decay_conversion (td1);	  	  td2 = decay_conversion	    (get_tinfo_fn (TYPE_MAIN_VARIANT (TREE_TYPE (type))));	  td3 = decay_conversion	    (get_tinfo_fn (TYPE_MAIN_VARIANT (TREE_TYPE (exprtype))));          elems = tree_cons	    (NULL_TREE, td1, tree_cons	     (NULL_TREE, td2, tree_cons	      (NULL_TREE, build_int_2 (1, 0), tree_cons	       (NULL_TREE, expr2, tree_cons		(NULL_TREE, td3, tree_cons		 (NULL_TREE, expr1, NULL_TREE))))));	  dcast_fn = get_identifier ("__dynamic_cast");	  if (IDENTIFIER_GLOBAL_VALUE (dcast_fn))	    dcast_fn = IDENTIFIER_GLOBAL_VALUE (dcast_fn);	  else	    {	      tree tmp;	      push_obstacks (&permanent_obstack, &permanent_obstack);	      tmp = tree_cons		(NULL_TREE, TREE_TYPE (td1), tree_cons		 (NULL_TREE, TREE_TYPE (td1), tree_cons		  (NULL_TREE, integer_type_node, tree_cons		   (NULL_TREE, ptr_type_node, tree_cons		    (NULL_TREE, TREE_TYPE (td1), tree_cons		     (NULL_TREE, ptr_type_node, void_list_node))))));	      tmp = build_function_type (ptr_type_node, tmp);	      dcast_fn = build_lang_decl (FUNCTION_DECL, dcast_fn, tmp);	      DECL_EXTERNAL (dcast_fn) = 1;	      TREE_PUBLIC (dcast_fn) = 1;	      DECL_ARTIFICIAL (dcast_fn) = 1;	      pushdecl_top_level (dcast_fn);	      make_function_rtl (dcast_fn);	      assemble_external (dcast_fn);	      pop_obstacks ();	    }	            result = build_call	    (dcast_fn, TREE_TYPE (TREE_TYPE (dcast_fn)), elems);	  if (tc == REFERENCE_TYPE)	    {	      expr1 = throw_bad_cast ();	      expr1 = build_compound_expr		(expr_tree_cons (NULL_TREE, expr1,			    build_expr_list (NULL_TREE, cp_convert (type, integer_zero_node))));	      TREE_TYPE (expr1) = type;	      result = save_expr (result);	      return build (COND_EXPR, type, result, result, expr1);	    }	  /* Now back to the type we want from a void*.  */	  result = cp_convert (type, result);          return ifnonnull (expr, result);	}    } fail:  cp_error ("cannot dynamic_cast `%E' (of type `%#T') to type `%#T'",	    expr, exprtype, type);  return error_mark_node;}treebuild_dynamic_cast (type, expr)     tree type, expr;{  return convert_from_reference (build_dynamic_cast_1 (type, expr));}/* Build and initialize various sorts of descriptors.  Every descriptor   node has a name associated with it (the name created by mangling).   For this reason, we use the identifier as our access to the __*_desc   nodes, instead of sticking them directly in the types.  Otherwise we   would burden all built-in types (and pointer types) with slots that   we don't necessarily want to use.   For each descriptor we build, we build a variable that contains   the descriptor's information.  When we need this info at runtime,   all we need is access to these variables.   Note: these constructors always return the address of the descriptor   info, since that is simplest for their mutual interaction.  */extern tree const_string_type_node;/* Build an initializer for a __si_type_info node.  */static voidexpand_si_desc (tdecl, type)     tree tdecl;     tree type;{  tree t, elems, fn;  char *name = build_overload_name (type, 1, 1);  tree name_string = combine_strings (build_string (strlen (name)+1, name));  type = BINFO_TYPE (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0));  expand_expr_stmt (get_typeid_1 (type));  t = decay_conversion (get_tinfo_var (type));  elems = tree_cons    (NULL_TREE, decay_conversion (tdecl), tree_cons     (NULL_TREE, decay_conversion (name_string), tree_cons      (NULL_TREE, t, NULL_TREE)));  fn = get_identifier ("__rtti_si");  if (IDENTIFIER_GLOBAL_VALUE (fn))    fn = IDENTIFIER_GLOBAL_VALUE (fn);  else    {      tree tmp;      push_obstacks (&permanent_obstack, &permanent_obstack);      tmp = tree_cons	(NULL_TREE, ptr_type_node, tree_cons	 (NULL_TREE, const_string_type_node, tree_cons	  (NULL_TREE, build_pointer_type (type_info_type_node),	   void_list_node)));      tmp = build_function_type	(void_type_node, tmp);        fn = build_lang_decl (FUNCTION_DECL, fn, tmp);      DECL_EXTERNAL (fn) = 1;      TREE_PUBLIC (fn) = 1;      DECL_ARTIFICIAL (fn) = 1;      pushdecl_top_level (fn);      make_function_rtl (fn);      assemble_external (fn);      pop_obstacks ();    }  fn = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), elems);  expand_expr_stmt (fn);}/* Build an initializer for a __class_type_info node.  */static voidexpand_class_desc (tdecl, type)     tree tdecl;     tree type;{  tree name_string;  tree fn, tmp;  char *name;  int i = CLASSTYPE_N_BASECLASSES (type);  int base_cnt = 0;  tree binfos = TYPE_BINFO_BASETYPES (type);#if 0  /* See code below that used these.  */  tree vb = CLASSTYPE_VBASECLASSES (type);  int n_base = i;#endif  tree base, elems, access, offset, isvir;  tree elt, elts = NULL_TREE;  static tree base_info_type_node;  if (base_info_type_node == NULL_TREE)    {      tree fields [4];      /* A reasonably close approximation of __class_type_info::base_info */      push_obstacks (&permanent_obstack, &permanent_obstack);      base_info_type_node = make_lang_type (RECORD_TYPE);      /* Actually const __user_type_info * */      fields [0] = build_lang_field_decl	(FIELD_DECL, NULL_TREE,	 build_pointer_type (build_type_variant (type_info_type_node, 1, 0)));      fields [1] = build_lang_field_decl	(FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);      DECL_BIT_FIELD (fields[1]) = 1;      DECL_FIELD_SIZE (fields[1]) = 29;      fields [2] = build_lang_field_decl	(FIELD_DECL, NULL_TREE, boolean_type_node);      DECL_BIT_FIELD (fields[2]) = 1;      DECL_FIELD_SIZE (fields[2]) = 1;      /* Actually enum access */      fields [3] = build_lang_field_decl	(FIELD_DECL, NULL_TREE, integer_type_node);      DECL_BIT_FIELD (fields[3]) = 1;      DECL_FIELD_SIZE (fields[3]) = 2;      finish_builtin_type (base_info_type_node, "__base_info", fields,			   3, ptr_type_node);      pop_obstacks ();    }  while (--i >= 0)    {      tree binfo = TREE_VEC_ELT (binfos, i);      expand_expr_stmt (get_typeid_1 (BINFO_TYPE (binfo)));      base = decay_conversion (get_tinfo_var (BINFO_TYPE (binfo)));      if (TREE_VIA_VIRTUAL (binfo))	{	  tree t = BINFO_TYPE (binfo);	  char *name;	  tree field;	  name = (char *) alloca (TYPE_NAME_LENGTH (t)+sizeof (VBASE_NAME)+1);	  sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (t));	  field = lookup_field (type, get_identifier (name), 0, 0);	  offset = size_binop (FLOOR_DIV_EXPR, 		DECL_FIELD_BITPOS (field), size_int (BITS_PER_UNIT));	}      else	offset = BINFO_OFFSET (binfo);      if (TREE_VIA_PUBLIC (binfo))        access = access_public_node;      else if (TREE_VIA_PROTECTED (binfo))	access = access_protected_node;      else	access = access_private_node;      if (TREE_VIA_VIRTUAL (binfo))	isvir = boolean_true_node;      else	isvir = boolean_false_node;      elt = build	(CONSTRUCTOR, base_info_type_node, NULL_TREE, tree_cons	 (NULL_TREE, base, tree_cons	  (NULL_TREE, offset, tree_cons	   (NULL_TREE, isvir, tree_cons	    (NULL_TREE, access, NULL_TREE)))));      TREE_HAS_CONSTRUCTOR (elt) = TREE_CONSTANT (elt) = TREE_STATIC (elt) = 1;      elts = expr_tree_cons (NULL_TREE, elt, elts);      base_cnt++;    }#if 0  i = n_base;  while (vb)    {      tree b;      access = access_public_node;      while (--i >= 0)	{	  b = TREE_VEC_ELT (binfos, i);	  if (BINFO_TYPE (vb) == BINFO_TYPE (b) && TREE_VIA_VIRTUAL (b))	    {	      if (TREE_VIA_PUBLIC (b))		access = access_public_node;	      else if (TREE_VIA_PROTECTED (b))		access = access_protected_node;	      else		access = access_private_node;	      break;	    }	}      base = build_t_desc (BINFO_TYPE (vb), 1);      offset = BINFO_OFFSET (vb);      isvir = build_int_2 (1, 0);      base_list = expr_tree_cons (NULL_TREE, base, base_list);      isvir_list = expr_tree_cons (NULL_TREE, isvir, isvir_list);      acc_list = expr_tree_cons (NULL_TREE, access, acc_list);      off_list = expr_tree_cons (NULL_TREE, offset, off_list);      base_cnt++;      vb = TREE_CHAIN (vb);    }#endif  name = build_overload_name (type, 1, 1);  name_string = combine_strings (build_string (strlen (name)+1, name));  {    tree arrtype = build_array_type (base_info_type_node, NULL_TREE);    elts = build (CONSTRUCTOR, arrtype, NULL_TREE, elts);    TREE_HAS_CONSTRUCTOR (elts) = TREE_CONSTANT (elts)      = TREE_STATIC (elts) = 1;    complete_array_type (arrtype, elts, 1);  }  elems = tree_cons    (NULL_TREE, decay_conversion (tdecl), tree_cons     (NULL_TREE, decay_conversion (name_string), tree_cons      (NULL_TREE, decay_conversion (elts), tree_cons       (NULL_TREE, cp_convert (sizetype, build_int_2 (base_cnt, 0)),	NULL_TREE))));  fn = get_identifier ("__rtti_class");  if (IDENTIFIER_GLOBAL_VALUE (fn))    fn = IDENTIFIER_GLOBAL_VALUE (fn);  else    {      push_obstacks (&permanent_obstack, &permanent_obstack);      tmp = tree_cons	(NULL_TREE, ptr_type_node, tree_cons	 (NULL_TREE, const_string_type_node, tree_cons	  (NULL_TREE, build_pointer_type (base_info_type_node), tree_cons	   (NULL_TREE, sizetype, void_list_node))));      tmp = build_function_type	(void_type_node, tmp);        fn = build_lang_decl (FUNCTION_DECL, fn, tmp);      DECL_EXTERNAL (fn) = 1;      TREE_PUBLIC (fn) = 1;      DECL_ARTIFICIAL (fn) = 1;      pushdecl_top_level (fn);      make_function_rtl (fn);      assemble_external (fn);      pop_obstacks ();    }  fn = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), elems);  expand_expr_stmt (fn);}/* Build an initializer for a __pointer_type_info node.  */static voidexpand_ptr_desc (tdecl, type)     tree tdecl;     tree type;{  tree t, elems, fn;  char *name = build_overload_name (type, 1, 1);  tree name_string = combine_strings (build_string (strlen (name)+1, name));  type = TREE_TYPE (type);  expand_expr_stmt (get_typeid_1 (type));  t = decay_conversion (get_tinfo_var (type));  elems = tree_cons    (NULL_TREE, decay_conversion (tdecl), tree_cons     (NULL_TREE, decay_conversion (name_string), tree_cons      (NULL_TREE, t, NULL_TREE)));  fn = get_identifier ("__rtti_ptr");  if (IDENTIFIER_GLOBAL_VALUE (fn))    fn = IDENTIFIER_GLOBAL_VALUE (fn);  else    {      tree tmp;      push_obstacks (&permanent_obstack, &permanent_obstack);      tmp = tree_cons	(NULL_TREE, ptr_type_node, tree_cons	 (NULL_TREE, const_string_type_node, tree_cons	  (NULL_TREE, build_pointer_type (type_info_type_node),	   void_list_node)));      tmp = build_function_type	(void_type_node, tmp);        fn = build_lang_decl (FUNCTION_DECL, fn, tmp);      DECL_EXTERNAL (fn) = 1;      TREE_PUBLIC (fn) = 1;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?