/*
* Copyright (c) 2003, The Tendra Project <http://www.ten15.org/>
* 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 ("<type>");
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;
}
syntax highlighted by Code2HTML, v. 0.9.1