/*
* Copyright (c) 2002, 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/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);
}
syntax highlighted by Code2HTML, v. 0.9.1