--- gcc/cp/pt.c 2018/04/24 18:20:20 1.1 +++ gcc/cp/pt.c 2018/04/24 18:26:57 1.1.1.2 @@ -1,5 +1,5 @@ /* Handle parameterized types (templates) for GNU C++. - Copyright (C) 1992, 1993 Free Software Foundation, Inc. + Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. Written by Ken Raeburn (raeburn@cygnus.com) while at Watchmaker Computing. This file is part of GNU CC. @@ -16,7 +16,8 @@ GNU General Public License for more deta You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* Known bugs or deficiencies include: * templates for class static data don't work (methods only) @@ -38,9 +39,10 @@ the Free Software Foundation, 675 Mass A #include "decl.h" #include "parse.h" #include "lex.h" +#include "output.h" +#include "defaults.h" extern struct obstack permanent_obstack; -extern tree grokdeclarator (); extern int lineno; extern char *input_filename; @@ -49,6 +51,11 @@ struct pending_inline *pending_template_ int processing_template_decl; int processing_template_defn; +/* This is a kludge to handle instantiation of template methods that are + used before their definition. It should not be necessary after the + template rewrite. */ +static tree template_classes; + #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free @@ -94,11 +101,10 @@ process_template_parm (list, next) my_friendly_assert (TREE_CODE (TREE_PURPOSE (parm)) == TREE_LIST, 260); /* is a const-param */ parm = grokdeclarator (TREE_VALUE (parm), TREE_PURPOSE (parm), - PARM, 0, NULL_TREE); + PARM, 0, NULL_TREE, NULL_TREE); /* A template parameter is not modifiable. */ TREE_READONLY (parm) = 1; - if (TREE_CODE (TREE_TYPE (parm)) == RECORD_TYPE - || TREE_CODE (TREE_TYPE (parm)) == UNION_TYPE) + if (IS_AGGR_TYPE (TREE_TYPE (parm))) { sorry ("aggregate template parameter types"); TREE_TYPE (parm) = void_type_node; @@ -129,6 +135,7 @@ process_template_parm (list, next) defval = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (defval)); } } + SET_DECL_ARTIFICIAL (decl); pushdecl (decl); parm = build_tree_list (defval, parm); return chainon (list, parm); @@ -231,7 +238,7 @@ end_template_decl (d1, d2, is_class, def my_friendly_assert (code == BIT_NOT_EXPR || code == OP_IDENTIFIER || code == SCOPE_REF, 264); - d2 = grokdeclarator (d2, NULL_TREE, MEMFUNCDEF, 0, NULL_TREE); + d2 = grokdeclarator (d2, NULL_TREE, MEMFUNCDEF, 0, NULL_TREE, NULL_TREE); decl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (d2), TREE_TYPE (d2)); DECL_TEMPLATE_RESULT (decl) = d2; @@ -239,8 +246,10 @@ end_template_decl (d1, d2, is_class, def DECL_CLASS_CONTEXT (decl) = DECL_CLASS_CONTEXT (d2); DECL_NAME (decl) = DECL_NAME (d2); TREE_TYPE (decl) = TREE_TYPE (d2); - if (interface_unknown && flag_external_templates && ! DECL_IN_SYSTEM_HEADER (decl)) - warn_if_unknown_interface (); + if (interface_unknown && flag_external_templates + && ! flag_alt_external_templates + && ! DECL_IN_SYSTEM_HEADER (decl)) + warn_if_unknown_interface (decl); TREE_PUBLIC (decl) = TREE_PUBLIC (d2) = flag_external_templates && !interface_unknown; DECL_EXTERNAL (decl) = (DECL_EXTERNAL (d2) && !(DECL_CLASS_CONTEXT (d2) @@ -319,48 +328,7 @@ end_template_decl (d1, d2, is_class, def (void) get_pending_sizes (); } -/* If TYPE contains a template parm type, then substitute that type - with its actual type that is found in TVEC. */ -static void -grok_template_type (tvec, type) - tree tvec; - tree* type; -{ - switch (TREE_CODE (*type)) - { - case TEMPLATE_TYPE_PARM: - if (*type != TYPE_MAIN_VARIANT (*type)) - { - /* we are here for cases like const T* etc. */ - grok_template_type (tvec, &TYPE_MAIN_VARIANT (*type)); - *type = cp_build_type_variant (TYPE_MAIN_VARIANT (*type), - TYPE_READONLY (*type), - TYPE_VOLATILE (*type)); - } - else - *type = TREE_VEC_ELT (tvec, TEMPLATE_TYPE_IDX (*type)); - return; - case POINTER_TYPE: - case REFERENCE_TYPE: - grok_template_type (tvec, &TREE_TYPE (*type)); - return; - case FUNCTION_TYPE: - { - tree p; - - /* take care of function's return type first */ - grok_template_type (tvec, &TREE_TYPE (*type)); - - /* take care of function's arguments */ - for (p = TYPE_ARG_TYPES (*type); p; p = TREE_CHAIN (p)) - grok_template_type (tvec, &TREE_VALUE (p)); - return; - } - default: - break; - } - return; -} +tree tsubst PROTO ((tree, tree*, int, tree)); /* Convert all template arguments to their appropriate types, and return a vector containing the resulting values. If any error occurs, return @@ -438,16 +406,11 @@ coerce_template_parms (parms, arglist, i } if (is_type) val = groktypename (arg); - else if (TREE_CODE (arg) == STRING_CST) - { - cp_error ("string literal %E is not a valid template argument", arg); - error ("because it is the address of an object with static linkage"); - val = error_mark_node; - } else { - grok_template_type (vec, &TREE_TYPE (parm)); - val = digest_init (TREE_TYPE (parm), arg, (tree *) 0); + tree t = tsubst (TREE_TYPE (parm), &TREE_VEC_ELT (vec, 0), + TREE_VEC_LENGTH (vec), in_decl); + val = digest_init (t, arg, (tree *) 0); if (val == error_mark_node) ; @@ -461,14 +424,41 @@ coerce_template_parms (parms, arglist, i arg); val = error_mark_node; } - else if (TREE_CODE (val) == ADDR_EXPR) + else if (POINTER_TYPE_P (TREE_TYPE (val)) + && ! integer_zerop (val) + && TREE_CODE (TREE_TYPE (TREE_TYPE (val))) != OFFSET_TYPE + && TREE_CODE (TREE_TYPE (TREE_TYPE (val))) != METHOD_TYPE) { - tree a = TREE_OPERAND (val, 0); - if ((TREE_CODE (a) == VAR_DECL - || TREE_CODE (a) == FUNCTION_DECL) - && !TREE_PUBLIC (a)) + t = val; + STRIP_NOPS (t); + if (TREE_CODE (t) == ADDR_EXPR) { - cp_error ("address of non-extern `%E' cannot be used as template argument", a); + tree a = TREE_OPERAND (t, 0); + STRIP_NOPS (a); + if (TREE_CODE (a) == STRING_CST) + { + cp_error ("string literal %E is not a valid template argument", a); + error ("because it is the address of an object with static linkage"); + val = error_mark_node; + } + else if (TREE_CODE (a) != VAR_DECL + && TREE_CODE (a) != FUNCTION_DECL) + goto bad; + else if (! DECL_PUBLIC (a)) + { + cp_error ("address of non-extern `%E' cannot be used as template argument", a); + val = error_mark_node; + } + } + else + { + bad: + cp_error ("`%E' is not a valid template argument", t); + error ("it must be %s%s with external linkage", + TREE_CODE (TREE_TYPE (val)) == POINTER_TYPE + ? "a pointer to " : "", + TREE_CODE (TREE_TYPE (TREE_TYPE (val))) == FUNCTION_TYPE + ? "a function" : "an object"); val = error_mark_node; } } @@ -675,21 +665,26 @@ push_template_decls (parmlist, arglist, { /* add const decl to namespace */ tree val; + tree parmtype; if (requires_type) { error ("template use error: value provided where type needed"); continue; } - val = digest_init (TREE_TYPE (parm), arg, (tree *) 0); + parmtype = tsubst (TREE_TYPE (parm), &TREE_VEC_ELT (arglist, 0), + TREE_VEC_LENGTH (arglist), NULL_TREE); + val = digest_init (parmtype, arg, (tree *) 0); if (val != error_mark_node) { - decl = build_decl (VAR_DECL, DECL_NAME (parm), TREE_TYPE (parm)); + decl = build_decl (CONST_DECL, DECL_NAME (parm), + parmtype); DECL_INITIAL (decl) = val; TREE_READONLY (decl) = 1; } } if (decl != 0) { + SET_DECL_ARTIFICIAL (decl); layout_decl (decl, 0); if (class_level) pushdecl_class_level (decl); @@ -751,6 +746,8 @@ uses_template_parms (t) case REFERENCE_TYPE: return uses_template_parms (TREE_TYPE (t)); case RECORD_TYPE: + if (TYPE_PTRMEMFUNC_FLAG (t)) + return uses_template_parms (TYPE_PTRMEMFUNC_FN_TYPE (t)); case UNION_TYPE: if (!TYPE_NAME (t)) return 0; @@ -770,7 +767,7 @@ uses_template_parms (t) return 1; return uses_template_parms (TREE_TYPE (t)); case METHOD_TYPE: - if (uses_template_parms (TYPE_OFFSET_BASETYPE (t))) + if (uses_template_parms (TYPE_METHOD_BASETYPE (t))) return 1; if (uses_template_parms (TYPE_ARG_TYPES (t))) return 1; @@ -834,6 +831,11 @@ uses_template_parms (t) case UNINSTANTIATED_P_TYPE: return 1; + case CONSTRUCTOR: + if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t))) + return uses_template_parms (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (t))); + /* else fall through */ + default: switch (TREE_CODE_CLASS (TREE_CODE (t))) { @@ -898,19 +900,6 @@ instantiate_member_templates (classname) &TREE_VEC_ELT (parmvec, 0)); type = IDENTIFIER_TYPE_VALUE (id); my_friendly_assert (type != 0, 277); - if (flag_external_templates) - { - if (CLASSTYPE_INTERFACE_UNKNOWN (type)) - { - DECL_EXTERNAL (t2) = 0; - TREE_PUBLIC (t2) = 0; - } - else - { - DECL_EXTERNAL (t2) = CLASSTYPE_INTERFACE_ONLY (type); - TREE_PUBLIC (t2) = 1; - } - } break; case 1: /* Failure. */ @@ -926,16 +915,26 @@ instantiate_member_templates (classname) } } -struct tinst_level *current_tinst_level = 0; -struct tinst_level *free_tinst_level = 0; +static struct tinst_level *current_tinst_level = 0; +static struct tinst_level *free_tinst_level = 0; +static int tinst_depth = 0; +int max_tinst_depth = 17; -void +int push_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; @@ -957,6 +956,8 @@ push_tinst_level (name) } new->next = current_tinst_level; current_tinst_level = new; + ++tinst_depth; + return 1; } void @@ -967,6 +968,7 @@ pop_tinst_level () current_tinst_level = old->next; old->next = free_tinst_level; free_tinst_level = old; + --tinst_depth; } struct tinst_level * @@ -1042,9 +1044,8 @@ instantiate_class_template (classname, s push_to_top_level (); template_info = DECL_TEMPLATE_INFO (t1); - if (setup_parse) + if (setup_parse && push_tinst_level (classname)) { - push_tinst_level (classname); push_template_decls (DECL_TEMPLATE_PARMS (TREE_PURPOSE (template)), TREE_VALUE (template), 0); set_current_level_tags_transparency (1); @@ -1061,6 +1062,8 @@ instantiate_class_template (classname, s processing_template_defn++; if (!flag_external_templates) interface_unknown++; + template_classes + = perm_tree_cons (classname, NULL_TREE, template_classes); } else { @@ -1138,7 +1141,7 @@ search_nested_type_in_tmpl (tmpl, type) return t; } -static tree +tree tsubst (t, args, nargs, in_decl) tree t, *args; int nargs; @@ -1157,9 +1160,8 @@ tsubst (t, args, nargs, in_decl) && type != integer_type_node && type != void_type_node && type != char_type_node) - type = cp_build_type_variant (tsubst (type, args, nargs, in_decl), - TYPE_READONLY (type), - TYPE_VOLATILE (type)); + type = tsubst (type, args, nargs, in_decl); + switch (TREE_CODE (t)) { case RECORD_TYPE: @@ -1247,6 +1249,39 @@ tsubst (t, args, nargs, in_decl) && 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), @@ -1396,17 +1431,21 @@ tsubst (t, args, nargs, in_decl) r = build_lang_decl (FUNCTION_DECL, r, type); DECL_ASSEMBLER_NAME (r) = a; } - else if (DECL_INLINE (r) && DECL_SAVED_INSNS (r)) + else if (TREE_STATIC (r)) { /* This overrides the template version, use it. */ return r; } } } - TREE_PUBLIC (r) = TREE_PUBLIC (t); - DECL_EXTERNAL (r) = DECL_EXTERNAL (t); - TREE_STATIC (r) = TREE_STATIC (t); + TREE_PUBLIC (r) = 1; + DECL_EXTERNAL (r) = 1; + TREE_STATIC (r) = 0; + DECL_INTERFACE_KNOWN (r) = 0; DECL_INLINE (r) = DECL_INLINE (t); + DECL_THIS_INLINE (r) = DECL_THIS_INLINE (t); + TREE_READONLY (r) = TREE_READONLY (t); + TREE_THIS_VOLATILE (r) = TREE_THIS_VOLATILE (t); { #if 0 /* Maybe later. -jason */ struct tinst_level *til = tinst_for_decl(); @@ -1441,6 +1480,13 @@ tsubst (t, args, nargs, in_decl) tree r; r = build_decl (PARM_DECL, DECL_NAME (t), type); DECL_INITIAL (r) = TREE_TYPE (r); + DECL_ARTIFICIAL (r) = DECL_ARTIFICIAL (t); +#ifdef PROMOTE_PROTOTYPES + if ((TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (r) = integer_type_node; +#endif if (TREE_CHAIN (t)) TREE_CHAIN (r) = tsubst (TREE_CHAIN (t), args, nargs, TREE_CHAIN (t)); return r; @@ -1521,7 +1567,7 @@ tsubst (t, args, nargs, in_decl) case FUNCTION_TYPE: case METHOD_TYPE: { - tree values = TYPE_VALUES (t); /* same as TYPE_ARG_TYPES */ + tree values = TYPE_ARG_TYPES (t); tree context = TYPE_CONTEXT (t); tree new_value; @@ -1649,12 +1695,16 @@ instantiate_template (tmpl, targ_ptr) my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 283); len = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (tmpl)); + i = len; + while (i--) + targ_ptr[i] = copy_to_permanent (targ_ptr[i]); + for (fndecl = DECL_TEMPLATE_INSTANTIATIONS (tmpl); fndecl; fndecl = TREE_CHAIN (fndecl)) { tree *t1 = &TREE_VEC_ELT (TREE_PURPOSE (fndecl), 0); for (i = len - 1; i >= 0; i--) - if (t1[i] != targ_ptr[i]) + if (simple_cst_equal (t1[i], targ_ptr[i]) <= 0) goto no_match; /* Here, we have a match. */ @@ -1677,16 +1727,16 @@ instantiate_template (tmpl, targ_ptr) if (fndecl == error_mark_node) goto exit; + assemble_external (fndecl); + /* If it's a static member fn in the template, we need to change it into a FUNCTION_TYPE and chop off its this pointer. */ if (TREE_CODE (TREE_TYPE (DECL_RESULT (tmpl))) == METHOD_TYPE && DECL_STATIC_FUNCTION_P (fndecl)) { - tree olddecl = DECL_RESULT (tmpl); revert_static_member_fn (&DECL_RESULT (tmpl), NULL, NULL); /* Chop off the this pointer that grokclassfn so kindly added for us (it didn't know yet if the fn was static or not). */ - DECL_ARGUMENTS (olddecl) = TREE_CHAIN (DECL_ARGUMENTS (olddecl)); DECL_ARGUMENTS (fndecl) = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); } @@ -1694,7 +1744,7 @@ instantiate_template (tmpl, targ_ptr) /* If we have a preexisting version of this function, don't expand the template version, use the other instead. */ - if (DECL_INLINE (fndecl) && DECL_SAVED_INSNS (fndecl)) + if (TREE_STATIC (fndecl) || DECL_TEMPLATE_SPECIALIZATION (fndecl)) { SET_DECL_TEMPLATE_SPECIALIZATION (fndecl); p = (struct pending_inline *)0; @@ -1702,6 +1752,7 @@ instantiate_template (tmpl, targ_ptr) else if (t->text) { SET_DECL_IMPLICIT_INSTANTIATION (fndecl); + repo_template_used (fndecl); p = (struct pending_inline *) permalloc (sizeof (struct pending_inline)); p->parm_vec = t->parm_vec; p->bindings = targs; @@ -1718,10 +1769,21 @@ instantiate_template (tmpl, targ_ptr) input_filename = p->filename = t->filename; extract_interface_info (); - - if (interface_unknown && flag_external_templates && ! DECL_IN_SYSTEM_HEADER (tmpl)) - warn_if_unknown_interface (); - if (interface_unknown || !flag_external_templates) + + if (interface_unknown && flag_external_templates) + { + if (DECL_CLASS_CONTEXT (fndecl) + && CLASSTYPE_INTERFACE_KNOWN (DECL_CLASS_CONTEXT (fndecl))) + { + interface_unknown = 0; + interface_only + = CLASSTYPE_INTERFACE_ONLY (DECL_CLASS_CONTEXT (fndecl)); + } + else if (! DECL_IN_SYSTEM_HEADER (tmpl)) + warn_if_unknown_interface (tmpl); + } + + if (interface_unknown || ! flag_external_templates) p->interface = 1; /* unknown */ else p->interface = interface_only ? 0 : 2; @@ -1813,7 +1875,7 @@ overload_template_name (id, classlevel) } #endif - t = xref_tag (tinfo->aggr, id, NULL_TREE, 0); + t = xref_tag (tinfo->aggr, id, NULL_TREE, 1); my_friendly_assert (TREE_CODE (t) == RECORD_TYPE || TREE_CODE (t) == UNION_TYPE || TREE_CODE (t) == UNINSTANTIATED_P_TYPE, 286); @@ -1844,12 +1906,13 @@ overload_template_name (id, classlevel) #endif } +extern struct pending_input *to_be_restored; + /* NAME is the IDENTIFIER value of a PRE_PARSED_CLASS_DECL. */ void end_template_instantiation (name) tree name; { - extern struct pending_input *to_be_restored; tree t, decl; processing_template_defn--; @@ -1995,6 +2058,15 @@ type_unification (tparms, targs, parms, return 1; if (arg == unknown_type_node) return 1; + + if (! uses_template_parms (parm) + && TREE_CODE_CLASS (TREE_CODE (arg)) != 't') + { + if (can_convert_arg (parm, TREE_TYPE (arg), arg)) + continue; + return 1; + } + #if 0 if (TREE_CODE (arg) == VAR_DECL) arg = TREE_TYPE (arg); @@ -2004,6 +2076,23 @@ type_unification (tparms, targs, parms, if (TREE_CODE_CLASS (TREE_CODE (arg)) != 't') { my_friendly_assert (TREE_TYPE (arg) != NULL_TREE, 293); + if (TREE_CODE (arg) == TREE_LIST + && TREE_TYPE (arg) == unknown_type_node + && TREE_CODE (TREE_VALUE (arg)) == TEMPLATE_DECL) + { + int nsubsts, ntparms; + tree *targs; + + /* Have to back unify here */ + arg = TREE_VALUE (arg); + nsubsts = 0; + ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (arg)); + targs = (tree *) alloca (sizeof (tree) * ntparms); + parm = tree_cons (NULL_TREE, parm, NULL_TREE); + return type_unification (DECL_TEMPLATE_PARMS (arg), targs, + TYPE_ARG_TYPES (TREE_TYPE (arg)), + parm, &nsubsts, 0); + } arg = TREE_TYPE (arg); } #endif @@ -2145,6 +2234,8 @@ unify (tparms, targs, ntparms, parm, arg nsubsts); case REFERENCE_TYPE: + if (TREE_CODE (arg) == REFERENCE_TYPE) + arg = TREE_TYPE (arg); return unify (tparms, targs, ntparms, TREE_TYPE (parm), arg, nsubsts); case ARRAY_TYPE: @@ -2187,8 +2278,6 @@ unify (tparms, targs, ntparms, parm, arg tree t1, t2; t1 = TREE_OPERAND (parm, 0); t2 = TREE_OPERAND (parm, 1); - if (TREE_CODE (t1) != TEMPLATE_CONST_PARM) - return 1; return unify (tparms, targs, ntparms, t1, fold (build (PLUS_EXPR, integer_type_node, arg, t2)), nsubsts); @@ -2212,22 +2301,19 @@ unify (tparms, targs, ntparms, parm, arg case UNINSTANTIATED_P_TYPE: { tree a; - /* Unification of something that is not a template fails. (mrs) */ - if (TYPE_NAME (arg) == 0) + /* Unification of something that is not a class fails. */ + if (! IS_AGGR_TYPE (arg)) return 1; a = IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (arg)); - /* Unification of something that is not a template fails. (mrs) */ - if (a == 0) - return 1; - if (UPT_TEMPLATE (parm) != TREE_PURPOSE (a)) - /* different templates */ - return 1; - return unify (tparms, targs, ntparms, UPT_PARMS (parm), TREE_VALUE (a), - nsubsts); + if (a && UPT_TEMPLATE (parm) == TREE_PURPOSE (a)) + return unify (tparms, targs, ntparms, UPT_PARMS (parm), + TREE_VALUE (a), nsubsts); + /* FIXME: Should check base conversions here. */ + return 1; } case RECORD_TYPE: - if (TYPE_PTRMEMFUNC_P (parm)) + if (TYPE_PTRMEMFUNC_FLAG (parm)) return unify (tparms, targs, ntparms, TYPE_PTRMEMFUNC_FN_TYPE (parm), arg, nsubsts); @@ -2247,6 +2333,9 @@ unify (tparms, targs, ntparms, parm, arg if (TREE_CODE (arg) != FUNCTION_TYPE) return 1; check_args: + if (unify (tparms, targs, ntparms, TREE_TYPE (parm), + TREE_TYPE (arg), nsubsts)) + return 1; return type_unification (tparms, targs, TYPE_ARG_TYPES (parm), TYPE_ARG_TYPES (arg), nsubsts, 1); @@ -2274,6 +2363,12 @@ do_pending_expansions () { struct pending_inline *i, *new_list = 0; + { + tree t; + for (t = template_classes; t; t = TREE_CHAIN (t)) + instantiate_member_templates (TREE_PURPOSE (t)); + } + if (!pending_template_expansions) return 0; @@ -2298,10 +2393,19 @@ do_pending_expansions () DECIDE (0); if (DECL_EXPLICIT_INSTANTIATION (t)) - DECIDE (! DECL_EXTERNAL (t)); + DECIDE (DECL_NOT_REALLY_EXTERN (t)); else if (! flag_implicit_templates) DECIDE (0); + if (i->interface == 1) + /* OK, it was an implicit instantiation. */ + { + if (SUPPORTS_WEAK) + DECL_WEAK (t) = 1; + else + TREE_PUBLIC (t) = 0; + } + /* If it's a method, let the class type decide it. @@ What if the method template is in a separate file? Maybe both file contexts should be taken into account? @@ -2319,7 +2423,7 @@ do_pending_expansions () If `interface', ext ref. */ if (CLASSTYPE_INTERFACE_KNOWN (context)) DECIDE (!CLASSTYPE_INTERFACE_ONLY (context)); -#if 0 /* This doesn't get us stuff needed only by the file initializer. */ +#if 1 /* This doesn't get us stuff needed only by the file initializer. */ DECIDE (TREE_USED (t)); #else /* This compiles too much stuff, but that's probably better in most cases than never compiling the stuff we need. */ @@ -2396,23 +2500,53 @@ add_pending_template (pt) p->id = pt; } +void +mark_function_instantiated (result, extern_p) + tree result; + int extern_p; +{ + if (DECL_TEMPLATE_INSTANTIATION (result)) + SET_DECL_EXPLICIT_INSTANTIATION (result); + TREE_PUBLIC (result) = 1; + + if (! extern_p) + { + DECL_INTERFACE_KNOWN (result) = 1; + DECL_NOT_REALLY_EXTERN (result) = 1; + } +} + /* called from the parser. */ void do_function_instantiation (declspecs, declarator, storage) tree declspecs, declarator, storage; { - tree decl = grokdeclarator (declarator, declspecs, NORMAL, 0, 0); - tree name = DECL_NAME (decl); - tree fn = IDENTIFIER_GLOBAL_VALUE (name); + tree decl = grokdeclarator (declarator, declspecs, NORMAL, 0, + NULL_TREE, NULL_TREE); + tree name; + tree fn; tree result = NULL_TREE; - if (fn) + int extern_p = 0; + + /* If we've already seen this template instance, use it. */ + if (name = DECL_ASSEMBLER_NAME (decl), + fn = IDENTIFIER_GLOBAL_VALUE (name), + fn && DECL_TEMPLATE_INSTANTIATION (fn)) + result = fn; + else if (name = DECL_NAME (decl), fn = IDENTIFIER_GLOBAL_VALUE (name), fn) { for (fn = get_first_fn (fn); fn; fn = DECL_CHAIN (fn)) - if (TREE_CODE (fn) == TEMPLATE_DECL) + if (decls_match (fn, decl) + && DECL_DEFER_OUTPUT (fn)) + { + result = fn; + break; + } + else if (TREE_CODE (fn) == TEMPLATE_DECL) { int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (fn)); tree *targs = (tree *) malloc (sizeof (tree) * ntparms); - int i, dummy; + int i, dummy = 0; i = type_unification (DECL_TEMPLATE_PARMS (fn), targs, TYPE_ARG_TYPES (TREE_TYPE (fn)), TYPE_ARG_TYPES (TREE_TYPE (decl)), @@ -2424,39 +2558,53 @@ do_function_instantiation (declspecs, de else result = instantiate_template (fn, targs); } + free (targs); } } if (! result) - cp_error ("no matching template for `%D' found", decl); + { + cp_error ("no matching template for `%D' found", decl); + return; + } if (flag_external_templates) return; - if (DECL_EXPLICIT_INSTANTIATION (result) && TREE_PUBLIC (result)) - return; - - SET_DECL_EXPLICIT_INSTANTIATION (result); - if (storage == NULL_TREE) - { - TREE_PUBLIC (result) = 1; - DECL_EXTERNAL (result) = (DECL_INLINE (result) - && ! flag_implement_inlines); - TREE_STATIC (result) = ! DECL_EXTERNAL (result); - } - else if (storage == ridpointers[(int) RID_EXTERN]) ; + else if (storage == ridpointers[(int) RID_EXTERN]) + extern_p = 1; else cp_error ("storage class `%D' applied to template instantiation", storage); + mark_function_instantiated (result, extern_p); + repo_template_instantiated (result, extern_p); } void +mark_class_instantiated (t, extern_p) + tree t; + int extern_p; +{ + SET_CLASSTYPE_EXPLICIT_INSTANTIATION (t); + SET_CLASSTYPE_INTERFACE_KNOWN (t); + CLASSTYPE_INTERFACE_ONLY (t) = extern_p; + CLASSTYPE_VTABLE_NEEDS_WRITING (t) = ! extern_p; + TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = extern_p; + if (! extern_p) + { + CLASSTYPE_DEBUG_REQUESTED (t) = 1; + rest_of_type_compilation (t, 1); + } +} + +void do_type_instantiation (name, storage) tree name, storage; { tree t = TREE_TYPE (name); - int extern_p; + int extern_p = 0; + int nomem_p = 0; /* With -fexternal-templates, explicit instantiations are treated the same as implicit ones. */ @@ -2471,7 +2619,9 @@ do_type_instantiation (name, storage) } if (storage == NULL_TREE) - extern_p = 0; + /* OK */; + else if (storage == ridpointers[(int) RID_INLINE]) + nomem_p = 1; else if (storage == ridpointers[(int) RID_EXTERN]) extern_p = 1; else @@ -2482,27 +2632,19 @@ do_type_instantiation (name, storage) } /* We've already instantiated this. */ - if (CLASSTYPE_EXPLICIT_INSTANTIATION (t) && CLASSTYPE_INTERFACE_KNOWN (t)) - { - if (! extern_p) - cp_pedwarn ("multiple explicit instantiation of `%#T'", t); - return; - } + if (CLASSTYPE_EXPLICIT_INSTANTIATION (t) && ! CLASSTYPE_INTERFACE_ONLY (t) + && extern_p) + return; if (! CLASSTYPE_TEMPLATE_SPECIALIZATION (t)) { - SET_CLASSTYPE_EXPLICIT_INSTANTIATION (t); - if (! extern_p) - { - SET_CLASSTYPE_INTERFACE_KNOWN (t); - CLASSTYPE_INTERFACE_ONLY (t) = 0; - CLASSTYPE_VTABLE_NEEDS_WRITING (t) = 1; - CLASSTYPE_DEBUG_REQUESTED (t) = 1; - TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 0; - rest_of_type_compilation (t, 1); - } + mark_class_instantiated (t, extern_p); + repo_template_instantiated (t, extern_p); } - + + if (nomem_p) + return; + { tree tmp; /* Classes nested in template classes currently don't have an @@ -2516,21 +2658,11 @@ do_type_instantiation (name, storage) /* this should really be done by instantiate_member_templates */ tmp = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (t), 0); for (; tmp; tmp = TREE_CHAIN (tmp)) - { - if (DECL_TEMPLATE_SPECIALIZATION (tmp) - || (DECL_USE_TEMPLATE (tmp) == 0 - && CLASSTYPE_TEMPLATE_SPECIALIZATION (t))) - continue; - - SET_DECL_EXPLICIT_INSTANTIATION (tmp); - if (! extern_p) - { - TREE_PUBLIC (tmp) = 1; - DECL_EXTERNAL (tmp) = (DECL_INLINE (tmp) - && ! flag_implement_inlines); - TREE_STATIC (tmp) = ! DECL_EXTERNAL (tmp); - } - } + if (DECL_TEMPLATE_INSTANTIATION (tmp)) + { + mark_function_instantiated (tmp, extern_p); + repo_template_instantiated (tmp, extern_p); + } #if 0 for (tmp = TYPE_FIELDS (t); tmp; tmp = TREE_CHAIN (tmp))