📄 pt.c
字号:
static struct tinst_level *free_tinst_level = 0;static int tinst_depth = 0;int max_tinst_depth = 17;intpush_tinst_level (name) tree name;{ struct tinst_level *new; tree global = IDENTIFIER_GLOBAL_VALUE (name); if (tinst_depth >= max_tinst_depth) { error ("template instantiation depth exceeds maximum of %d", max_tinst_depth); cp_error (" instantiating `%D'", name); return 0; } if (free_tinst_level) { new = free_tinst_level; free_tinst_level = new->next; } else new = (struct tinst_level *) xmalloc (sizeof (struct tinst_level)); new->classname = name; if (global) { new->line = DECL_SOURCE_LINE (global); new->file = DECL_SOURCE_FILE (global); } else { new->line = lineno; new->file = input_filename; } new->next = current_tinst_level; current_tinst_level = new; ++tinst_depth; return 1;}voidpop_tinst_level (){ struct tinst_level *old = current_tinst_level; current_tinst_level = old->next; old->next = free_tinst_level; free_tinst_level = old; --tinst_depth;}struct tinst_level *tinst_for_decl (){ struct tinst_level *p = current_tinst_level; if (p) for (; p->next ; p = p->next ) ; return p;}treeinstantiate_class_template (classname, setup_parse) tree classname; int setup_parse;{ struct template_info *template_info; tree template, t1; if (classname == error_mark_node) return error_mark_node; my_friendly_assert (TREE_CODE (classname) == IDENTIFIER_NODE, 278); template = IDENTIFIER_TEMPLATE (classname); if (IDENTIFIER_HAS_TYPE_VALUE (classname)) { tree type = IDENTIFIER_TYPE_VALUE (classname); if (TREE_CODE (type) == UNINSTANTIATED_P_TYPE) return type; if (TYPE_BEING_DEFINED (type) || TYPE_SIZE (type) || CLASSTYPE_USE_TEMPLATE (type) != 0) return type; } /* If IDENTIFIER_LOCAL_VALUE is already set on this template classname (it's something like `foo<int>'), that means we're already working on the instantiation for it. Normally, a classname comes in with nothing but its IDENTIFIER_TEMPLATE slot set. If we were to try to instantiate this again, we'd get a redeclaration error. Since we're already working on it, we'll pass back this classname's TYPE_DECL (it's the value of the classname's IDENTIFIER_LOCAL_VALUE). Only do this if we're setting things up for the parser, though---if we're just trying to instantiate it (e.g., via tsubst) we can trip up cuz it may not have an IDENTIFIER_TYPE_VALUE when it will need one. */ if (setup_parse && IDENTIFIER_LOCAL_VALUE (classname)) return IDENTIFIER_LOCAL_VALUE (classname); if (uses_template_parms (classname)) { if (!TREE_TYPE (classname)) { tree t = make_lang_type (RECORD_TYPE); tree d = build_decl (TYPE_DECL, classname, t); DECL_NAME (d) = classname; TYPE_NAME (t) = d; pushdecl (d); } return NULL_TREE; } t1 = TREE_PURPOSE (template); my_friendly_assert (TREE_CODE (t1) == TEMPLATE_DECL, 279); /* If a template is declared but not defined, accept it; don't crash. Later uses requiring the definition will be flagged as errors by other code. Thanks to niklas@appli.se for this bug fix. */ if (DECL_TEMPLATE_INFO (t1)->text == 0) setup_parse = 0; push_to_top_level (); template_info = DECL_TEMPLATE_INFO (t1); if (setup_parse && push_tinst_level (classname)) { push_template_decls (DECL_TEMPLATE_PARMS (TREE_PURPOSE (template)), TREE_VALUE (template), 0); set_current_level_tags_transparency (1); feed_input (template_info->text, template_info->length, (struct obstack *)0); lineno = template_info->lineno; input_filename = template_info->filename; /* Get interface/implementation back in sync. */ extract_interface_info (); overload_template_name (classname, 0); /* Kludge so that we don't get screwed by our own base classes. */ TYPE_BEING_DEFINED (TREE_TYPE (classname)) = 1; yychar = PRE_PARSED_CLASS_DECL; yylval.ttype = classname; processing_template_defn++; if (!flag_external_templates) interface_unknown++; template_classes = perm_tree_cons (classname, NULL_TREE, template_classes); } else { tree t, decl, id, tmpl; id = classname; tmpl = TREE_PURPOSE (IDENTIFIER_TEMPLATE (id)); t = xref_tag (DECL_TEMPLATE_INFO (tmpl)->aggr, id, NULL_TREE, 0); my_friendly_assert (TREE_CODE (t) == RECORD_TYPE || TREE_CODE (t) == UNION_TYPE, 280); /* Now, put a copy of the decl in global scope, to avoid * recursive expansion. */ decl = IDENTIFIER_LOCAL_VALUE (id); if (!decl) decl = IDENTIFIER_CLASS_VALUE (id); if (decl) { my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 281); /* We'd better make sure we're on the permanent obstack or else * we'll get a "friendly" abort 124 in pushdecl. Perhaps a * copy_to_permanent would be sufficient here, but then a * sharing problem might occur. I don't know -- niklas@appli.se */ push_obstacks (&permanent_obstack, &permanent_obstack); pushdecl_top_level (copy_node (decl)); pop_obstacks (); } pop_from_top_level (); } return NULL_TREE;}static intlist_eq (t1, t2) tree t1, t2;{ if (t1 == NULL_TREE) return t2 == NULL_TREE; if (t2 == NULL_TREE) return 0; /* Don't care if one declares its arg const and the other doesn't -- the main variant of the arg type is all that matters. */ if (TYPE_MAIN_VARIANT (TREE_VALUE (t1)) != TYPE_MAIN_VARIANT (TREE_VALUE (t2))) return 0; return list_eq (TREE_CHAIN (t1), TREE_CHAIN (t2));}static tree lookup_nested_type_by_name (ctype, name) tree ctype, name;{ tree t; for (t = CLASSTYPE_TAGS (ctype); t; t = TREE_CHAIN (t)) { if (name == TREE_PURPOSE (t)) return TREE_VALUE (t); } return NULL_TREE;}static treesearch_nested_type_in_tmpl (tmpl, type) tree tmpl, type;{ tree t; if (tmpl == NULL || TYPE_CONTEXT(type) == NULL) return tmpl; t = search_nested_type_in_tmpl (tmpl, TYPE_CONTEXT(type)); if (t == NULL) return t; t = lookup_nested_type_by_name(t, DECL_NAME(TYPE_NAME(type))); return t;}treetsubst (t, args, nargs, in_decl) tree t, *args; int nargs; tree in_decl;{ tree type; if (t == NULL_TREE || t == error_mark_node) return t; type = TREE_TYPE (t); if (type /* Minor optimization. ?? Are these really the most frequent cases? Is the savings significant? */ && type != integer_type_node && type != void_type_node && type != char_type_node) type = tsubst (type, args, nargs, in_decl); switch (TREE_CODE (t)) { case RECORD_TYPE: if (TYPE_PTRMEMFUNC_P (t)) return build_ptrmemfunc_type (tsubst (TYPE_PTRMEMFUNC_FN_TYPE (t), args, nargs, in_decl)); /* else fall through */ case ERROR_MARK: case IDENTIFIER_NODE: case OP_IDENTIFIER: case VOID_TYPE: case REAL_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: case INTEGER_CST: case REAL_CST: case STRING_CST: case UNION_TYPE: return t; case INTEGER_TYPE: if (t == integer_type_node) return t; if (TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST && TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST) return t; return build_index_2_type (tsubst (TYPE_MIN_VALUE (t), args, nargs, in_decl), tsubst (TYPE_MAX_VALUE (t), args, nargs, in_decl)); case TEMPLATE_TYPE_PARM: { tree arg = args[TEMPLATE_TYPE_IDX (t)]; return cp_build_type_variant (arg, TYPE_READONLY (arg) || TYPE_READONLY (t), TYPE_VOLATILE (arg) || TYPE_VOLATILE (t)); } case TEMPLATE_CONST_PARM: return args[TEMPLATE_CONST_IDX (t)]; case FUNCTION_DECL: { tree r; tree fnargs, result; if (type == TREE_TYPE (t) && (DECL_CONTEXT (t) == NULL_TREE || TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (t))) != 't')) return t; fnargs = tsubst (DECL_ARGUMENTS (t), args, nargs, t); result = tsubst (DECL_RESULT (t), args, nargs, t); if (DECL_CONTEXT (t) != NULL_TREE && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (t))) == 't') { /* Look it up in that class, and return the decl node there, instead of creating a new one. */ tree ctx, methods, name, method; int n_methods; int i, found = 0; name = DECL_NAME (t); ctx = tsubst (DECL_CONTEXT (t), args, nargs, t); methods = CLASSTYPE_METHOD_VEC (ctx); if (methods == NULL_TREE) /* No methods at all -- no way this one can match. */ goto no_match; n_methods = TREE_VEC_LENGTH (methods); r = NULL_TREE; if (!strncmp (OPERATOR_TYPENAME_FORMAT, IDENTIFIER_POINTER (name), sizeof (OPERATOR_TYPENAME_FORMAT) - 1)) { /* Type-conversion operator. Reconstruct the name, in case it's the name of one of the template's parameters. */ name = build_typename_overload (TREE_TYPE (type)); } if (DECL_CONTEXT (t) != NULL_TREE && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (t))) == 't' && constructor_name (DECL_CONTEXT (t)) == DECL_NAME (t)) name = constructor_name (ctx); if (DECL_CONSTRUCTOR_P (t) && TYPE_USES_VIRTUAL_BASECLASSES (ctx)) { /* Since we didn't know that this class had virtual bases until after we instantiated it, we have to recreate the arguments to this constructor, as otherwise it would miss the __in_chrg parameter. */ tree newtype, parm; tree parms = TREE_CHAIN (TYPE_ARG_TYPES (type)); parms = hash_tree_chain (integer_type_node, parms); newtype = build_cplus_method_type (ctx, TREE_TYPE (type), parms); newtype = build_type_variant (newtype, TYPE_READONLY (type), TYPE_VOLATILE (type)); type = newtype; fnargs = copy_node (DECL_ARGUMENTS (t)); TREE_CHAIN (fnargs) = TREE_CHAIN (DECL_ARGUMENTS (t)); /* In this case we need "in-charge" flag saying whether this constructor is responsible for initialization of virtual baseclasses or not. */ parm = build_decl (PARM_DECL, in_charge_identifier, integer_type_node); /* Mark the artificial `__in_chrg' parameter as "artificial". */ SET_DECL_ARTIFICIAL (parm); DECL_ARG_TYPE (parm) = integer_type_node; DECL_REGISTER (parm) = 1; TREE_CHAIN (parm) = TREE_CHAIN (fnargs); TREE_CHAIN (fnargs) = parm; fnargs = tsubst (fnargs, args, nargs, t); }#if 0 fprintf (stderr, "\nfor function %s in class %s:\n", IDENTIFIER_POINTER (name), IDENTIFIER_POINTER (TYPE_IDENTIFIER (ctx)));#endif for (i = 0; i < n_methods; i++) { int pass; method = TREE_VEC_ELT (methods, i); if (method == NULL_TREE || DECL_NAME (method) != name) continue; pass = 0; maybe_error: for (; method; method = DECL_CHAIN (method)) { my_friendly_assert (TREE_CODE (method) == FUNCTION_DECL, 282); if (! comptypes (type, TREE_TYPE (method), 1)) { tree mtype = TREE_TYPE (method); tree t1, t2; /* Keep looking for a method that matches perfectly. This takes care of the problem where destructors (which have implicit int args) look like constructors which have an int arg. */ if (pass == 0) continue; t1 = TYPE_ARG_TYPES (mtype); t2 = TYPE_ARG_TYPES (type); if (TREE_CODE (mtype) == FUNCTION_TYPE) t2 = TREE_CHAIN (t2); if (list_eq (t1, t2)) { if (TREE_CODE (mtype) == FUNCTION_TYPE) { tree newtype; newtype = build_function_type (TREE_TYPE (type), TYPE_ARG_TYPES (type)); newtype = build_type_variant (newtype, TYPE_READONLY (type), TYPE_VOLATILE (type)); type = newtype; if (TREE_TYPE (type) != TREE_TYPE (mtype)) goto maybe_bad_return_type; } else if (TYPE_METHOD_BASETYPE (mtype) == TYPE_METHOD_BASETYPE (type)) { /* Types didn't match, but arg types and `this' do match, so the return type is all that should be messing it up. */ maybe_bad_return_type: if (TREE_TYPE (type) != TREE_TYPE (mtype)) error ("inconsistent return types for method `%s' in class `%s'", IDENTIFIER_POINTER (name), IDENTIFIER_POINTER (TYPE_IDENTIFIER (ctx))); } r = method; break; } found = 1; continue; }#if 0 fprintf (stderr, "\tfound %s\n\n", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (method)));#endif if (DECL_ARTIFICIAL (method)) { cp_error ("template for method `%D' which has default implementation in class `%T'", name, ctx); if (in_decl) cp_error_at ("in attempt to instantiate `%D' declared at this point in file", in_decl); return error_mark_node; } if (DECL_ARGUMENTS (method) && ! TREE_PERMANENT (DECL_ARGUMENTS (method))) /* @@ Is this early enough? Might we want to do this instead while processing the expansion? */ DECL_ARGUMENTS (method) = tsubst (DECL_ARGUMENTS (t), args, nargs, t); r = method; break; } if (r == NULL_TREE && pass == 0) { pass = 1; method = TREE_VEC_ELT (methods, i);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -