/* * Copyright (c) 2003, The Tendra Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * Crown Copyright (c) 1997, 1998 * * This TenDRA(r) Computer Program is subject to Copyright * owned by the United Kingdom Secretary of State for Defence * acting through the Defence Evaluation and Research Agency * (DERA). It is made available to Recipients with a * royalty-free licence for its use, reproduction, transfer * to other parties and amendment for any purpose not excluding * product development provided that any such use et cetera * shall be deemed to be acceptance of the following conditions:- * * (1) Its Recipients shall ensure that this Notice is * reproduced upon any copies or amended versions of it; * * (2) Any amended version of it shall be clearly marked to * show both the nature of and the organisation responsible * for the relevant amendment or amendments; * * (3) Its onward transfer from a recipient to another * party shall be deemed to be that party's acceptance of * these conditions; * * (4) DERA gives no warranty or assurance as to its * quality or suitability for any purpose and DERA accepts * no liability whatsoever in relation to any use to which * it may be put. * * $TenDRA: tendra/src/producers/common/construct/template.c,v 1.13 2004/08/15 11:13:36 bp Exp $ */ #include "config.h" #include "producer.h" #include "msgcat.h" #include "c_types.h" #include "ctype_ops.h" #include "etype_ops.h" #include "exp_ops.h" #include "hashid_ops.h" #include "id_ops.h" #include "inst_ops.h" #include "itype_ops.h" #include "member_ops.h" #include "nat_ops.h" #include "nspace_ops.h" #include "off_ops.h" #include "tok_ops.h" #include "type_ops.h" #include "error.h" #include "catalog.h" #include "option.h" #include "basetype.h" #include "check.h" #include "chktype.h" #include "class.h" #include "compile.h" #include "convert.h" #include "copy.h" #include "declare.h" #include "derive.h" #include "dump.h" #include "expression.h" #include "hash.h" #include "identifier.h" #include "initialise.h" #include "instance.h" #include "macro.h" #include "namespace.h" #include "option.h" #include "overload.h" #include "parse.h" #include "predict.h" #include "statement.h" #include "syntax.h" #include "template.h" #include "tokdef.h" #include "token.h" #include "ustring.h" /* * TEMPLATE ARGUMENT HACK FLAG * * This flag can be set to true to indicate that the template argument * hack, namely mapping '>>' to '> >' at the end of a set of template * arguments, should be applied. */ static int apply_rshift_hack = 0; /* * SKIP TEMPLATE ARGUMENTS OR PARAMETERS * * This routine skips a set of template arguments or parameters. It * returns the sequence of preprocessing tokens enclosed between the * initial '<' and the matching closing '>'. */ static PPTOKEN *skip_template(IDENTIFIER id) { PPTOKEN *q; LOCATION loc; int templ = 0; int angles = 1; int brackets = 0; int t = crt_lex_token; PPTOKEN *p = crt_token; loc = crt_loc; do { switch (t) { case lex_less : { /* Open angle brackets */ if (!brackets && templ) angles++; templ = 0; break; } case lex_greater : { /* Close angle brackets */ if (!brackets) angles--; templ = 0; break; } case lex_rshift : { /* Map '>>' to '> >' */ if (!brackets && apply_rshift_hack) { PPTOKEN *r = new_pptok (); r->tok = lex_greater; r->next = crt_token->next; crt_token->tok = lex_greater; crt_token->next = r; angles--; report (crt_loc, ERR_temp_names_hack ()); } templ = 0; break; } case lex_open_Hround : case lex_open_Hbrace_H1 : case lex_open_Hbrace_H2 : case lex_open_Hsquare_H1 : case lex_open_Hsquare_H2 : { /* Open brackets */ brackets++; templ = 0; break; } case lex_close_Hround : case lex_close_Hbrace_H1 : case lex_close_Hbrace_H2 : case lex_close_Hsquare_H1 : case lex_close_Hsquare_H2 : { /* Close brackets */ if (brackets) brackets--; templ = 0; break; } case lex_identifier : case lex_template : case lex_const_Hcast : case lex_static_Hcast : case lex_dynamic_Hcast : case lex_reinterpret_Hcast : { /* These may be followed by '<' */ /* NOT YET IMPLEMENTED - but are they? */ templ = 1; break; } case lex_eof : { /* End of file */ if (IS_NULL_id (id)) { report (loc, ERR_temp_param_eof ()); } else { report (loc, ERR_temp_names_eof (id)); } angles = 0; break; } default : { /* Other tokens */ templ = 0; break; } } q = crt_token; t = expand_preproc (EXPAND_AHEAD); } while (angles); q->tok = lex_close_Htemplate; snip_tokens (p, q); return (p); } /* * SKIP A SET OF TEMPLATE ARGUMENTS * * This routine skips a set of arguments for the template id. It is * entered with the current token equal to the template name preceding * the initial '<' if started is false, and equal to the initial '<' * otherwise. After skipping the current token is either still the * template name or the token following the template arguments, depending * on the value of started. */ PPTOKEN *skip_template_args(IDENTIFIER id, int started) { PPTOKEN *q; PPTOKEN *p = crt_token; int t = crt_lex_token; if (started) { /* Patch in dummy preprocessing token */ q = patch_tokens (1); q->tok = t; t = lex_ignore_token; p->tok = t; } IGNORE expand_preproc (EXPAND_AHEAD); crt_lex_token = lex_open_Htemplate; crt_token->tok = lex_open_Htemplate; q = skip_template (id); crt_lex_token = t; crt_token = p; if (started) { /* Advance to following token */ ADVANCE_LEXER; } return (q); } /* * PARSE A SET OF TEMPLATE ARGUMENTS * * This routine parses the template arguments p. Note that unlike token * arguments the template argument sorts are deduced by look-ahead rather * than from the template sort. */ static LIST (TOKEN) parse_template_args(PPTOKEN *p) { int t; PARSE_STATE st; LIST (TOKEN) args = NULL_list (TOKEN); if (p == NULL) return (args); /* Initialise parser */ save_state (&st, 1); init_parser (p); ADVANCE_LEXER; t = crt_lex_token; if (t == lex_open_Htemplate) { /* Step over open bracket */ ADVANCE_LEXER; t = crt_lex_token; } /* Scan through arguments */ if (t != lex_close_Htemplate) { for (;;) { TOKEN arg; if (predict_typeid (2)) { TYPE r = NULL_type; have_type_specifier = 0; if (predict_typename ()) { /* Template argument */ IDENTIFIER rid = NULL_id; parse_id (&rid); MAKE_tok_class (r, rid, arg); } else { /* Type argument */ parse_type (&r); MAKE_tok_type (btype_lang, r, arg); } } else { /* Expression argument */ EXP e = NULL_exp; TYPE r = NULL_type; parse_exp (&e); if (!IS_NULL_exp (e)) { r = DEREF_type (exp_type (e)); } MAKE_tok_exp (r, 1, e, arg); } if (have_syntax_error) break; CONS_tok (arg, args, args); t = crt_lex_token; if (t == lex_close_Htemplate) { break; } else if (t == lex_comma) { ADVANCE_LEXER; } else { t = lex_close_Htemplate; report (crt_loc, ERR_lex_expect (t)); break; } } } /* Restore state */ restore_state (&st); p = restore_parser (); free_tok_list (p); /* Return result */ args = REVERSE_list (args); return (args); } /* * CHECK A TEMPLATE PARAMETER TYPE * * This routine checks the type t of the template parameter id. */ static void templ_param_type(IDENTIFIER id, TYPE t) { switch (TAG_type (t)) { case type_floating_tag : case type_top_tag : case type_bottom_tag : { /* Illegal parameter types */ report (crt_loc, ERR_temp_param_type (id, t)); break; } } return; } /* * DEFINE A TEMPLATE PARAMETER * * This routine defines the template parameter id to be arg. */ static int define_templ_param(IDENTIFIER id, TOKEN arg, IDENTIFIER tid, int def) { int ok = 1; TOKEN sort = DEREF_tok (id_token_sort (id)); unsigned tag = TAG_tok (sort); if (tag == tok_type_tag) { /* Type parameter */ TYPE t; if (IS_tok_type (arg)) { t = DEREF_type (tok_type_value (arg)); if (def) t = expand_type (t, 2); if (!is_global_type (t)) { /* Type must have external linkage */ ERROR err = ERR_temp_arg_local (t); err = concat_error (ERR_temp_arg_init (id, tid), err); report (crt_loc, err); } COPY_type (tok_type_value (arg), t); } else { /* Non-type argument supplied */ t = type_error; report (crt_loc, ERR_temp_arg_type (id, tid)); ok = 0; } COPY_type (tok_type_value (sort), t); } else if (tag == tok_exp_tag) { /* Expression parameter */ EXP e; if (IS_tok_exp (arg)) { int over = 0; ERROR err = NULL_err; TYPE s1 = DEREF_type (tok_exp_type (sort)); TYPE s2 = expand_type (s1, 2); if (!EQ_type (s1, s2)) templ_param_type (id, s2); e = DEREF_exp (tok_exp_value (arg)); if (def) { /* Perform conversion if necessary */ unsigned etag = TAG_exp (e); e = convert_reference (e, REF_ASSIGN); e = expand_exp (e, 2, 0); if (IS_exp_address_mem (e)) { /* Check for overloaded pointer to members */ EXP a = DEREF_exp (exp_address_mem_arg (e)); if (IS_exp_member (a)) { IDENTIFIER mid = DEREF_id (exp_member_id (a)); if (IS_id_function_etc (mid)) { mid = DEREF_id (id_function_etc_over (mid)); if (!IS_NULL_id (mid)) over = 1; } } } if (IS_type_array (s2)) { if (etag == exp_paren_tag) e = make_paren_exp (e); e = init_array (s2, cv_none, e, 1, &err); } else { e = init_assign (s2, cv_none, e, &err); } if (!IS_NULL_err (err)) err = init_error (err, 0); } if (is_const_exp (e, 1)) { switch (TAG_type (s2)) { case type_integer_tag : case type_floating_tag : case type_top_tag : case type_bottom_tag : case type_enumerate_tag : case type_token_tag : case type_error_tag : { /* Constants of these types are alright */ break; } default : { /* Check linkage in other cases */ EXP pa = NULL_exp; DECL_SPEC ln = find_exp_linkage (e, &pa, 0); if (ln & dspec_extern) { /* External linkage */ /* EMPTY */ } else if (ln & dspec_static) { /* Internal linkage */ ERROR err2 = ERR_temp_arg_internal (); err = concat_error (err, err2); } else { /* No linkage */ ERROR err2 = ERR_temp_arg_bad (); err = concat_error (err, err2); } if (over) { /* Overloaded pointer to member */ ERROR err2 = ERR_temp_arg_over (); err = concat_error (err, err2); } break; } } } else { err = concat_error (err, ERR_temp_arg_const ()); } if (!IS_NULL_err (err)) { err = concat_error (ERR_temp_arg_init (id, tid), err); report (crt_loc, err); } COPY_type (tok_exp_type (arg), s2); COPY_exp (tok_exp_value (arg), e); } else { /* Non-expression argument supplied */ e = make_error_exp (0); report (crt_loc, ERR_temp_arg_exp (id, tid)); ok = 0; } COPY_exp (tok_exp_value (sort), e); } else { /* Template class parameter */ IDENTIFIER sid; if (IS_tok_class (arg)) { sid = DEREF_id (tok_class_value (arg)); if (!IS_NULL_id (sid) && IS_id_class_name_etc (sid)) { TYPE s = DEREF_type (id_class_name_etc_defn (sid)); if (!is_global_type (s)) { /* Type must have external linkage */ ERROR err = ERR_temp_arg_local (s); err = concat_error (ERR_temp_arg_init (id, tid), err); report (crt_loc, err); } } init_template_param (id, sid); } else { /* Non-template argument supplied */ HASHID nm = KEYWORD (lex_zzzz); sid = DEREF_id (hashid_id (nm)); report (crt_loc, ERR_temp_arg_templ (id, tid)); ok = 0; } COPY_id (tok_class_value (sort), sid); } return (ok); } /* * DEFAULT TEMPLATE ARGUMENTS FLAG * * This flag may be set to false to suppress template default arguments. */ int allow_templ_dargs = 1; /* * CHECK A SET OF TEMPLATE ARGUMENTS * * This routine checks the set of template arguments args for the template * tid of sort tok. Note that if tid is a function then there may be * less arguments than parameters, in this case in_template_decl is set * to indicate that certain template parameters remain unbound. */ static LIST (TOKEN) check_templ_args(TOKEN tok, LIST (TOKEN) args, IDENTIFIER tid) { int s; int reported = 0; LIST (TOKEN) a = args; LIST (TOKEN) b = NULL_list (TOKEN); LIST (TOKEN) d = DEREF_list (tok_templ_dargs (tok)); LIST (IDENTIFIER) pids = DEREF_list (tok_templ_pids (tok)); LIST (IDENTIFIER) qids = pids; if (in_template_decl && depends_on_args (args, pids, 0, 1)) { /* Be extra careful in this case */ tok = expand_sort (tok, 1, 1); args = check_templ_args (tok, args, tid); return (args); } s = save_token_args (qids, NULL_list (TOKEN)); if (!allow_templ_dargs) d = NULL_list (TOKEN); while (!IS_NULL_list (pids)) { TOKEN arg = NULL_tok; IDENTIFIER pid = DEREF_id (HEAD_list (pids)); if (!IS_NULL_list (a)) { /* Use argument from list */ arg = DEREF_tok (HEAD_list (a)); } else if (!IS_NULL_list (d)) { /* Use default argument */ arg = DEREF_tok (HEAD_list (d)); if (!IS_NULL_tok (arg)) { /* Add copy to list of arguments */ arg = expand_sort (arg, -1, 1); CONS_tok (arg, b, b); } } if (IS_NULL_tok (arg)) { /* Not enough arguments */ if (!reported) { if (IS_id_function_etc (tid)) { /* Allow for argument deduction */ a = NULL_list (TOKEN); in_template_decl++; break; } report (crt_loc, ERR_temp_arg_less (tid)); reported = 1; } arg = DEREF_tok (id_token_sort (pid)); IGNORE is_bound_tok (arg, 1); arg = expand_sort (arg, 2, 1); CONS_tok (arg, b, b); } IGNORE define_templ_param (pid, arg, tid, 1); if (!IS_NULL_list (d)) d = TAIL_list (d); if (!IS_NULL_list (a)) a = TAIL_list (a); pids = TAIL_list (pids); } if (!IS_NULL_list (a)) { /* Too many arguments */ report (crt_loc, ERR_temp_arg_more (tid)); } if (!IS_NULL_list (b)) { /* Add default arguments to list */ b = REVERSE_list (b); args = APPEND_list (args, b); } restore_token_args (qids, s); return (args); } /* * CHECK A SET OF DEDUCED TEMPLATE ARGUMENTS * * This routine checks the deduced template arguments args for the * template tid with parameters pids. */ void check_deduced_args(IDENTIFIER tid, LIST (IDENTIFIER) pids, LIST (TOKEN) args) { while (!IS_NULL_list (pids) && !IS_NULL_list (args)) { IDENTIFIER pid = DEREF_id (HEAD_list (pids)); TOKEN arg = DEREF_tok (HEAD_list (args)); IGNORE define_templ_param (pid, arg, tid, 0); args = TAIL_list (args); pids = TAIL_list (pids); } return; } /* * DOES A SET OF TEMPLATE ARGUMENTS MATCH A SORT? * * This routine checks whether the template arguments args form a match * for an initial segment of the template sort tok. */ static int match_template_args(TOKEN tok, LIST (TOKEN) args) { LIST (IDENTIFIER) pids = DEREF_list (tok_templ_pids (tok)); while (!IS_NULL_list (pids) && !IS_NULL_list (args)) { IDENTIFIER pid = DEREF_id (HEAD_list (pids)); TOKEN sort = DEREF_tok (id_token_sort (pid)); TOKEN arg = DEREF_tok (HEAD_list (args)); if (TAG_tok (arg) != TAG_tok (sort)) { /* Argument sorts do not match */ return (0); } args = TAIL_list (args); pids = TAIL_list (pids); } if (!IS_NULL_list (args)) { /* Too many arguments */ return (0); } return (1); } /* * APPLY A FUNCTION TEMPLATE * * This routine applies the function template id to the arguments args. * Because id may comprise several overloaded template functions it is * necessary to check each to determine whether the template parameter * sorts match the argument sorts. If more than one match is found the * result is an overloaded function. */ static IDENTIFIER apply_func_templ(IDENTIFIER id, LIST (TOKEN) args, int def) { int force = 0; IDENTIFIER tid = NULL_id; do { /* Build up result */ IDENTIFIER fid = id; while (!IS_NULL_id (fid)) { TYPE t = DEREF_type (id_function_etc_type (fid)); if (IS_type_templ (t)) { TOKEN sort = DEREF_tok (type_templ_sort (t)); if (force || match_template_args (sort, args)) { /* Argument sorts match */ IDENTIFIER sid = tid; int td = in_template_decl; args = check_templ_args (sort, args, fid); tid = instance_func (fid, args, 0, def); COPY_id (id_function_etc_over (tid), sid); in_template_decl = td; } } fid = DEREF_id (id_function_etc_over (fid)); } if (force) { /* Should have bound arguments by now */ if (IS_NULL_id (tid)) tid = id; } else { /* Try again allowing for mismatches */ force = 1; } } while (IS_NULL_id (tid)); return (tid); } /* * APPLY A TYPEDEF TEMPLATE * * This routine applies the typedef template id to the arguments args. */ static TYPE apply_typedef_templ(IDENTIFIER id, LIST (TOKEN) args) { TYPE t = DEREF_type (id_class_name_etc_defn (id)); if (IS_type_templ (t)) { int td = in_template_decl; TOKEN sort = DEREF_tok (type_templ_sort (t)); LIST (IDENTIFIER) pids = DEREF_list (tok_templ_pids (sort)); args = check_templ_args (sort, args, id); t = DEREF_type (type_templ_defn (t)); if (is_templ_type (t)) { /* Template template parameter */ IDENTIFIER tid = DEREF_id (type_token_tok (t)); MAKE_type_token (cv_none, tid, args, t); } else { /* Expand type definition */ int d = save_token_args (pids, args); TYPE s = expand_type (t, 1); if (EQ_type (s, t)) s = copy_typedef (id, t, cv_none); restore_token_args (pids, d); t = s; } in_template_decl = td; } else { report (crt_loc, ERR_temp_names_not (id)); t = copy_typedef (id, t, cv_none); } return (t); } /* * APPLY A CLASS TEMPLATE * * This routine applies the class template id to the arguments args. */ static IDENTIFIER apply_type_templ(IDENTIFIER id, LIST (TOKEN) args, int def) { if (IS_id_class_name (id)) { /* Class template */ TYPE t; DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (ds & dspec_implicit) { /* Allow for nested calls */ IDENTIFIER tid = find_template (id, 0); if (!IS_NULL_id (tid)) id = tid; } t = DEREF_type (id_class_name_etc_defn (id)); if (IS_type_templ (t)) { int td = in_template_decl; TOKEN sort = DEREF_tok (type_templ_sort (t)); args = check_templ_args (sort, args, id); id = instance_type (id, args, 0, def); in_template_decl = td; } else { report (crt_loc, ERR_temp_names_not (id)); } } else { /* Type alias template */ TYPE t = apply_typedef_templ (id, args); if (IS_type_compound (t)) { CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); complete_class (ct, def); id = DEREF_id (ctype_name (ct)); } else { HASHID nm = DEREF_hashid (id_name (id)); NAMESPACE ns = DEREF_nspace (id_parent (id)); decl_loc = crt_loc; id = make_typedef (ns, nm, t, dspec_none); } } return (id); } /* * APPLY A TEMPLATE TO A SET OF ARGUMENTS * * This routine applies the template id to the arguments args. */ IDENTIFIER apply_template(IDENTIFIER id, LIST (TOKEN) args, int def, int force) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (ds & dspec_template) { if (IS_id_function_etc (id)) { id = apply_func_templ (id, args, def); } else { id = apply_type_templ (id, args, def); } } else { TYPE form; MAKE_type_token (cv_none, id, args, form); if (force || is_templ_depend (form)) { /* Dummy template identifier */ HASHID nm = DEREF_hashid (id_name (id)); NAMESPACE ns = DEREF_nspace (id_parent (id)); MAKE_id_undef (nm, dspec_none, ns, crt_loc, id); COPY_type (id_undef_form (id), form); } else { report (crt_loc, ERR_temp_names_not (id)); } } return (id); } /* * PARSE A SET OF NON-TYPE TEMPLATE ARGUMENTS * * This routine parses the template arguments p for the non-class template * id. This includes both template functions and dummy template identifiers * such as in 'ptr->template id < ... >'. */ IDENTIFIER parse_id_template(IDENTIFIER id, PPTOKEN *p, int def) { LIST (TOKEN) args = parse_template_args (p); id = apply_template (id, args, def, 1); return (id); } /* * PARSE A SET OF TYPE TEMPLATE ARGUMENTS * * This routine parses the template arguments p for the class template * id. def is passed to instance_type. */ IDENTIFIER parse_type_template(IDENTIFIER id, PPTOKEN *p, int def) { LIST (TOKEN) args = parse_template_args (p); id = apply_type_templ (id, args, def); return (id); } /* * PARSE A SET OF TYPEDEF TEMPLATE ARGUMENTS * * This routine parses the template arguments p for the typedef * template id. */ TYPE parse_typedef_templ(IDENTIFIER id, PPTOKEN *p) { LIST (TOKEN) args = parse_template_args (p); TYPE t = apply_typedef_templ (id, args); return (t); } /* * DEDUCE A TEMPLATE TYPE * * This routine deduces the arguments for the template type id called * without arguments. Within a template class definition the template * name gives the template applied to the current arguments. * Otherwise template declarations and definitions (for which used is * false) are allowed but other instances are not. */ TYPE deduce_type_template(IDENTIFIER id, int used) { TYPE t = DEREF_type (id_class_name_etc_defn (id)); if (used) { TYPE s = t; while (IS_type_templ (s)) { s = DEREF_type (type_templ_defn (s)); } if (IS_type_compound (s)) { CLASS_TYPE cs = DEREF_ctype (type_compound_defn (s)); if (defining_class (cs)) { /* In class definition */ return (s); } } report (crt_loc, ERR_temp_local_not (t)); } return (t); } /* * CURRENT TEMPLATE NAMESPACE * * This variable is used within a template declaration to hold the * namespace in which the template parameters are declared. */ NAMESPACE templ_namespace = NULL_nspace; /* * LIST OF ALL TEMPLATE PARAMETERS * * These lists are dummy values representing the lists of all template * parameters and all template or token parameters. */ LIST (IDENTIFIER) any_templ_param = NULL_list (IDENTIFIER); LIST (IDENTIFIER) any_token_param = NULL_list (IDENTIFIER); /* * PARSE A SET OF TEMPLATE PARAMETERS * * This routine parses a set of template parameters. It is entered after * the initial 'template' has been read. ex is true if this was preceded * by 'export'. */ TOKEN template_params(int ex) { int t; TOKEN tok; PPTOKEN *p; NAMESPACE ns; LOCATION loc; PARSE_STATE s; int have_darg = 0; unsigned long npars = 0; DECL_SPEC use = dspec_none; LIST (TOKEN) dargs = NULL_list (TOKEN); LIST (IDENTIFIER) pids = NULL_list (IDENTIFIER); /* Can't have template declarations inside blocks */ if (in_function_defn) { report (crt_loc, ERR_temp_decl_scope ()); } else if (in_class_defn && really_in_function_defn) { report (crt_loc, ERR_temp_mem_local ()); } /* Mark exported templates */ if (ex || option (OPT_templ_export)) use |= dspec_extern; /* Check for initial '<' */ if (crt_lex_token != lex_less) { /* Explicit instantiation */ MAKE_tok_templ (use, NULL_nspace, tok); return (tok); } /* Start template parameter namespace */ ns = make_namespace (NULL_id, nspace_templ_tag, 0); push_namespace (ns); in_template_decl++; record_location++; /* Prepare to parse template parameters */ ADVANCE_LEXER; loc = crt_loc; p = skip_template (NULL_id); save_state (&s, 1); crt_loc = loc; init_parser (p); ADVANCE_LEXER; t = crt_lex_token; /* Parse template parameters */ if (t != lex_close_Htemplate) { for (;;) { /* Declare parameter */ IDENTIFIER pid = NULL_id; decl_loc = crt_loc; if (predict_template ()) { /* Type parameter */ parse_type_param (&pid); } else { /* Expression parameter */ if (crt_lex_token == lex_typename) { /* Replace 'typename' by 'class' */ crt_lex_token = lex_class; } parse_param (NULL_type, CONTEXT_TEMPL_PARAM, &pid); } /* Add parameter to list */ if (!IS_NULL_id (pid)) { DECL_SPEC ds = DEREF_dspec (id_storage (pid)); ds |= dspec_template; COPY_dspec (id_storage (pid), ds); if (do_dump) dump_token_param (pid); tok = DEREF_tok (id_token_sort (pid)); switch (TAG_tok (tok)) { case tok_exp_tag : { /* Expression parameter */ int c; EXP e; TYPE r; DECONS_tok_exp (r, c, e, tok); templ_param_type (pid, r); if (IS_NULL_exp (e)) { if (have_darg) have_darg = 2; tok = NULL_tok; } else { COPY_exp (tok_exp_value (tok), NULL_exp); MAKE_tok_exp (r, c, e, tok); have_darg = 1; } break; } case tok_type_tag : { /* Type parameter */ TYPE r = DEREF_type (tok_type_value (tok)); if (IS_NULL_type (r)) { if (have_darg) have_darg = 2; tok = NULL_tok; } else { COPY_type (tok_type_value (tok), NULL_type); MAKE_tok_type (btype_lang, r, tok); have_darg = 1; } break; } case tok_class_tag : { /* Template class parameter */ TYPE r = DEREF_type (tok_class_type (tok)); IDENTIFIER cid = DEREF_id (tok_class_value (tok)); if (IS_NULL_id (cid)) { if (have_darg) have_darg = 2; tok = NULL_tok; } else { COPY_id (tok_class_value (tok), NULL_id); MAKE_tok_class (r, cid, tok); have_darg = 1; } break; } default : { /* Shouldn't occur */ tok = NULL_tok; break; } } if (have_darg == 2) { /* Missing default argument */ report (crt_loc, ERR_temp_param_default (pid)); } CONS_tok (tok, dargs, dargs); CONS_id (pid, pids, pids); npars++; } /* Check for next parameter */ t = crt_lex_token; if (t == lex_close_Htemplate) { /* End of parameter list */ break; } else if (t == lex_comma) { /* Move on to next parameter */ ADVANCE_LEXER; } else { /* Syntax error */ if (!have_syntax_error) { ERROR err = ERR_lex_parse (crt_token); report (crt_loc, err); } break; } } } /* Restore parser */ restore_state (&s); p = restore_parser (); free_tok_list (p); /* Construct the result */ MAKE_tok_templ (use, crt_namespace, tok); if (IS_NULL_list (pids)) { /* Explicit specialisation */ IGNORE pop_namespace (); in_template_decl--; record_location--; } else { IGNORE check_value (OPT_VAL_template_pars, npars); pids = REVERSE_list (pids); dargs = REVERSE_list (dargs); COPY_list (tok_templ_pids (tok), pids); COPY_list (tok_templ_dargs (tok), dargs); set_proc_token (pids); templ_namespace = ns; } return (tok); } /* * CREATE A TEMPLATE TYPE QUALIFIER * * This routine creates a template type qualifier from the template * parameters tok and the type t. It also terminates the template * parameter namespace while leaving its names in scope. */ TYPE make_template_type(TOKEN tok, TYPE t) { TYPE s; LIST (IDENTIFIER) pids = DEREF_list (tok_templ_pids (tok)); if (!IS_NULL_list (pids)) { /* Remove template parameters */ IGNORE restore_namespace (); } MAKE_type_templ (cv_none, tok, NULL_type, 0, s); if (!IS_NULL_type (t)) { unsigned tag = TAG_type (t); NAMESPACE ns = DEREF_nspace (tok_templ_pars (tok)); if (IS_NULL_nspace (ns)) { /* Can't have 'template template < ... >' */ report (crt_loc, ERR_temp_explicit_templ ()); s = NULL_type; } else { if (tag == type_templ_tag) { tok = DEREF_tok (type_templ_sort (t)); ns = DEREF_nspace (tok_templ_pars (tok)); if (IS_NULL_nspace (ns)) { /* Can't have 'template < ... > template' */ report (crt_loc, ERR_temp_explicit_templ ()); t = DEREF_type (type_templ_defn (t)); tag = TAG_type (t); } } } if (tag == type_func_tag) { /* Ignore linkage specifiers */ CV_SPEC cv = DEREF_cv (type_func_mqual (t)); cv &= ~cv_language; cv |= cv_cpp; COPY_cv (type_func_mqual (t), cv); } s = inject_pre_type (t, s, 0); } return (s); } /* * END A TEMPLATE DECLARATION * * This routine ends a template declaration. It removes the names from * the template parameter namespace from scope. */ void end_template(TOKEN tok) { LIST (IDENTIFIER) pids = DEREF_list (tok_templ_pids (tok)); if (!IS_NULL_list (pids)) { remove_namespace (); templ_namespace = NULL_nspace; in_template_decl--; record_location--; if (in_template_decl) { /* Find enclosing template namespace */ LIST (NAMESPACE) lns = LIST_stack (namespace_stack); while (!IS_NULL_list (lns)) { NAMESPACE ns = DEREF_nspace (HEAD_list (lns)); if (IS_nspace_templ (ns)) { templ_namespace = ns; break; } lns = TAIL_list (lns); } } } if (!in_template_decl) clear_templates (1); return; } /* * CHECK A TEMPLATE DECLARATOR * * This routine is called whenever the template type t is used to qualify * a class definition or a function declarator. */ void template_decl(TYPE t) { while (!IS_NULL_type (t) && IS_type_templ (t)) { TOKEN sort = DEREF_tok (type_templ_sort (t)); DECL_SPEC ds = DEREF_dspec (tok_templ_usage (sort)); if (ds & dspec_used) { /* Already used */ report (crt_loc, ERR_temp_decl_one ()); } ds |= dspec_used; COPY_dspec (tok_templ_usage (sort), ds); t = DEREF_type (type_templ_defn (t)); } return; } /* * EXPORT A SET OF TEMPLATE INSTANCES * * This routine exports the instances associated with the template type t. * It returns the non-template component of t. */ static TYPE export_instances(TYPE t, int def) { while (IS_type_templ (t)) { TOKEN sort = DEREF_tok (type_templ_sort (t)); INSTANCE apps = DEREF_inst (tok_templ_apps (sort)); while (!IS_NULL_inst (apps)) { DECL_SPEC acc = DEREF_dspec (inst_templ_access (apps)); if (!(acc & (dspec_alias | dspec_main))) { IDENTIFIER id = DEREF_id (inst_templ_id (apps)); export_template (id, def); } acc |= dspec_typedef; COPY_dspec (inst_templ_access (apps), acc); apps = DEREF_inst (inst_next (apps)); } t = DEREF_type (type_templ_defn (t)); } return (t); } /* * EXPORT A TEMPLATE IDENTIFIER * * This routine marks the template identifier id as having been exported. * def is 2 for the first explicit declaration of a template, 1 for a * redeclaration and 0 otherwise. */ void export_template(IDENTIFIER id, int def) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (ds & (dspec_inherit | dspec_implicit)) return; if (ds & (dspec_inline | dspec_static)) return; if (def == 0 && (ds & dspec_typedef)) { /* Already exported */ return; } ds |= dspec_typedef; COPY_dspec (id_storage (id), ds); if (def == 2 && !has_linkage (id)) { /* Can't export anonymous identifiers */ report (crt_loc, ERR_temp_decl_export (id)); } switch (TAG_id (id)) { case id_class_name_tag : case id_class_alias_tag : { /* Template classes */ TYPE t = DEREF_type (id_class_name_etc_defn (id)); t = export_instances (t, def); if (IS_type_compound (t)) { CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); IDENTIFIER cid = DEREF_id (ctype_name (ct)); if (EQ_id (id, cid)) { NAMESPACE ns = DEREF_nspace (ctype_member (ct)); MEMBER mem = DEREF_member (nspace_ctype_first (ns)); while (!IS_NULL_member (mem)) { /* Scan through class members */ IDENTIFIER pid = DEREF_id (member_id (mem)); IDENTIFIER qid = DEREF_id (member_alt (mem)); if (!IS_NULL_id (pid)) { export_template (pid, def); } if (!IS_NULL_id (qid) && !EQ_id (qid, pid)) { export_template (qid, def); } mem = DEREF_member (member_next (mem)); } } } break; } case id_function_tag : case id_mem_func_tag : case id_stat_mem_func_tag : { /* Template functions */ TYPE t = DEREF_type (id_function_etc_type (id)); IGNORE export_instances (t, def); update_tag (id, 0); break; } case id_stat_member_tag : { /* Static data members */ update_tag (id, 0); break; } } return; } /* * HAS A TEMPLATE BEEN EXPORTED? * * This routine checks whether the template instance id has been exported. */ int is_exported(IDENTIFIER id) { TYPE form; int def = 0; DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (ds & dspec_typedef) return (1); form = find_form (id, &def); if (!IS_NULL_type (form) && IS_type_instance (form)) { IDENTIFIER tid = DEREF_id (type_instance_id (form)); ds = DEREF_dspec (id_storage (tid)); if (ds & dspec_typedef) { export_template (id, 0); return (1); } } return (0); } /* * CREATE A SET OF PRIMARY TEMPLATE ARGUMENTS * * This routine creates a list of primary template arguments corresponding * to the template parameters pids. */ LIST (TOKEN) make_primary_args(LIST (IDENTIFIER) pids) { LIST (TOKEN) args = NULL_list (TOKEN); while (!IS_NULL_list (pids)) { IDENTIFIER pid = DEREF_id (HEAD_list (pids)); TOKEN arg = apply_token (pid, NULL_list (TOKEN)); CONS_tok (arg, args, args); pids = TAIL_list (pids); } return (REVERSE_list (args)); } /* * CHECK A SET OF PRIMARY TEMPLATE PARAMETERS * * This routine checks the template parameters given by the type t for * the declaration of the primary template class or function id. It * returns the non-template component of t. */ TYPE check_templ_params(TYPE t, IDENTIFIER id) { int depth = 0; unsigned tag = TAG_type (t); while (tag == type_templ_tag) { TOKEN sort = DEREF_tok (type_templ_sort (t)); NAMESPACE ns = DEREF_nspace (tok_templ_pars (sort)); DECL_SPEC use = DEREF_dspec (tok_templ_usage (sort)); LIST (IDENTIFIER) pids = DEREF_list (tok_templ_pids (sort)); TYPE s = DEREF_type (type_templ_defn (t)); tag = TAG_type (s); if (IS_NULL_list (pids)) { /* No template parameters */ if (IS_NULL_nspace (ns)) { /* Explicit instantiation */ report (decl_loc, ERR_temp_explicit_bad (id)); } else { /* Specialisation */ report (decl_loc, ERR_temp_param_none (id)); COPY_id (nspace_name (ns), id); } } else { /* Create primary specialisation */ TYPE form; TYPE prim; INSTANCE apps; DECL_SPEC ds = (dspec_template | dspec_extern | dspec_main); LIST (TOKEN) args = make_primary_args (pids); MAKE_type_token (cv_none, id, args, form); MAKE_type_templ (cv_none, sort, form, 1, prim); apps = DEREF_inst (tok_templ_apps (sort)); MAKE_inst_templ (prim, apps, id, ds, all_instances, apps); COPY_inst (type_token_app (form), apps); COPY_inst (tok_templ_apps (sort), apps); all_instances = apps; if (tag == type_compound_tag) { CLASS_TYPE cs = DEREF_ctype (type_compound_defn (s)); COPY_type (ctype_form (cs), form); } else if (tag == type_func_tag) { /* Can't have default arguments with function */ if (check_templ_dargs (t)) { report (decl_loc, ERR_temp_param_func ()); } } COPY_id (nspace_name (ns), id); } if (use & dspec_extern) export_template (id, 2); depth++; t = s; } if (depth > 1) { /* More than one level of templates */ report (decl_loc, ERR_temp_decl_bad ()); } return (t); } /* * CHECK FOR TEMPLATE DEFAULT ARGUMENTS * * This routine returns true if the template type t has default arguments. */ int check_templ_dargs(TYPE t) { if (IS_type_templ (t)) { TOKEN sort = DEREF_tok (type_templ_sort (t)); LIST (TOKEN) dargs = DEREF_list (tok_templ_dargs (sort)); while (!IS_NULL_list (dargs)) { TOKEN darg = DEREF_tok (HEAD_list (dargs)); if (!IS_NULL_tok (darg)) return (1); dargs = TAIL_list (dargs); } } return (0); } /* * FIND AN UNDERLYING TEMPLATE * * This routine checks whether the identifier id results from the * application of a template. If so it returns the underlying template. */ IDENTIFIER find_template(IDENTIFIER id, int force) { if (!IS_NULL_id (id)) { switch (TAG_id (id)) { case id_class_name_tag : { /* Template classes */ CLASS_TYPE ct; int templ = 0; TYPE t = DEREF_type (id_class_name_defn (id)); while (IS_type_templ (t)) { t = DEREF_type (type_templ_defn (t)); templ = 1; } ct = DEREF_ctype (type_compound_defn (t)); t = DEREF_type (ctype_form (ct)); if (!IS_NULL_type (t) && IS_type_token (t)) { IDENTIFIER tid = DEREF_id (type_token_tok (t)); if (!IS_id_token (tid)) return (tid); } if (templ && force) { /* Primary template class */ return (id); } break; } case id_function_tag : case id_mem_func_tag : case id_stat_mem_func_tag : { /* Template functions */ TYPE t = DEREF_type (id_function_etc_form (id)); if (!IS_NULL_type (t) && IS_type_token (t)) { IDENTIFIER tid = DEREF_id (type_token_tok (t)); if (!IS_id_token (tid)) return (tid); } if (force) { t = DEREF_type (id_function_etc_type (id)); if (IS_type_templ (t)) { /* Primary template function */ return (id); } } break; } case id_ambig_tag : { /* Ambiguous identifiers */ LIST (IDENTIFIER) pids; pids = DEREF_list (id_ambig_ids (id)); if (!IS_NULL_list (pids)) { IDENTIFIER pid = DEREF_id (HEAD_list (pids)); IDENTIFIER tid = find_template (pid, force); if (!IS_NULL_id (tid)) { pids = TAIL_list (pids); while (!IS_NULL_list (pids)) { IDENTIFIER sid; pid = DEREF_id (HEAD_list (pids)); sid = find_template (pid, force); if (!EQ_id (sid, tid)) return (NULL_id); pids = TAIL_list (pids); } return (tid); } } break; } } } return (NULL_id); } /* * REDECLARE A TEMPLATE PARAMETER * * This routine checks the template parameter id for redeclarations. */ static IDENTIFIER redecl_templ_param(IDENTIFIER id) { HASHID nm = DEREF_hashid (id_name (id)); MEMBER mem = search_member (crt_namespace, nm, 1); IDENTIFIER pid = DEREF_id (member_id (mem)); if (!IS_NULL_id (pid)) { /* Parameter already defined */ report (crt_loc, ERR_temp_param_dup (nm)); nm = lookup_anon (); id = DEREF_id (hashid_id (nm)); } return (id); } /* * DECLARE A TEMPLATE TYPE PARAMETER * * This routine declares a template type parameter named id. */ IDENTIFIER make_type_param(IDENTIFIER id) { TOKEN tok; MAKE_tok_type (btype_template, NULL_type, tok); id = redecl_templ_param (id); id = make_token_decl (tok, 0, id, NULL_id); return (id); } /* * SET A DEFAULT TEMPLATE TYPE ARGUMENT * * This routine sets the default value for the template type parameter id * to be t. */ void init_type_param(IDENTIFIER id, TYPE t) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); COPY_dspec (id_storage (id), (ds & ~dspec_pure)); IGNORE define_type_token (id, t, 0); COPY_dspec (id_storage (id), ds); return; } /* * DECLARE A TEMPLATE EXPRESSION PARAMETER * * This routine declares a template expression parameter named id of * type t. */ IDENTIFIER make_exp_param(TYPE t, IDENTIFIER id) { TOKEN tok; t = rvalue_type (t); MAKE_tok_exp (t, 1, NULL_exp, tok); id = make_token_decl (tok, 0, id, NULL_id); return (id); } /* * SET A DEFAULT TEMPLATE EXPRESSION ARGUMENT * * This routine sets the default value for the template expression * parameter id to be e. */ void init_exp_param(IDENTIFIER id, EXP e) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); COPY_dspec (id_storage (id), (ds & ~dspec_pure)); IGNORE define_exp_token (id, e, 1); COPY_dspec (id_storage (id), ds); return; } /* * DECLARE A TEMPLATE TEMPLATE PARAMETER * * This routine declares a template template parameter named id of type t. */ IDENTIFIER make_template_param(TYPE t, IDENTIFIER id) { TOKEN tok; MAKE_tok_class (t, NULL_id, tok); id = redecl_templ_param (id); id = make_token_decl (tok, 0, id, NULL_id); return (id); } /* * SET A TEMPLATE TEMPLATE ARGUMENT * * This routine sets the value for the template template parameter id to * be tid. This is used both to set a default argument value and to * define a template template parameter. */ void init_template_param(IDENTIFIER id, IDENTIFIER tid) { if (!IS_NULL_id (tid)) { if (IS_id_class_name_etc (tid)) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); COPY_dspec (id_storage (id), (ds & ~dspec_pure)); IGNORE define_templ_token (id, tid); COPY_dspec (id_storage (id), ds); } else { report (crt_loc, ERR_temp_arg_templ_not (id, tid)); } } return; } /* * LIST OF DUMMY TYPE PARAMETERS * * This list is used to store all the dummy type parameters created by * make_dummy_type to avoid duplicates. */ static LIST (IDENTIFIER) dummy_types = NULL_list (IDENTIFIER); /* * CREATE A DUMMY TYPE PARAMETER * * This routine creates a dummy type parameter named id in the namespace * ns. bt gives the token type kind. */ static TYPE make_dummy_type(NAMESPACE ns, IDENTIFIER id, BASE_TYPE bt, LIST (TOKEN) args) { TYPE t; HASHID nm = DEREF_hashid (id_name (id)); LIST (IDENTIFIER) p = dummy_types; while (!IS_NULL_list (p)) { IDENTIFIER pid = DEREF_id (HEAD_list (p)); HASHID pnm = DEREF_hashid (id_name (pid)); NAMESPACE pns = DEREF_nspace (id_parent (pid)); if (EQ_hashid (nm, pnm) && EQ_nspace (ns, pns)) { TOKEN tok = DEREF_tok (id_token_sort (pid)); BASE_TYPE pt = DEREF_btype (tok_type_kind (tok)); if (bt == pt) { id = pid; break; } } p = TAIL_list (p); } if (IS_NULL_list (p)) { /* Create new parameter */ TOKEN tok; DECL_SPEC ds = (dspec_template | dspec_token | dspec_auto | dspec_pure | dspec_implicit); MAKE_tok_type (bt, NULL_type, tok); MAKE_id_token (nm, ds, ns, crt_loc, tok, NULL_id, id); COPY_id (id_token_alt (id), id); CONS_id (id, dummy_types, dummy_types); } MAKE_type_token (cv_none, id, args, t); return (t); } /* * DOES A TYPE REPRESENT A TEMPLATE SPECIALISATION? * * This routine checks whether the type t represents an explicit template * specialisation or instantiation. */ int is_templ_spec(TYPE t) { while (!IS_NULL_type (t) && IS_type_templ (t)) { LIST (IDENTIFIER) pids; TOKEN sort = DEREF_tok (type_templ_sort (t)); pids = DEREF_list (tok_templ_pids (sort)); if (IS_NULL_list (pids)) return (1); t = DEREF_type (type_templ_defn (t)); } return (0); } /* * IS A TYPE A TEMPLATE PARAMETER? * * This routine checks whether the type t represents a template parameter * and a template declaration is currently being processed. */ int is_templ_type(TYPE t) { if (!IS_NULL_type (t) && IS_type_token (t)) { IDENTIFIER id = DEREF_id (type_token_tok (t)); if (is_templ_param (id)) return (in_template_decl); } return (0); } /* * DOES A TYPE DEPEND ON A TEMPLATE TYPE PARAMETER? * * This routine checks whether the type t is dependent on any template * parameter. */ int is_templ_depend(TYPE t) { if (in_template_decl) { /* Only need to check in a template declaration */ return (depends_on (t, any_templ_param)); } return (0); } /* * IS AN IDENTIFIER A TEMPLATE TYPE PARAMETER? * * This routine checks whether the token identifier id represents a * template type parameter. */ int is_templ_param(IDENTIFIER id) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if ((ds & dspec_template) && (ds & dspec_auto)) return (1); return (0); } /* * IS AN IDENTIFIER AN ALIAS FOR A TEMPLATE TYPE PARAMETER? * * This routine checks whether the identifier id is the internal name * for a template type parameter. */ int is_templ_alias(IDENTIFIER id) { unsigned tag = TAG_id (id); if (tag == id_type_alias_tag) { TYPE t = DEREF_type (id_type_alias_defn (id)); if (IS_type_token (t)) { id = DEREF_id (type_token_tok (t)); tag = TAG_id (id); } } else if (tag == id_token_tag) { id = DEREF_id (id_token_alt (id)); tag = TAG_id (id); } if (tag == id_token_tag && is_templ_param (id)) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (!(ds & dspec_implicit)) return (1); } return (0); } /* * IS AN IDENTIFIER A TEMPLATE DECLARATOR? * * This routine checks whether the declarator id represents a template * instance. If id is a function declaration then t gives the function * type. */ int is_templ_decl(IDENTIFIER id, TYPE t) { if (crt_templ_qualifier) { /* Declaration is a template-id */ IDENTIFIER tid = find_template (id, 0); if (!IS_NULL_id (tid)) return (1); } if (!IS_NULL_type (t) && crt_id_qualifier != qual_none) { /* Function declarator is a qualified-id */ int eq = 0; LIST (IDENTIFIER) pids = NULL_list (IDENTIFIER); IDENTIFIER pid = resolve_func (id, t, 1, 1, pids, &eq); if (!IS_NULL_id (pid)) { IDENTIFIER tid = find_template (pid, 0); if (!IS_NULL_id (tid)) return (1); } } return (0); } /* * IS A NAMESPACE A TEMPLATE CLASS? * * This routine checks whether the namespace ns represents a template * class or a nested class of a template class or a block of a template * function. */ int is_templ_nspace(NAMESPACE ns) { while (!IS_NULL_nspace (ns)) { IDENTIFIER tid; IDENTIFIER id = DEREF_id (nspace_name (ns)); if (IS_NULL_id (id)) break; tid = find_template (id, 1); if (!IS_NULL_id (tid)) return (1); ns = DEREF_nspace (id_parent (id)); } return (0); } /* * CHECK A TYPENAME * * This routine checks whether 'typename ns::id' can be used to declare * a type. If so this type is returned, otherwise the null type is * returned. Any following template arguments are dealt with in this * routine. */ TYPE check_typename(NAMESPACE ns, IDENTIFIER id, BASE_TYPE key) { TYPE s = NULL_type; if (in_template_decl) { if (!IS_NULL_nspace (ns) && IS_nspace_ctype (ns)) { IDENTIFIER tid = DEREF_id (nspace_name (ns)); TYPE t = DEREF_type (id_class_name_etc_defn (tid)); while (IS_type_templ (t)) { /* Step over any template qualifiers */ t = DEREF_type (type_templ_defn (t)); } if (is_templ_depend (t)) { /* Qualifier depends on a template parameter */ int templ = 0; LIST (TOKEN) args = NULL_list (TOKEN); if (crt_lex_token == lex_less) { /* Step over template arguments */ PPTOKEN *p = skip_template_args (NULL_id, 1); args = parse_template_args (p); templ = 1; } if (IS_id_class_name_etc (id)) { if (templ) { /* Apply template arguments */ id = apply_template (id, args, 0, 0); } s = DEREF_type (id_class_name_etc_defn (id)); if (IS_type_templ (s)) { s = deduce_type_template (id, 1); } s = copy_typedef (id, s, cv_none); COPY_id (type_name (s), id); use_id (id, 0); } else { BASE_TYPE bt = (btype_template | btype_typename); if (templ) bt |= btype_args; s = make_dummy_type (ns, id, bt, args); if (key != btype_none) { /* Result should be a class */ id = DEREF_id (type_token_tok (s)); args = NULL_list (TOKEN); s = make_dummy_class (id, args, key); } } } } } return (s); } /* * DECLARE A TYPENAME * * This routine handles a type declared using typename. ns gives the * name qualifiers used in the declaration and id gives the actual member * name. Any following template arguments are dealt with in this * routine. */ TYPE make_typename(NAMESPACE ns, IDENTIFIER id) { TYPE s = check_typename (ns, id, btype_none); if (IS_NULL_type (s)) { int templ = 0; LIST (TOKEN) args = NULL_list (TOKEN); report (crt_loc, ERR_temp_res_qual ()); if (crt_lex_token == lex_less) { /* Step over template arguments */ PPTOKEN *p = skip_template_args (NULL_id, 1); args = parse_template_args (p); templ = 1; } if (IS_id_class_name_etc (id)) { /* Name denotes a type - return that */ if (templ) { /* Apply template arguments */ id = apply_template (id, args, 0, 0); } s = DEREF_type (id_class_name_etc_defn (id)); if (IS_type_templ (s)) { s = deduce_type_template (id, 1); } s = copy_typedef (id, s, cv_none); COPY_id (type_name (s), id); use_id (id, 0); } else { /* Return the error type */ s = type_error; } } return (s); } /* * LIST OF BAD TYPENAMES * * Without some action, an illegal typename can be reported many times. * A list of all bad typename look-ups is maintained so that the error is * only reported once. */ static LIST (IDENTIFIER) non_typenames = NULL_list (IDENTIFIER); /* * FIND THE TYPE GIVEN BY A TYPENAME * * This routine expands the type name id. If no expansion is possible * then the null type is returned. type indicates whether the look-up * should be for a type name or an object name (the latter is used when * searching for a type previously declared using typename). */ TYPE find_typename(IDENTIFIER id, LIST (TOKEN) args, BASE_TYPE bt, int type) { TYPE t = NULL_type; NAMESPACE ns = DEREF_nspace (id_parent (id)); NAMESPACE cns = rescan_nspace (ns); if (!EQ_nspace (cns, ns)) { /* Rescan type name */ LIST (IDENTIFIER) p; HASHID nm = DEREF_hashid (id_name (id)); IDENTIFIER tid = search_field (cns, nm, 0, type); if (!IS_NULL_id (tid) && IS_id_class_name_etc (tid)) { /* Type name */ if (bt & btype_args) { /* Apply template arguments */ tid = apply_template (tid, args, 0, 0); } t = DEREF_type (id_class_name_etc_defn (tid)); if (IS_type_templ (t)) { t = deduce_type_template (tid, 1); } t = copy_typedef (tid, t, cv_none); COPY_id (type_name (t), tid); use_id (tid, 0); return (t); } /* Check for template parameters */ if (in_template_decl) { if (!IS_NULL_nspace (cns) && IS_nspace_ctype (cns)) { tid = DEREF_id (nspace_name (cns)); t = DEREF_type (id_class_name_etc_defn (tid)); while (IS_type_templ (t)) { t = DEREF_type (type_templ_defn (t)); } if (is_templ_depend (t)) { t = make_dummy_type (cns, id, bt, args); return (t); } } } /* Report error */ p = non_typenames; t = type_error; while (!IS_NULL_list (p)) { IDENTIFIER pid = DEREF_id (HEAD_list (p)); HASHID pnm = DEREF_hashid (id_name (pid)); NAMESPACE pns = DEREF_nspace (id_parent (pid)); if (EQ_hashid (pnm, nm) && EQ_nspace (pns, cns)) { /* Already reported */ break; } } if (IS_NULL_list (p)) { /* Report undefined type */ MAKE_id_type_alias (nm, dspec_none, cns, crt_loc, t, tid); CONS_id (tid, non_typenames, non_typenames); report (crt_loc, ERR_temp_res_type (cns, nm)); } } return (t); } /* * IDENTIFY TWO LISTS OF TEMPLATE PARAMETERS * * This routine identifies the list of template parameters ps with those * in pt, returning true if this is possible. */ int eq_templ_params(LIST (IDENTIFIER) ps, LIST (IDENTIFIER) pt) { int ok = 1; while (!IS_NULL_list (ps) && !IS_NULL_list (pt)) { IDENTIFIER is = DEREF_id (HEAD_list (ps)); IDENTIFIER it = DEREF_id (HEAD_list (pt)); if (!EQ_id (is, it)) { TOKEN ns, nt; unsigned vs, vt; if (IS_NULL_id (is)) return (0); if (IS_NULL_id (it)) return (0); ns = DEREF_tok (id_token_sort (is)); nt = DEREF_tok (id_token_sort (it)); vs = TAG_tok (ns); vt = TAG_tok (nt); if (vs != vt) { /* Parameter sorts should be equal */ ok = 0; break; } if (vs == tok_exp_tag) { /* Check expression parameter types */ TYPE rs = DEREF_type (tok_exp_type (ns)); TYPE rt = DEREF_type (tok_exp_type (nt)); rs = expand_type (rs, 2); if (eq_type (rs, rt) != 1) { ok = 0; break; } } if (vs == tok_class_tag) { /* Check template class parameter types */ TYPE rs = DEREF_type (tok_class_type (ns)); TYPE rt = DEREF_type (tok_class_type (nt)); rs = expand_type (rs, 2); if (eq_template (rs, rt, 0, 1, 0) != 3) { ok = 0; break; } } it = DEREF_id (id_alias (it)); COPY_id (id_alias (is), it); } pt = TAIL_list (pt); ps = TAIL_list (ps); } if (!EQ_list (ps, pt)) ok = 0; return (ok); } /* * RESTORE A LIST OF TEMPLATE PARAMETERS * * This routine clears the aliases set up by eq_templ_param from the * list of template parameters ps. */ void restore_templ_params(LIST (IDENTIFIER) ps) { while (!IS_NULL_list (ps)) { IDENTIFIER is = DEREF_id (HEAD_list (ps)); COPY_id (id_alias (is), is); ps = TAIL_list (ps); } return; } /* * CHECK FOR TEMPLATE TYPE EQUALITY * * This routine checks whether the template types s and t are equal * under a simple renaming of template parameters. If def is false * only the template parameters (and not the underlying type) are checked. * mq and rf are as in eq_func_type, as is the return value. */ int eq_template(TYPE s, TYPE t, int def, int mq, int rf) { TOKEN as = DEREF_tok (type_templ_sort (s)); TOKEN at = DEREF_tok (type_templ_sort (t)); LIST (IDENTIFIER) ps = DEREF_list (tok_templ_pids (as)); LIST (IDENTIFIER) pt = DEREF_list (tok_templ_pids (at)); int eq = eq_templ_params (ps, pt); if (eq && def) { /* Check for equality of definitions */ int ft = force_template; TYPE ds = DEREF_type (type_templ_defn (s)); TYPE dt = DEREF_type (type_templ_defn (t)); force_template = 0; eq = eq_func_type (ds, dt, mq, rf); force_template = ft; } restore_templ_params (ps); return (eq); } /* * RENAME TEMPLATE PARAMETERS IN A TYPE * * This routine renames the parameters in the given template sort, * returning the template type formed by applying this renaming to t. */ static TYPE rename_templ_params(TOKEN sort, TYPE t, int rec) { if (rec) { int d; LIST (TOKEN) args; LIST (IDENTIFIER) pids; LIST (IDENTIFIER) qids; pids = DEREF_list (tok_templ_pids (sort)); sort = expand_sort (sort, 1, 1); qids = DEREF_list (tok_templ_pids (sort)); args = make_primary_args (qids); d = save_token_args (pids, args); t = expand_type (t, 1); restore_token_args (pids, d); } MAKE_type_templ (cv_none, sort, t, 1, t); return (t); } /* * CHECK FOR TEMPLATE TYPE SPECIALISATION * * This routine checks whether the type t is a specialisation of the * template type s. Type qualifiers are ignored if qu is false. */ int deduce_template(TYPE s, TYPE t, int qu) { int eq; TYPE r = DEREF_type (type_templ_defn (s)); TOKEN sort = DEREF_tok (type_templ_sort (s)); LIST (IDENTIFIER) pids = DEREF_list (tok_templ_pids (sort)); if (in_template_decl && depends_on (t, pids)) { /* Rename parameters if necessary */ CV_SPEC cv = DEREF_cv (type_qual (s)); s = rename_templ_params (sort, r, 1); COPY_cv (type_qual (s), cv); eq = deduce_template (s, t, qu); } else { /* Perform argument deduction */ int d; force_template++; d = save_token_args (pids, NULL_list (TOKEN)); eq = eq_type_qual (r, t, qu); if (eq == 3) eq = 0; restore_token_args (pids, d); force_template--; } return (eq); } /* * REDECLARE A TEMPLATE TYPE * * This routine checks the redeclaration of the template id of type ps to * have type pt. The primary purpose of this is to check for default * arguments in the redeclaration. The non-template components are * returned via ps and pt. */ void redecl_template(TYPE *ps, TYPE *pt, IDENTIFIER id) { TYPE s = *ps; TYPE t = *pt; while (IS_type_templ (s)) { s = DEREF_type (type_templ_defn (s)); } while (IS_type_templ (t)) { TOKEN sort = DEREF_tok (type_templ_sort (t)); DECL_SPEC use = DEREF_dspec (tok_templ_usage (sort)); if (use & dspec_extern) export_template (id, 1); if (check_templ_dargs (t)) { /* Can't have default arguments in redeclaration */ report (decl_loc, ERR_temp_param_redecl ()); } t = DEREF_type (type_templ_defn (t)); } *pt = t; *ps = s; return; } /* * RESET THE PRIMARY FORM OF A TEMPLATE * * This routine changes the primary representation of a template from * s to t. This is done when, for example, the latter is a definition * while the former is only a declaration. */ void reset_primary_templ(TYPE s, TYPE t) { unsigned ns = TAG_type (s); unsigned nt = TAG_type (t); while (ns == type_templ_tag && nt == type_templ_tag) { TOKEN as = DEREF_tok (type_templ_sort (s)); TOKEN at = DEREF_tok (type_templ_sort (t)); LIST (IDENTIFIER) ps = DEREF_list (tok_templ_pids (as)); LIST (IDENTIFIER) pt = DEREF_list (tok_templ_pids (at)); INSTANCE apps = DEREF_inst (tok_templ_apps (as)); INSTANCE app = apps; LIST (TOKEN) dargs = DEREF_list (tok_templ_dargs (as)); while (!IS_NULL_inst (app)) { DECL_SPEC ds = DEREF_dspec (inst_templ_access (app)); if (ds & dspec_main) { /* Replace primary template instance */ TYPE form = DEREF_type (inst_form (app)); LIST (TOKEN) args = make_primary_args (pt); COPY_tok (type_templ_sort (form), at); form = DEREF_type (type_templ_defn (form)); COPY_list (type_token_args (form), args); } app = DEREF_inst (inst_next (app)); } if (check_templ_dargs (s)) { /* Expand default arguments */ LIST (TOKEN) args = make_primary_args (pt); int d = save_token_args (ps, args); dargs = expand_args (dargs, 1, 1); restore_token_args (ps, d); } COPY_list (tok_templ_dargs (at), dargs); COPY_inst (tok_templ_apps (at), apps); s = DEREF_type (type_templ_defn (s)); t = DEREF_type (type_templ_defn (t)); ns = TAG_type (s); nt = TAG_type (t); } return; } /* * IS AN IDENTIFIER A TEMPLATE PARAMETER? * * This routine checks whether the token identifier id is one of the * template or token parameters given by pids. */ int depends_on_param(IDENTIFIER id, LIST (IDENTIFIER) pids) { if (IS_id_token (id)) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (!(ds & dspec_ignore)) { if (EQ_list (pids, any_templ_param)) { /* Short-cut for list of all template parameters */ if ((ds & dspec_template) && (ds & dspec_auto)) { return (1); } return (0); } if (EQ_list (pids, any_token_param)) { /* Short-cut for list of all token parameters */ if (ds & dspec_auto) return (1); return (0); } while (!IS_NULL_list (pids)) { IDENTIFIER pid = DEREF_id (HEAD_list (pids)); if (EQ_id (pid, id)) return (1); pids = TAIL_list (pids); } } } return (0); } /* * DOES AN IDENTIFIER DEPEND ON A TEMPLATE PARAMETER? * * This routine checks whether the identifier id is one of the template * parameters pids or is a template function with an argument depending * on pids. If use is true then any other identifiers found are marked * as used. */ static int depends_on_id(IDENTIFIER id, LIST (IDENTIFIER) pids, int use) { if (!IS_NULL_id (id)) { NAMESPACE ns; switch (TAG_id (id)) { case id_class_name_tag : { /* Check for template classes */ TYPE form; CLASS_TYPE ct; TYPE t = DEREF_type (id_class_name_defn (id)); while (IS_type_templ (t)) { t = DEREF_type (type_templ_defn (t)); } ct = DEREF_ctype (type_compound_defn (t)); form = DEREF_type (ctype_form (ct)); if (!IS_NULL_type (form)) { if (depends_on (form, pids)) return (1); } break; } case id_function_tag : case id_mem_func_tag : case id_stat_mem_func_tag : { /* Check for template functions */ TYPE form = DEREF_type (id_function_etc_form (id)); if (!IS_NULL_type (form)) { /* Check function form */ if (depends_on (form, pids)) return (1); } if (use) reuse_id (id, 0); break; } case id_token_tag : { /* Check for template parameters */ if (depends_on_param (id, pids)) return (1); break; } case id_ambig_tag : { /* Check ambiguous identifiers */ LIST (IDENTIFIER) qids; qids = DEREF_list (id_ambig_ids (id)); while (!IS_NULL_list (qids)) { IDENTIFIER qid = DEREF_id (HEAD_list (qids)); if (depends_on_id (qid, pids, use)) return (1); qids = TAIL_list (qids); } break; } case id_stat_member_tag : { /* Mark static data members */ if (use) reuse_id (id, 0); break; } } ns = DEREF_nspace (id_parent (id)); if (!IS_NULL_nspace (ns)) { /* Check enclosing namespace */ IDENTIFIER cid = DEREF_id (nspace_name (ns)); return (depends_on_id (cid, pids, 0)); } } return (0); } /* * DOES A LIST OF TOKEN ARGUMENTS DEPEND ON A TEMPLATE PARAMETER? * * This routine checks whether the list of token arguments args depends * on one of the template parameters pids. If next is true then the * algorithm is modified to check whether any token argument depends * on a later template parameter (e.g. does the first element of args * depend on the second, third, etc. element of pids). */ int depends_on_args(LIST (TOKEN) args, LIST (IDENTIFIER) pids, int use, int next) { while (!IS_NULL_list (args)) { TOKEN tok = DEREF_tok (HEAD_list (args)); if (next) { /* Move on to next parameter */ if (IS_NULL_list (pids)) break; pids = TAIL_list (pids); } if (!IS_NULL_tok (tok)) { switch (TAG_tok (tok)) { case tok_exp_tag : { EXP e = DEREF_exp (tok_exp_value (tok)); if (depends_on_exp (e, pids, use)) return (1); break; } case tok_stmt_tag : { EXP e = DEREF_exp (tok_stmt_value (tok)); if (depends_on_exp (e, pids, use)) return (1); break; } case tok_nat_tag : case tok_snat_tag : { NAT n = DEREF_nat (tok_nat_etc_value (tok)); if (depends_on_nat (n, pids, use)) return (1); break; } case tok_type_tag : { TYPE t = DEREF_type (tok_type_value (tok)); if (depends_on (t, pids)) return (1); break; } case tok_member_tag : { OFFSET off = DEREF_off (tok_member_value (tok)); if (depends_on_off (off, pids, use)) return (1); break; } case tok_class_tag : { /* NOT YET IMPLEMENTED */ break; } } } args = TAIL_list (args); } return (0); } /* * DOES AN INTEGRAL CONSTANT DEPEND ON A TEMPLATE PARAMETER? * * This routine checks whether the integral constant n depends on one * of the template parameters pids. */ int depends_on_nat(NAT n, LIST (IDENTIFIER) pids, int use) { if (!IS_NULL_nat (n)) { switch (TAG_nat (n)) { case nat_calc_tag : { EXP e = DEREF_exp (nat_calc_value (n)); return (depends_on_exp (e, pids, use)); } case nat_token_tag : { IDENTIFIER tid = DEREF_id (nat_token_tok (n)); LIST (TOKEN) args = DEREF_list (nat_token_args (n)); if (depends_on_param (tid, pids)) return (2); if (depends_on_args (args, pids, use, 0)) return (1); break; } } } return (0); } /* * DOES A LIST OF EXPRESSIONS DEPEND ON A TEMPLATE PARAMETER? * * This routine checks whether the list of expressions p depends on one * of the template parameters pids. */ static int depends_on_exp_list(LIST (EXP) p, LIST (IDENTIFIER) pids, int use) { while (!IS_NULL_list (p)) { EXP a = DEREF_exp (HEAD_list (p)); if (depends_on_exp (a, pids, use)) return (1); p = TAIL_list (p); } return (0); } /* * DOES AN EXPRESSION DEPEND ON A TEMPLATE PARAMETER? * * This routine checks whether the expression e depends on one of the * template parameters pids. If e is actually a template parameter * then 2 is returned. */ int depends_on_exp(EXP e, LIST (IDENTIFIER) pids, int use) { if (!IS_NULL_exp (e)) { unsigned tag = TAG_exp (e); TYPE t = DEREF_type (exp_type (e)); if (tag == exp_token_tag) { /* Check for template parameters */ IDENTIFIER tid = DEREF_id (exp_token_tok (e)); LIST (TOKEN) args = DEREF_list (exp_token_args (e)); if (depends_on_param (tid, pids)) return (2); if (depends_on_args (args, pids, use, 0)) return (1); } if (depends_on (t, pids)) return (1); ASSERT (ORDER_exp == 88); switch (tag) { case exp_identifier_tag : case exp_member_tag : case exp_ambiguous_tag : case exp_undeclared_tag : { IDENTIFIER id = DEREF_id (exp_identifier_etc_id (e)); if (depends_on_id (id, pids, use)) return (1); break; } case exp_int_lit_tag : { NAT n = DEREF_nat (exp_int_lit_nat (e)); return (depends_on_nat (n, pids, use)); } case exp_paren_tag : case exp_copy_tag : { EXP a = DEREF_exp (exp_paren_etc_arg (e)); return (depends_on_exp (a, pids, use)); } case exp_assign_tag : { EXP a = DEREF_exp (exp_assign_ref (e)); EXP b = DEREF_exp (exp_assign_arg (e)); if (depends_on_exp (a, pids, use)) return (1); if (depends_on_exp (b, pids, use)) return (1); break; } case exp_init_tag : { IDENTIFIER id = DEREF_id (exp_init_id (e)); EXP a = DEREF_exp (exp_init_arg (e)); if (depends_on_id (id, pids, use)) return (1); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_preinc_tag : { EXP a = DEREF_exp (exp_preinc_op (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_postinc_tag : { EXP a = DEREF_exp (exp_postinc_op (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_indir_tag : { EXP a = DEREF_exp (exp_indir_ptr (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_contents_tag : { EXP a = DEREF_exp (exp_contents_ptr (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_address_tag : { EXP a = DEREF_exp (exp_address_arg (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_address_mem_tag : { EXP a = DEREF_exp (exp_address_mem_arg (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_func_tag : { EXP a = DEREF_exp (exp_func_fn (e)); LIST (EXP) p = DEREF_list (exp_func_args (e)); if (depends_on_exp (a, pids, use)) return (1); if (depends_on_exp_list (p, pids, use)) return (1); break; } case exp_func_id_tag : { IDENTIFIER id = DEREF_id (exp_func_id_id (e)); LIST (EXP) p = DEREF_list (exp_func_id_args (e)); if (depends_on_id (id, pids, use)) return (1); if (depends_on_exp_list (p, pids, use)) return (1); break; } case exp_call_tag : { EXP a = DEREF_exp (exp_call_ptr (e)); EXP b = DEREF_exp (exp_call_arg (e)); if (depends_on_exp (a, pids, use)) return (1); if (depends_on_exp (b, pids, use)) return (1); break; } case exp_negate_tag : case exp_compl_tag : case exp_not_tag : case exp_abs_tag : { EXP a = DEREF_exp (exp_negate_etc_arg (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_plus_tag : case exp_minus_tag : case exp_mult_tag : case exp_div_tag : case exp_rem_tag : case exp_and_tag : case exp_or_tag : case exp_xor_tag : case exp_log_and_tag : case exp_log_or_tag : case exp_lshift_tag : case exp_rshift_tag : case exp_max_tag : case exp_min_tag : { EXP a = DEREF_exp (exp_plus_etc_arg1 (e)); EXP b = DEREF_exp (exp_plus_etc_arg2 (e)); if (depends_on_exp (a, pids, use)) return (1); if (depends_on_exp (b, pids, use)) return (1); break; } case exp_test_tag : { EXP a = DEREF_exp (exp_test_arg (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_compare_tag : { EXP a = DEREF_exp (exp_compare_arg1 (e)); EXP b = DEREF_exp (exp_compare_arg2 (e)); if (depends_on_exp (a, pids, use)) return (1); if (depends_on_exp (b, pids, use)) return (1); break; } case exp_cast_tag : { EXP a = DEREF_exp (exp_cast_arg (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_base_cast_tag : { EXP a = DEREF_exp (exp_base_cast_arg (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_dyn_cast_tag : { EXP a = DEREF_exp (exp_dyn_cast_arg (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_add_ptr_tag : { EXP a = DEREF_exp (exp_add_ptr_ptr (e)); OFFSET off = DEREF_off (exp_add_ptr_off (e)); if (depends_on_exp (a, pids, use)) return (1); if (depends_on_off (off, pids, use)) return (1); break; } case exp_offset_size_tag : { OFFSET off = DEREF_off (exp_offset_size_off (e)); TYPE s = DEREF_type (exp_offset_size_step (e)); if (depends_on_off (off, pids, use)) return (1); if (depends_on (s, pids)) return (1); break; } case exp_constr_tag : { EXP a = DEREF_exp (exp_constr_call (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_destr_tag : { EXP a = DEREF_exp (exp_destr_call (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_alloc_tag : { EXP a = DEREF_exp (exp_alloc_call (e)); EXP b = DEREF_exp (exp_alloc_init (e)); if (depends_on_exp (a, pids, use)) return (1); if (depends_on_exp (b, pids, use)) return (1); break; } case exp_dealloc_tag : { EXP a = DEREF_exp (exp_dealloc_term (e)); EXP b = DEREF_exp (exp_dealloc_call (e)); if (depends_on_exp (a, pids, use)) return (1); if (depends_on_exp (b, pids, use)) return (1); break; } case exp_rtti_tag : { EXP a = DEREF_exp (exp_rtti_arg (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_rtti_type_tag : { TYPE s = DEREF_type (exp_rtti_type_arg (e)); if (depends_on (s, pids)) return (1); break; } case exp_rtti_no_tag : { TYPE s = DEREF_type (exp_rtti_no_arg (e)); if (depends_on (s, pids)) return (1); break; } case exp_dynamic_tag : { EXP a = DEREF_exp (exp_dynamic_arg (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_aggregate_tag : { LIST (EXP) p = DEREF_list (exp_aggregate_args (e)); if (depends_on_exp_list (p, pids, use)) return (1); break; } case exp_initialiser_tag : { LIST (EXP) p = DEREF_list (exp_initialiser_args (e)); if (depends_on_exp_list (p, pids, use)) return (1); break; } case exp_nof_tag : { EXP a = DEREF_exp (exp_nof_start (e)); EXP b = DEREF_exp (exp_nof_pad (e)); EXP c = DEREF_exp (exp_nof_end (e)); if (depends_on_exp (a, pids, use)) return (1); if (depends_on_exp (b, pids, use)) return (1); if (depends_on_exp (c, pids, use)) return (1); break; } case exp_comma_tag : { LIST (EXP) p = DEREF_list (exp_comma_args (e)); if (depends_on_exp_list (p, pids, use)) return (1); break; } case exp_set_tag : { EXP a = DEREF_exp (exp_set_arg (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_unused_tag : { EXP a = DEREF_exp (exp_unused_arg (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_sequence_tag : { LIST (EXP) p = DEREF_list (exp_sequence_first (e)); if (depends_on_exp_list (p, pids, use)) return (1); break; } case exp_if_stmt_tag : { EXP c = DEREF_exp (exp_if_stmt_cond (e)); EXP a = DEREF_exp (exp_if_stmt_true_code (e)); EXP b = DEREF_exp (exp_if_stmt_false_code (e)); if (depends_on_exp (c, pids, use)) return (1); if (depends_on_exp (a, pids, use)) return (1); if (depends_on_exp (b, pids, use)) return (1); break; } case exp_try_block_tag : { EXP a = DEREF_exp (exp_try_block_body (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_exception_tag : { EXP a = DEREF_exp (exp_exception_arg (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_op_tag : { EXP a = DEREF_exp (exp_op_arg1 (e)); EXP b = DEREF_exp (exp_op_arg2 (e)); if (depends_on_exp (a, pids, use)) return (1); if (depends_on_exp (b, pids, use)) return (1); break; } case exp_opn_tag : { LIST (EXP) p = DEREF_list (exp_opn_args (e)); if (depends_on_exp_list (p, pids, use)) return (1); break; } case exp_location_tag : { EXP a = DEREF_exp (exp_location_arg (e)); if (depends_on_exp (a, pids, use)) return (1); break; } case exp_dummy_tag : { EXP a = DEREF_exp (exp_dummy_value (e)); if (depends_on_exp (a, pids, use)) return (1); break; } } } return (0); } /* * DOES AN OFFSET DEPEND ON A TEMPLATE PARAMETER? * * This routine checks whether the offset off depends on one of the * template parameters pids. */ int depends_on_off(OFFSET off, LIST (IDENTIFIER) pids, int use) { if (!IS_NULL_off (off)) { ASSERT (ORDER_off == 13); switch (TAG_off (off)) { case off_zero_tag : { TYPE t = DEREF_type (off_zero_type (off)); if (depends_on (t, pids)) return (1); break; } case off_type_tag : { TYPE t = DEREF_type (off_type_type (off)); if (depends_on (t, pids)) return (1); break; } case off_array_tag : { TYPE t = DEREF_type (off_array_type (off)); if (depends_on (t, pids)) return (1); break; } case off_extra_tag : { TYPE t = DEREF_type (off_extra_type (off)); if (depends_on (t, pids)) return (1); break; } #if 0 case off_base_tag : { GRAPH graph = DEREF_graph (off_base_graph (off)); break; } case off_deriv_tag : { GRAPH graph = DEREF_graph (off_deriv_graph (off)); OFFSET direct = DEREF_off (off_deriv_direct (off)); OFFSET indirect = DEREF_off (off_deriv_indirect (off)); break; } case off_member_tag : { IDENTIFIER id = DEREF_id (off_member_id (off)); break; } #endif case off_ptr_mem_tag : { EXP a = DEREF_exp (off_ptr_mem_arg (off)); if (depends_on_exp (a, pids, use)) return (1); break; } case off_negate_tag : { OFFSET a = DEREF_off (off_negate_arg (off)); if (depends_on_off (a, pids, use)) return (1); break; } case off_plus_tag : { OFFSET a = DEREF_off (off_plus_arg1 (off)); OFFSET b = DEREF_off (off_plus_arg2 (off)); if (depends_on_off (a, pids, use)) return (1); if (depends_on_off (b, pids, use)) return (1); break; } case off_mult_tag : { OFFSET a = DEREF_off (off_mult_arg1 (off)); EXP b = DEREF_exp (off_mult_arg2 (off)); if (depends_on_off (a, pids, use)) return (1); if (depends_on_exp (b, pids, use)) return (1); break; } case off_ptr_diff_tag : { EXP a = DEREF_exp (off_ptr_diff_ptr1 (off)); EXP b = DEREF_exp (off_ptr_diff_ptr2 (off)); if (depends_on_exp (a, pids, use)) return (1); if (depends_on_exp (b, pids, use)) return (1); break; } case off_token_tag : { IDENTIFIER tid = DEREF_id (off_token_tok (off)); LIST (TOKEN) args = DEREF_list (off_token_args (off)); if (depends_on_param (tid, pids)) return (2); if (depends_on_args (args, pids, use, 0)) return (1); break; } } } return (0); } /* * DOES A TYPE DEPEND ON A TEMPLATE PARAMETER? * * This routine checks whether the type t depends on one of the template * parameters pids. */ int depends_on(TYPE t, LIST (IDENTIFIER) pids) { if (!IS_NULL_type (t)) { ASSERT (ORDER_type == 18); switch (TAG_type (t)) { case type_ptr_tag : case type_ref_tag : { TYPE s = DEREF_type (type_ptr_etc_sub (t)); return (depends_on (s, pids)); } case type_ptr_mem_tag : { TYPE s = DEREF_type (type_ptr_mem_sub (t)); CLASS_TYPE cr = DEREF_ctype (type_ptr_mem_of (t)); TYPE r = DEREF_type (ctype_form (cr)); if (depends_on (s, pids)) return (1); return (depends_on (r, pids)); } case type_func_tag : { TYPE r = DEREF_type (type_func_ret (t)); LIST (TYPE) p = DEREF_list (type_func_mtypes (t)); if (depends_on (r, pids)) return (1); while (!IS_NULL_list (p)) { TYPE s = DEREF_type (HEAD_list (p)); if (depends_on (s, pids)) return (1); p = TAIL_list (p); } break; } case type_array_tag : { TYPE s = DEREF_type (type_array_sub (t)); NAT n = DEREF_nat (type_array_size (t)); if (depends_on (s, pids)) return (1); return (depends_on_nat (n, pids, 0)); } case type_bitfield_tag : { INT_TYPE it = DEREF_itype (type_bitfield_defn (t)); TYPE s = DEREF_type (itype_bitfield_sub (it)); NAT n = DEREF_nat (itype_bitfield_size (it)); if (depends_on (s, pids)) return (1); return (depends_on_nat (n, pids, 0)); } case type_compound_tag : { CLASS_TYPE cs = DEREF_ctype (type_compound_defn (t)); IDENTIFIER cid = DEREF_id (ctype_name (cs)); return (depends_on_id (cid, pids, 0)); } case type_enumerate_tag : { ENUM_TYPE et = DEREF_etype (type_enumerate_defn (t)); IDENTIFIER eid = DEREF_id (etype_name (et)); return (depends_on_id (eid, pids, 0)); } case type_token_tag : { IDENTIFIER tid = DEREF_id (type_token_tok (t)); LIST (TOKEN) args = DEREF_list (type_token_args (t)); if (depends_on_param (tid, pids)) return (1); if (depends_on_args (args, pids, 0, 0)) return (1); if (IS_id_token (tid)) { TOKEN sort = DEREF_tok (id_token_sort (tid)); if (IS_tok_type (sort)) { BASE_TYPE bt; bt = DEREF_btype (tok_type_kind (sort)); if (bt & btype_typename) { /* Allow for typename */ return (depends_on_id (tid, pids, 0)); } } } break; } case type_templ_tag : { int dep; LIST (IDENTIFIER) qids; TYPE s = DEREF_type (type_templ_defn (t)); TOKEN sort = DEREF_tok (type_templ_sort (t)); qids = DEREF_list (tok_templ_pids (sort)); while (!IS_NULL_list (qids)) { /* Suppress template parameters */ IDENTIFIER qid = DEREF_id (HEAD_list (qids)); DECL_SPEC ds = DEREF_dspec (id_storage (qid)); ds |= dspec_ignore; COPY_dspec (id_storage (qid), ds); qids = TAIL_list (qids); } dep = depends_on (s, pids); qids = DEREF_list (tok_templ_pids (sort)); while (!IS_NULL_list (qids)) { /* Restore template parameters */ IDENTIFIER qid = DEREF_id (HEAD_list (qids)); DECL_SPEC ds = DEREF_dspec (id_storage (qid)); ds &= ~dspec_ignore; COPY_dspec (id_storage (qid), ds); qids = TAIL_list (qids); } return (dep); } } } return (0); } /* * DOES A FUNCTION CALL DEPEND ON A TEMPLATE PARAMETER? * * This routine checks whether the function call 'id (args)' depends * on a template parameter. */ int dependent_call(IDENTIFIER id, LIST (EXP) args) { if (in_template_decl) { /* Only check in a template declaration */ LIST (IDENTIFIER) pids = any_templ_param; if (depends_on_id (id, pids, 0)) return (1); if (IS_id_function_etc (id)) { while (!IS_NULL_id (id)) { TYPE t = DEREF_type (id_function_etc_type (id)); if (depends_on (t, pids)) return (1); id = DEREF_id (id_function_etc_over (id)); } } while (!IS_NULL_list (args)) { EXP a = DEREF_exp (HEAD_list (args)); if (!IS_NULL_exp (a)) { /* Check argument type */ TYPE t = DEREF_type (exp_type (a)); if (depends_on (t, pids)) return (1); } args = TAIL_list (args); } } return (0); } /* * DOES A FUNCTION CAST DEPEND ON A TEMPLATE PARAMETER? * * This routine checks whether the resolution of the overloaded function * id to the type t depends on a template parameter. */ int dependent_cast(IDENTIFIER id, TYPE t) { if (in_template_decl) { /* Only check in a template declaration */ LIST (IDENTIFIER) pids = any_templ_param; if (depends_on_id (id, pids, 0)) return (1); if (depends_on (t, pids)) return (1); } return (0); } /* * DOES A CONVERSION DEPEND ON A TEMPLATE PARAMETER? * * This routine checks whether the conversion 't (args)' depends * on a template parameter. */ int dependent_conv(TYPE t, LIST (EXP) args) { if (in_template_decl) { /* Only check in a template declaration */ LIST (IDENTIFIER) pids = any_templ_param; if (depends_on (t, pids)) return (1); while (!IS_NULL_list (args)) { EXP a = DEREF_exp (HEAD_list (args)); if (!IS_NULL_exp (a)) { /* Check argument type */ TYPE s = DEREF_type (exp_type (a)); if (depends_on (s, pids)) return (1); } args = TAIL_list (args); } } return (0); } /* * DOES AN IDENTIFIER DEPEND ON A TEMPLATE PARAMETER? * * This routine checks whether the identifier id depends on a template * parameter. */ int dependent_id(IDENTIFIER id) { if (in_template_decl) { /* Only check in a template declaration */ LIST (IDENTIFIER) pids = any_templ_param; if (depends_on_id (id, pids, 0)) return (1); } return (0); } /* * MARK THE IDENTIFIERS IN AN EXPRESSION AS USED * * This routine marks all the identifiers in the expression e as having * been used. This routine is combined with the depends_on functions * only because they happen to give a convenient tree-walking skeleton. */ void mark_used(EXP e) { if (!suppress_usage) { IGNORE depends_on_exp (e, NULL_list (IDENTIFIER), 1); } return; } /* * FIND AN INJECTED TYPE * * This routine modifies the type t which is injected from a template * into an enclosing scope (for example, a friend of a template class) * by qualifying it by copies of any unbound template qualifiers. */ TYPE injected_type(TYPE t, int rec) { IDENTIFIER pid = NULL_id; LIST (NAMESPACE) lns = LIST_stack (namespace_stack); while (!IS_NULL_list (lns)) { NAMESPACE ns = DEREF_nspace (HEAD_list (lns)); IDENTIFIER id = DEREF_id (nspace_name (ns)); if (!IS_NULL_id (id)) { if (!EQ_id (id, pid)) { TYPE s = NULL_type; switch (TAG_id (id)) { case id_class_name_tag : case id_class_alias_tag : { s = DEREF_type (id_class_name_etc_defn (id)); break; } case id_function_tag : case id_mem_func_tag : case id_stat_mem_func_tag : { s = DEREF_type (id_function_etc_type (id)); break; } } if (!IS_NULL_type (s) && IS_type_templ (s)) { LIST (IDENTIFIER) pids; TOKEN sort = DEREF_tok (type_templ_sort (s)); pids = DEREF_list (tok_templ_pids (sort)); if (depends_on (t, pids)) { t = rename_templ_params (sort, t, rec); } } pid = id; } } lns = TAIL_list (lns); } return (t); } /* * DUMMY TEMPLATE PARAMETER TYPE * * This variable gives a dummy template parameter type which allows the * propagation of types dependent in some non-obvious fashion on some * template parameter. */ TYPE type_templ_param; /* * INITIALISE TEMPLATE ROUTINES * * This routine initialises the template routines. In particular it * initialises the dummy template parameter type. */ void init_templates() { string s = ustrlit (""); unsigned long h = hash (s); HASHID nm = lookup_name (s, h, 0, lex_identifier); IDENTIFIER id = DEREF_id (hashid_id (nm)); LIST (TOKEN) args = NULL_list (TOKEN); TYPE t = make_dummy_type (crt_namespace, id, btype_template, args); type_templ_param = t; CONS_id (NULL_id, NULL_list (IDENTIFIER), any_templ_param); CONS_id (NULL_id, NULL_list (IDENTIFIER), any_token_param); return; }