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