📄 rtti.c
字号:
TREE_TYPE (name) = copy_to_permanent (type); pushdecl_top_level (d); make_function_rtl (d); mark_inline_for_output (d); pop_obstacks (); return d;}/* Likewise, but also mark it used. Called by various EH and RTTI code. */treeget_tinfo_fn (type) tree type;{ tree d = get_tinfo_fn_unused (type); mark_used (d); return d;}treeget_typeid_1 (type) tree type;{ tree t; 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 (TYPE_SIZE (type_info_type_node) == NULL_TREE) { error ("must #include <typeinfo> before using typeid"); return error_mark_node; } if (! flag_rtti) error ("requesting typeid with -fno-rtti"); 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); if (TYPE_SIZE (complete_type (type)) == NULL_TREE) { cp_error ("taking typeid of incomplete type `%T'", type); return error_mark_node; } 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; enum tree_code ec; tree dcast_fn; tree old_expr = expr; if (TREE_CODE (expr) == OFFSET_REF) expr = resolve_offset_ref (expr); exprtype = TREE_TYPE (expr); 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 (!at_least_as_qualified_p (TREE_TYPE (type), TREE_TYPE (exprtype))) 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) 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_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 (!at_least_as_qualified_p (TREE_TYPE (type), TREE_TYPE (exprtype))) 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 == -2) { cp_error ("dynamic_cast from `%T' to ambiguous base class `%T'", TREE_TYPE (exprtype), TREE_TYPE (type)); return error_mark_node; } if (distance == -3) { cp_error ("dynamic_cast from `%T' to private base class `%T'", TREE_TYPE (exprtype), TREE_TYPE (type)); return error_mark_node; } 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 (old_expr) == VAR_DECL && TREE_CODE (TREE_TYPE (old_expr)) == RECORD_TYPE) { cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed", old_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", op, 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); pop_obstacks (); } mark_used (dcast_fn); 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;{ if (type == error_mark_node || expr == error_mark_node) return error_mark_node; if (processing_template_decl) return build_min (DYNAMIC_CAST_EXPR, copy_to_permanent (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; const 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); pop_obstacks (); } mark_used (fn); 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -