/* * Copyright (c) 2002, 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/identifier.c,v 1.8 2005/11/07 18:42:37 stefanf Exp $ */ #include "config.h" #include "producer.h" #include "c_types.h" #include "ctype_ops.h" #include "exp_ops.h" #include "id_ops.h" #include "hashid_ops.h" #include "member_ops.h" #include "nspace_ops.h" #include "tok_ops.h" #include "type_ops.h" #include "error.h" #include "catalog.h" #include "access.h" #include "basetype.h" #include "class.h" #include "constant.h" #include "construct.h" #include "convert.h" #include "declare.h" #include "derive.h" #include "dump.h" #include "exception.h" #include "expression.h" #include "file.h" #include "function.h" #include "hash.h" #include "identifier.h" #include "initialise.h" #include "instance.h" #include "namespace.h" #include "option.h" #include "parse.h" #include "predict.h" #include "redeclare.h" #include "syntax.h" #include "template.h" #include "tok.h" #include "token.h" /* * USAGE SUPPRESSION FLAG * * This flag may be set to true to indicate that the parser is in a sizeof * expression or similar so that any usages should not be included. */ int suppress_usage = 0; /* * MARK AN IDENTIFIER AS BEING USED * * This routine marks the identifier id as having been used and checks * any access controls. */ void use_id(IDENTIFIER id, int suppress) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); DECL_SPEC acc = (ds & dspec_access); if (acc) check_access (id, acc); /* Check usage */ if (ds & dspec_main) { HASHID nm = DEREF_hashid (id_name (id)); switch (TAG_hashid (nm)) { case hashid_name_tag : { /* Can't take the address of 'main' */ report (crt_loc, ERR_basic_start_main_addr (id)); break; } case hashid_constr_tag : { /* Can't take the address of a constructor */ report (crt_loc, ERR_class_ctor_addr (id)); break; } case hashid_destr_tag : { /* Can't take the address of a destructor */ report (crt_loc, ERR_class_dtor_addr (id)); break; } } } /* Mark use */ if (!(ds & dspec_used)) { if (!suppress) { ds |= dspec_used; COPY_dspec (id_storage (id), ds); } if (ds & (dspec_inherit | dspec_alias | dspec_extern)) { /* Check for inheritance */ IDENTIFIER uid = DEREF_id (id_alias (id)); if (!EQ_id (uid, id)) { ds = DEREF_dspec (id_storage (uid)); if (ds & dspec_used) { if (do_usage) dump_use (id, &crt_loc, 1); return; } if (!suppress) { ds |= dspec_used; COPY_dspec (id_storage (uid), ds); } } } if (!(ds & dspec_defn) && (ds & dspec_instance)) { /* Define template instance */ if (!suppress) define_template (id, 0); } } /* Remember references to identifiers with internal linkage */ if ((ds & dspec_static) && in_function_defn) { IDENTIFIER fn = crt_func_id; if (IS_NULL_id (DEREF_id (id_function_etc_static_ref (fn)))) { COPY_id (id_function_etc_static_ref (fn), id); } } if (do_usage) dump_use (id, &crt_loc, 1); return; } /* * MARK A FUNCTION IDENTIFIER AS BEING USED * * This routine marks the function identifier id as having been called * and checks any access controls. In addition certain checks are applied * to the first call of an identifier. expl is true for explicit calls. */ void use_func_id(IDENTIFIER id, int expl, int suppress) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); DECL_SPEC acc = (ds & dspec_access); if (acc) check_access (id, acc); if (!(ds & dspec_called)) { /* Mark use */ if (!suppress) { if (!(ds & dspec_virtual)) ds |= dspec_used; ds |= dspec_called; COPY_dspec (id_storage (id), ds); } /* Check for inheritance */ if (ds & (dspec_inherit | dspec_alias | dspec_extern)) { IDENTIFIER uid = DEREF_id (id_alias (id)); if (!EQ_id (uid, id)) { ds = DEREF_dspec (id_storage (uid)); if (ds & dspec_called) { if (do_usage) dump_call (id, &crt_loc, expl); return; } if (!suppress) { if (!(ds & dspec_virtual)) ds |= dspec_used; ds |= dspec_called; COPY_dspec (id_storage (uid), ds); } } } /* Check usage */ if (ds & dspec_main) { HASHID nm = DEREF_hashid (id_name (id)); if (IS_hashid_name (nm)) { /* Can't call 'main' */ report (crt_loc, ERR_basic_start_main_call (id)); } } if (!(ds & dspec_defn) && !suppress) { if (ds & dspec_implicit) { /* Define implicitly declared function */ implicit_defn (id, DEFAULT_USR); ds = DEREF_dspec (id_storage (id)); } else if (ds & dspec_instance) { /* Define template function */ if (!(ds & dspec_virtual)) { define_template (id, 0); ds = DEREF_dspec (id_storage (id)); } } if ((ds & dspec_inline) && !(ds & dspec_defn)) { /* An inline function called before it is defined */ report (crt_loc, ERR_dcl_fct_spec_inline_call (id)); } } } /* Remember references to identifiers with internal linkage */ if ((ds & dspec_static) && in_function_defn) { IDENTIFIER fn = crt_func_id; if (IS_NULL_id (DEREF_id (id_function_etc_static_ref (fn)))) { COPY_id (id_function_etc_static_ref (fn), id); } } if (do_usage) dump_call (id, &crt_loc, expl); return; } /* * MARK A VIRTUAL FUNCTION AS BEING USED * * Note that use_func_id does not mark virtual functions as having been * used because the actual function called can only be determined at * run-time. If subsequently it is found that the function called can * be determined statically then this routine is called to mark that * function as having been used. It is also used in certain similar * situations. */ void reuse_id(IDENTIFIER id, int suppress) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (!(ds & dspec_used) && !suppress) { ds |= dspec_used; COPY_dspec (id_storage (id), ds); if (!(ds & dspec_defn)) { if (ds & dspec_implicit) { /* Define implicitly declared function */ implicit_defn (id, DEFAULT_USR); } else if (ds & dspec_instance) { /* Instantiate template functions */ define_template (id, 0); } } } return; } /* * DEFINE AN IDENTIFIER ALIAS * * This routine is called if the function or variable id is defined * (excluding tentative definitions). It passes the definition on to * any alias of id. */ void define_id(IDENTIFIER id) { IDENTIFIER lid = DEREF_id (id_alias (id)); if (!EQ_id (lid, id)) { /* Check for previous definition */ LOCATION loc; DECL_SPEC ds; DEREF_loc (id_loc (id), loc); ds = DEREF_dspec (id_storage (lid)); if (ds & dspec_defn) { EXP e = DEREF_exp (id_variable_etc_init (lid)); if (IS_NULL_exp (e) || !IS_exp_zero (e)) { /* Exclude previous tentative definitions */ PTR (LOCATION) ploc = id_loc (lid); ERROR err = ERR_basic_odr_def (lid, ploc); if (ds & dspec_c) { /* Explain C linkage identifications */ HASHID nm = DEREF_hashid (id_name (lid)); ERROR err2 = ERR_dcl_link_redecl (nm, ploc); err = concat_error (err, err2); } report (loc, err); } } /* Copy definition */ if (IS_id_function_etc (id)) { EXP e = DEREF_exp (id_function_etc_defn (id)); COPY_exp (id_function_etc_defn (lid), e); } else if (IS_id_variable_etc (id)) { TYPE t = DEREF_type (id_variable_etc_type (id)); EXP e = DEREF_exp (id_variable_etc_init (id)); EXP d = DEREF_exp (id_variable_etc_term (id)); COPY_exp (id_variable_etc_init (lid), e); COPY_exp (id_variable_etc_term (lid), d); COPY_type (id_variable_etc_type (lid), t); } /* Record definition */ ds |= dspec_defn; COPY_dspec (id_storage (lid), ds); DEREF_loc (id_loc (lid), loc); } return; } /* * FIND THE END OF A LIST OF IDENTIFIER ALIASES * * In most cases the alias of an identifier is its underlying meaning, * however for function parameters it is possible to have vast lists * of identifiers arising from redeclarations all linked by their alias * field. This routine scans down such a list until it finds an identifier * which is its own alias. */ IDENTIFIER chase_alias(IDENTIFIER id) { while (!IS_NULL_id (id)) { IDENTIFIER lid = DEREF_id (id_alias (id)); if (EQ_id (lid, id)) break; id = lid; } return (id); } /* * CURRENT IDENTIFIER QUALIFIER * * This variable is set to describe how the current identifier is * qualified. */ QUALIFIER crt_id_qualifier = qual_none; int crt_templ_qualifier = 0; /* * CHECK AN IDENTIFIER NAME * * This routine checks whether the identifier name id is suitable for use * in the context given by loc. The namespace qualifiers used in describing * id will be given by crt_id_qualifier. The routine returns true for * legal identifiers. */ ERROR check_id_name(IDENTIFIER id, int loc) { /* Check on namespace component */ ERROR err = NULL_err; QUALIFIER cq = crt_id_qualifier; switch (cq) { case qual_none : { /* No namespace specifier */ if (in_template_decl && is_templ_alias (id)) { /* Check for hiding of template parameters */ err = ERR_temp_local_hide (id); if (!IS_NULL_err (err)) return (err); } if (crt_templ_qualifier) goto qualifier_lab; break; } case qual_nested : qualifier_lab : { /* Nested namespace specifier */ if (loc == CONTEXT_PARAMETER || loc == CONTEXT_TEMPL_PARAM) { err = ERR_dcl_meaning_id (cq, id); if (!IS_NULL_err (err)) return (err); } break; } case qual_full : case qual_top : { /* Namespace specifier beginning with '::' */ err = ERR_dcl_meaning_full (cq, id); if (!IS_NULL_err (err)) return (err); goto qualifier_lab; } } /* Check on name component */ if (loc != CONTEXT_FUNCTION && loc != CONTEXT_FUNC_MEMBER) { HASHID nm = DEREF_hashid (id_name (id)); switch (TAG_hashid (nm)) { case hashid_constr_tag : { /* A constructor must be a member function */ err = ERR_class_mem_ctor (id); break; } case hashid_destr_tag : { /* A destructor must be a member function */ err = ERR_class_dtor_func (nm); break; } case hashid_conv_tag : case hashid_op_tag : { /* These must be functions */ err = ERR_dcl_meaning_id (cq, id); break; } } } return (err); } /* * DECLARE AN IMPLICIT FUNCTION * * This routine declares a function named id in the current scope with * declaration specifiers ds, return type ret (which may be the null type), * parameter types p (terminated by the null type), and function kind ell. * It is used to declare implicit functions. */ IDENTIFIER declare_func(DECL_SPEC ds, IDENTIFIER id, TYPE ret, TYPE *p, int ell, LIST (TYPE) ex) { /* Save certain information */ TYPE t; CV_SPEC cv; DECL_SPEC acc = crt_access; int td = have_type_declaration; QUALIFIER cq = crt_id_qualifier; int tq = crt_templ_qualifier; crt_access = dspec_public; crt_id_qualifier = qual_none; crt_templ_qualifier = 0; have_type_declaration = TYPE_DECL_NONE; /* Declare parameters */ decl_loc = crt_loc; begin_param (id); while (!IS_NULL_type (*p)) { HASHID nm = lookup_anon (); IDENTIFIER pid = DEREF_id (hashid_id (nm)); pid = make_param_decl (dspec_none, *p, pid, CONTEXT_PARAMETER); init_param (pid, NULL_exp); p++; } if (IS_NULL_type (ret)) ret = type_inferred; cv = func_linkage (cv_none); t = make_func_type (ret, ell, cv, ex); end_param (); /* Declare the function */ if (in_class_defn) { #if LANGUAGE_CPP if (ds & dspec_friend) { id = make_friend_decl (ds, t, id, 0, 1); } else { id = make_func_mem_decl (ds, t, id, 0); } #else id = make_member_decl (ds, t, id, 0); #endif } else { id = make_func_decl (ds, t, id, 0); } if (do_dump) { dump_implicit = 1; dump_declare (id, &decl_loc, 0); } have_type_declaration = td; crt_templ_qualifier = tq; crt_id_qualifier = cq; crt_access = acc; return (id); } /* * IMPLICITLY DECLARE AN IDENTIFIER * * This routine implicitly declares an identifier id, either as a local * variable, if fn is false, or as a function. fn will be 2 in the cases * where C allows an implicit function declaration. The routine returns * the corresponding identifier expression. */ EXP implicit_id_exp(IDENTIFIER id, int fn) { EXP e; ERROR err; LOCATION loc; DECL_SPEC ds; IDENTIFIER pid; DECL_SPEC cl = crt_linkage; QUALIFIER cq = crt_id_qualifier; int tq = crt_templ_qualifier; NAMESPACE cns = crt_namespace; HASHID nm = DEREF_hashid (id_name (id)); NAMESPACE ns = DEREF_nspace (id_parent (id)); /* Check for implicit function declarations */ if (fn == 2 && option (OPT_func_impl) == OPTION_DISALLOW) fn = 1; /* Allow for template dependent declarations */ if (in_template_decl && is_templ_nspace (cns)) { int opt = OPT_templ_undecl; OPTION sev = option (opt); if (sev != OPTION_ALLOW) { /* Implicit declarations for dependent identifiers */ if (dependent_id (id)) { opt = OPT_none; sev = OPTION_ALLOW; } } if (sev != OPTION_DISALLOW) { if (sev != OPTION_ALLOW && fn != 2) { if (cq == qual_none) { err = ERR_lookup_unqual_undef (nm); } else { err = ERR_lookup_qual_undef (nm, ns); } err = set_severity (err, opt, 0); report (crt_loc, err); } MAKE_exp_undeclared (type_templ_param, id, cq, e); return (e); } if (cq == qual_none) ns = NULL_nspace; } /* Check for previous declaration */ if (IS_NULL_nspace (ns)) { OPTION sev = option (OPT_decl_unify); if (sev != OPTION_OFF) { LIST (IDENTIFIER) p; NAMESPACE pns = nonblock_namespace; p = DEREF_list (nspace_named_etc_extra (pns)); pid = unify_extern (id, NULL_type, pns, p); if (!IS_NULL_id (pid)) { if (sev != OPTION_ON) { err = ERR_lookup_unqual_vis (pid); err = set_severity (err, OPT_decl_unify, 0); report (crt_loc, err); } e = make_id_exp (pid); return (e); } } ns = cns; } /* Rescan identifier */ pid = search_id (ns, nm, 0, 0); if (!IS_NULL_id (pid)) { switch (TAG_id (pid)) { case id_variable_tag : case id_function_tag : { e = make_id_exp (pid); return (e); } } } /* Find namespace for declaration */ crt_linkage = dspec_c; crt_id_qualifier = qual_none; crt_templ_qualifier = 0; push_namespace (ns); bad_crt_loc++; loc = crt_loc; if (crt_state_depth == 0) { /* Find identifier location */ IDENTIFIER uid = underlying_id (id); DEREF_loc (id_loc (uid), crt_loc); } if (fn) { /* Implicit functions declarations */ int ell; TYPE ret = type_sint; TYPE pars = NULL_type; #if LANGUAGE_CPP /* Type is 'int (...)' in C++ */ ell = FUNC_ELLIPSIS; if (fn == 1) ret = type_error; #else /* Type is 'int ()' in C */ ell = FUNC_NO_PARAMS; #endif ds = (dspec_extern | dspec_ignore); id = declare_func (ds, id, ret, &pars, ell, empty_type_set); } else { /* Other implicit declarations */ decl_loc = crt_loc; id = make_object_decl (dspec_none, type_error, id, 0); IGNORE init_object (id, NULL_exp); } /* Report error */ crt_linkage = cl; crt_templ_qualifier = tq; crt_id_qualifier = cq; if (fn == 2) { pid = DEREF_id (id_alias (id)); ds = DEREF_dspec (id_storage (pid)); if (ds & dspec_temp) { /* Implicit declaration already reported */ err = NULL_err; } else { err = ERR_expr_call_undecl (id); if (!IS_NULL_err (err)) { ds |= dspec_temp; COPY_dspec (id_storage (pid), ds); } } } else if (cq == qual_none) { err = ERR_lookup_unqual_undef (nm); } else { err = ERR_lookup_qual_undef (nm, ns); } report (crt_loc, err); /* Construct the result */ crt_loc = loc; bad_crt_loc--; IGNORE pop_namespace (); e = make_id_exp (id); return (e); } /* * LIST OF MEANINGS * * This list is built up by list_ambiguous to give all the meanings of * its ambiguous identifier which match its type argument. */ static LIST (IDENTIFIER) ambig_meanings = NULL_list (IDENTIFIER); /* * LIST MEANINGS OF AN AMBIGUOUS IDENTIFIER * * This routine adds all meanings of the ambiguous identifier id to the * error list err. */ static unsigned list_ambiguous(IDENTIFIER id, unsigned n, ERROR *err, int type, int rec) { if (!IS_NULL_id (id)) { switch (TAG_id (id)) { case id_ambig_tag : { /* Ambiguous identifiers */ LIST (IDENTIFIER) p = DEREF_list (id_ambig_ids (id)); rec = DEREF_int (id_ambig_over (id)); while (!IS_NULL_list (p)) { id = DEREF_id (HEAD_list (p)); n = list_ambiguous (id, n, err, type, rec); p = TAIL_list (p); } break; } case id_function_tag : case id_mem_func_tag : case id_stat_mem_func_tag : { /* Functions */ if (rec) { IDENTIFIER over; over = DEREF_id (id_function_etc_over (id)); n = list_ambiguous (over, n, err, type, rec); } goto default_lab; } case id_class_name_tag : case id_class_alias_tag : case id_enum_name_tag : case id_enum_alias_tag : case id_type_alias_tag : { /* Types */ type = 0; goto default_lab; } default : default_lab : { /* Other identifiers */ PTR (LOCATION) loc = id_loc (id); n++; add_error (err, ERR_fail_list_item (n, id, loc)); break; } } if (type == 0) { /* Add to list of meanings */ CONS_id (id, ambig_meanings, ambig_meanings); } } return (n); } /* * REPORT AN AMBIGUOUS IDENTIFIER * * This routine reports the identifier id as being ambiguous. Overloaded * functions count as a single identifier unless rec is true. It returns * one of the possible meanings. Only types are considered if type is * true. If there is exactly one possible meaning or force is true the * first meaning is returned. Otherwise the null identifier is returned. */ IDENTIFIER report_ambiguous(IDENTIFIER id, int type, int rec, int force) { ERROR err, err2; LIST (IDENTIFIER) p; NAMESPACE ns = DEREF_nspace (id_parent (id)); /* List all meanings */ if (!IS_NULL_nspace (ns) && IS_nspace_ctype (ns)) { err = ERR_lookup_ambig_mem (id); } else { err = ERR_lookup_ambig_id (id); } err2 = ERR_lookup_ambig_list (); if (!IS_NULL_err (err2)) { unsigned n = 0; err = concat_error (err, err2); n = list_ambiguous (id, n, &err, type, rec); err = concat_error (err, ERR_fail_list_end (n)); } report (crt_loc, err); /* Check for resolved meaning */ id = NULL_id; p = ambig_meanings; if (!IS_NULL_list (p)) { if (IS_NULL_list (TAIL_list (p)) || force) { id = DEREF_id (HEAD_list (p)); } DESTROY_list (p, SIZE_id); ambig_meanings = NULL_list (IDENTIFIER); } return (id); } /* * FIND THE DECLARATION SPECIFIER FOR AN AMBIGUOUS IDENTIFIER * * This routine finds the declaration specifier for an ambiguous identifier * given by the list of cases pids. This consists of various properties * which all the cases share. */ DECL_SPEC find_ambig_dspec(LIST (IDENTIFIER) pids) { DECL_SPEC ds = (dspec_implicit | dspec_template); while (!IS_NULL_list (pids)) { IDENTIFIER pid = DEREF_id (HEAD_list (pids)); if (!IS_NULL_id (pid)) { DECL_SPEC pds = DEREF_dspec (id_storage (pid)); ds &= pds; } pids = TAIL_list (pids); } return (ds); } /* * CREATE AN IDENTIFIER EXPRESSION * * This routine creates an expression corresponding to the identifier id. * Note that static member functions are identifier expressions if they * are not overloaded, but member expression otherwise. They are sorted * out properly during overload resolution (see resolve_cast). */ EXP make_id_exp(IDENTIFIER id) { EXP e; unsigned tag = TAG_id (id); QUALIFIER cq = crt_id_qualifier; switch (tag) { case id_variable_tag : case id_parameter_tag : { /* Variables and parameters */ TYPE t; DECL_SPEC ds; use_id (id, 0); ds = DEREF_dspec (id_storage (id)); if (ds & dspec_auto) { /* Check use of automatic variable */ NAMESPACE ns = crt_namespace; switch (TAG_nspace (ns)) { case nspace_block_tag : case nspace_dummy_tag : { if (really_in_function_defn > 1) { /* Used in nested function */ IDENTIFIER fid; ns = DEREF_nspace (id_parent (id)); fid = DEREF_id (nspace_name (ns)); if (!EQ_id (fid, crt_func_id)) { ERROR err = ERR_class_local_auto (id); report (crt_loc, err); } } break; } case nspace_param_tag : case nspace_templ_tag : { /* Used in default argument */ if (in_default_arg) { ERROR err = ERR_dcl_fct_default_param (id); report (crt_loc, err); } break; } default : { /* Used in local class */ ERROR err = ERR_class_local_auto (id); report (crt_loc, err); break; } } } t = DEREF_type (id_variable_etc_type (id)); if ((ds & dspec_extern) && cv_extern) { CV_SPEC cv = DEREF_cv (type_qual (t)); t = qualify_type (t, (cv | cv_extern), 0); used_extern_volatile = 1; } MAKE_exp_identifier (t, id, cq, e); break; } case id_stat_member_tag : { /* Static data members */ TYPE t; DECL_SPEC ds; use_id (id, suppress_usage); ds = DEREF_dspec (id_storage (id)); if (ds & dspec_inherit) id = DEREF_id (id_alias (id)); t = DEREF_type (id_stat_member_type (id)); if ((ds & dspec_extern) && cv_extern) { CV_SPEC cv = DEREF_cv (type_qual (t)); t = qualify_type (t, (cv | cv_extern), 0); used_extern_volatile = 1; } MAKE_exp_identifier (t, id, cq, e); break; } case id_function_tag : { /* Normal functions */ TYPE t = DEREF_type (id_function_type (id)); MAKE_exp_identifier (t, id, cq, e); break; } case id_stat_mem_func_tag : { /* Static member functions */ TYPE t = DEREF_type (id_stat_mem_func_type (id)); IDENTIFIER over = DEREF_id (id_stat_mem_func_over (id)); if (IS_NULL_id (over)) { MAKE_exp_identifier (t, id, cq, e); } else { MAKE_exp_member (t, id, cq, e); } break; } case id_mem_func_tag : { /* Non-static member functions */ TYPE t = DEREF_type (id_mem_func_type (id)); MAKE_exp_member (t, id, cq, e); break; } case id_member_tag : { /* Non-static members */ TYPE t = DEREF_type (id_member_type (id)); MAKE_exp_member (t, id, cq, e); break; } case id_enumerator_tag : { /* Enumerators */ NAT n; TYPE t; use_id (id, 0); e = DEREF_exp (id_enumerator_value (id)); DECONS_exp_int_lit (t, n, tag, e); MAKE_exp_int_lit (t, n, tag, e); break; } case id_token_tag : { /* Tokens */ TOKEN tok = DEREF_tok (id_token_sort (id)); switch (TAG_tok (tok)) { case tok_exp_tag : case tok_nat_tag : case tok_snat_tag : case tok_stmt_tag : { /* Expression tokens */ use_id (id, 0); id = DEREF_id (id_token_alt (id)); e = apply_exp_token (id, NULL_list (TOKEN), 0); break; } default : { /* Other tokens */ goto default_lab; } } break; } case id_class_name_tag : case id_enum_name_tag : case id_class_alias_tag : case id_enum_alias_tag : case id_type_alias_tag : { /* Type names */ TYPE t = DEREF_type (id_class_name_etc_defn (id)); report (crt_loc, ERR_expr_prim_type (id)); MAKE_exp_value (t, e); break; } case id_ambig_tag : { /* Ambiguous identifiers */ MAKE_exp_ambiguous (type_error, id, cq, e); break; } default : default_lab : { /* Undefined identifiers */ if (cq == qual_none && in_template_decl) { /* Create a dummy identifier */ HASHID nm = DEREF_hashid (id_name (id)); NAMESPACE ns = nonblock_namespace; MAKE_id_undef (nm, dspec_none, ns, crt_loc, id); } MAKE_exp_undeclared (type_error, id, cq, e); break; } } return (e); } /* * FIND THE THIS PARAMETER OF A FUNCTION * * This routine returns the 'this' parameter of the member function fn. * If use is true then the parameter is marked as used. */ IDENTIFIER this_param(IDENTIFIER fn, int use) { NAMESPACE ns; IDENTIFIER pid; HASHID nm = KEYWORD (lex_this_Hname); TYPE t = DEREF_type (id_mem_func_type (fn)); while (IS_type_templ (t)) { t = DEREF_type (type_templ_defn (t)); } ns = DEREF_nspace (type_func_pars (t)); pid = search_id (ns, nm, 0, 0); if (!IS_NULL_id (pid) && use) { /* Mark parameter as used */ DECL_SPEC ds = DEREF_dspec (id_storage (pid)); ds |= dspec_used; COPY_dspec (id_storage (pid), ds); } return (pid); } /* * CREATE A THIS EXPRESSION * * This routine deals with the 'this' expression. This is only in scope * in the definition of a non-static member function. Note that the * current value of 'this' is given by the address of the dummy parameter * with name given by lex_this_Hname. */ EXP make_this_exp(void) { EXP e; TYPE t; IDENTIFIER fn = crt_func_id; if (in_function_defn && IS_id_mem_func (fn)) { /* The current value of 'this' is returned */ IDENTIFIER pid = this_param (fn, 1); if (in_default_arg) { /* Can't use 'this' in default argument */ ERROR err = ERR_dcl_fct_default_param (pid); report (crt_loc, err); } e = DEREF_exp (id_parameter_init (pid)); t = DEREF_type (exp_type (e)); MAKE_exp_copy (t, e, e); } else { /* Must be inside a non-static member function */ report (crt_loc, ERR_expr_prim_this ()); e = make_error_exp (0); } return (e); } /* * CREATE A THIS EXPRESSION * * This routine creates an expression corresponding to the 'this' parameter * of a member function. The parent class namespace is assigned to pns. * The null expression is returned if we are outside of a member function. */ EXP make_this_ref(NAMESPACE *pns) { IDENTIFIER fn = crt_func_id; if (in_function_defn && IS_id_mem_func (fn)) { EXP e; IDENTIFIER pid = this_param (fn, 1); TYPE t = DEREF_type (id_parameter_type (pid)); MAKE_exp_identifier (t, pid, qual_none, e); *pns = DEREF_nspace (id_parent (fn)); return (e); } return (NULL_exp); } /* * DECLARE A THIS PARAMETER * * This routine declares the dummy extra parameter for the non-static * member function given by the identifier fn. The type of this parameter * is the first element of the corresponding mtypes list (see * member_func_type). An expression giving the address of the parameter * is stored in its default argument position. This gives the value of * the 'this' expression. */ EXP make_this_decl(IDENTIFIER fn) { /* Look up identifier */ EXP e; TYPE t; IDENTIFIER pid; LIST (TYPE) mtypes; NAMESPACE ns = crt_namespace; HASHID nm = KEYWORD (lex_this_Hname); MEMBER mem = search_member (ns, nm, 1); IDENTIFIER qid = DEREF_id (member_id (mem)); DECL_SPEC ds = (dspec_auto | dspec_defn | dspec_implicit); /* Construct the type of the parameter */ TYPE f = DEREF_type (id_mem_func_type (fn)); while (IS_type_templ (f)) { f = DEREF_type (type_templ_defn (f)); } mtypes = DEREF_list (type_func_mtypes (f)); t = DEREF_type (HEAD_list (mtypes)); /* Declare parameter */ MAKE_id_parameter (nm, ds, ns, crt_loc, t, pid); if (!IS_NULL_id (qid)) { qid = DEREF_id (id_alias (qid)); COPY_id (id_alias (pid), qid); } COPY_id (hashid_cache (nm), pid); COPY_id (member_id (mem), pid); /* Construct the 'this' expression */ t = DEREF_type (type_ref_sub (t)); t = rvalue_type (t); if (option (OPT_this_lvalue) == OPTION_ALLOW) { MAKE_type_ptr (cv_lvalue, t, t); MAKE_exp_identifier (t, pid, qual_none, e); } else { MAKE_type_ptr (cv_none, t, t); MAKE_exp_identifier (t, pid, qual_none, e); MAKE_exp_contents (t, e, e); } COPY_exp (id_parameter_init (pid), e); return (e); } /* * CHECK FOR THIS EXPRESSIONS * * This routine checks whether the expression e is a 'this' expression. */ int is_this_exp(EXP e) { if (!IS_NULL_exp (e)) { unsigned tag = TAG_exp (e); if (tag == exp_indir_tag) { e = DEREF_exp (exp_indir_ptr (e)); tag = TAG_exp (e); } if (tag == exp_copy_tag) { e = DEREF_exp (exp_copy_arg (e)); tag = TAG_exp (e); } if (tag == exp_contents_tag) { e = DEREF_exp (exp_contents_ptr (e)); tag = TAG_exp (e); } if (tag == exp_copy_tag) { e = DEREF_exp (exp_copy_arg (e)); tag = TAG_exp (e); } if (tag == exp_identifier_tag) { IDENTIFIER id = DEREF_id (exp_identifier_id (e)); HASHID nm = DEREF_hashid (id_name (id)); if (EQ_KEYWORD (nm, lex_this_Hname)) return (1); } } return (0); } /* * FIND THE ELLIPSIS PARAMETER OF A FUNCTION * * This routine returns the ellipsis parameter of the function fn. */ IDENTIFIER ellipsis_param(IDENTIFIER fn) { int ell; TYPE t = DEREF_type (id_function_etc_type (fn)); while (IS_type_templ (t)) { t = DEREF_type (type_templ_defn (t)); } ell = DEREF_int (type_func_ellipsis (t)); if (ell & FUNC_ELLIPSIS) { HASHID nm = KEYWORD (lex_ellipsis_Hexp); NAMESPACE ns = DEREF_nspace (type_func_pars (t)); IDENTIFIER pid = search_id (ns, nm, 0, 0); return (pid); } return (NULL_id); } /* * FIND ELLIPSIS TYPE * * This routine returns the type of the dummy ellipsis parameter. If * force is true then an error is reported if this type has not been * declared. */ static TYPE find_ellipsis_type(int force) { TYPE t = type_ellipsis; if (IS_NULL_type (t)) { /* Look up token if not already defined */ IDENTIFIER tid = get_special (TOK_va_t, 1); if (!IS_NULL_id (tid) && IS_id_token (tid)) { tid = DEREF_id (id_token_alt (tid)); if (IS_id_class_name_etc (tid)) { t = DEREF_type (id_class_name_etc_defn (tid)); type_ellipsis = t; } } if (IS_NULL_type (t)) { if (force) { /* Report if ellipsis type is undefined */ HASHID nm = KEYWORD (lex_ellipsis_Hexp); report (crt_loc, ERR_lib_builtin (NULL_string, nm)); } t = type_error; } } return (t); } /* * DECLARE AN ELLIPSIS PARAMETER * * This routine declares the dummy extra parameter representing the * ellipsis component of the function id. */ void make_ellipsis_decl(void) { IDENTIFIER pid; NAMESPACE ns = crt_namespace; TYPE t = find_ellipsis_type (0); HASHID nm = KEYWORD (lex_ellipsis_Hexp); MEMBER mem = search_member (ns, nm, 1); IDENTIFIER qid = DEREF_id (member_id (mem)); DECL_SPEC ds = (dspec_auto | dspec_defn | dspec_implicit); MAKE_id_parameter (nm, ds, ns, crt_loc, t, pid); if (!IS_NULL_id (qid)) { qid = DEREF_id (id_alias (qid)); COPY_id (id_alias (pid), qid); } COPY_id (hashid_cache (nm), pid); COPY_id (member_id (mem), pid); return; } /* * CREATE AN ELLIPSIS EXPRESSION * * This routine creates an expression corresponding to the ellipsis * expression '...'. This can only be used in a function definition * which has an ellipsis type, in which case it is an rvalue of type * type_ellipsis. */ EXP make_ellipsis_exp(void) { EXP e; if (in_function_defn) { IDENTIFIER pid = ellipsis_param (crt_func_id); if (!IS_NULL_id (pid)) { /* Form result */ TYPE t = find_ellipsis_type (1); report (crt_loc, ERR_expr_call_ell_exp ()); MAKE_exp_identifier (t, pid, qual_none, e); return (e); } } report (crt_loc, ERR_expr_call_ell_func ()); e = make_error_exp (0); return (e); }