/*
* 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/class.c,v 1.8 2004/10/17 21:38:55 stefanf Exp $
*/
#include "config.h"
#include "producer.h"
#include "c_types.h"
#include "ctype_ops.h"
#include "etype_ops.h"
#include "exp_ops.h"
#include "graph_ops.h"
#include "hashid_ops.h"
#include "id_ops.h"
#include "inst_ops.h"
#include "nat_ops.h"
#include "member_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 "access.h"
#include "allocate.h"
#include "basetype.h"
#include "cast.h"
#include "chktype.h"
#include "construct.h"
#include "constant.h"
#include "convert.h"
#include "copy.h"
#include "class.h"
#include "declare.h"
#include "derive.h"
#include "dump.h"
#include "file.h"
#include "function.h"
#include "hash.h"
#include "identifier.h"
#include "initialise.h"
#include "instance.h"
#include "namespace.h"
#include "operator.h"
#include "parse.h"
#include "predict.h"
#include "redeclare.h"
#include "rewrite.h"
#include "statement.h"
#include "syntax.h"
#include "template.h"
#include "tokdef.h"
#include "token.h"
#include "virtual.h"
/*
* SET A CLASS KEY
*
* This routine adjusts the class information ci to be that representing
* the given class key.
*/
static CLASS_INFO
set_class_key(CLASS_INFO ci, BASE_TYPE key)
{
ci &= ~cinfo_key;
if (key == btype_union) {
ci |= cinfo_union;
} else if (key == btype_struct) {
ci |= cinfo_struct;
}
return (ci);
}
/*
* IS A NAMESPACE CONTAINED IN A BLOCK?
*
* This routine checks whether the namespace ns is enclosed within a
* block namespace.
*/
int
is_local_nspace(NAMESPACE ns)
{
while (!IS_NULL_nspace (ns)) {
IDENTIFIER id;
switch (TAG_nspace (ns)) {
case nspace_block_tag :
case nspace_dummy_tag : {
return (1);
}
case nspace_param_tag :
case nspace_templ_tag : {
return (2);
}
}
id = DEREF_id (nspace_name (ns));
if (IS_NULL_id (id)) break;
ns = DEREF_nspace (id_parent (id));
}
return (0);
}
/*
* CREATE A CLASS OR ENUMERATION TYPE
*
* This routine creates a class or enumeration type (indicated by key)
* with type name nm and template qualifiers q in the namespace ns.
*/
IDENTIFIER
make_class(NAMESPACE ns, HASHID nm, BASE_TYPE key, DECL_SPEC bds, TYPE q,
TYPE prev)
{
TYPE t;
IDENTIFIER id;
ENUM_TYPE et = NULL_etype;
CLASS_TYPE ct = NULL_ctype;
CLASS_INFO ci = cinfo_default;
DECL_SPEC ds = (bds | dspec_lang);
if (option (OPT_complete_struct) && crt_file_type == 0) {
/* Allow incomplete types in start-up files */
ci |= cinfo_incomplete;
}
/* Check on class linkage and access */
if (!IS_NULL_nspace (ns)) {
if (IS_nspace_ctype (ns)) {
/* Only nested classes (not friend classes) have access */
if (!(ds & dspec_access)) ds |= crt_access;
}
if (!really_in_function_defn || !is_local_nspace (ns)) {
ds |= dspec_extern;
}
}
if (key == btype_enum) {
/* Create the enumeration type */
MAKE_id_enum_name (nm, ds, ns, decl_loc, NULL_type, id);
COPY_btype (id_enum_name_rep (id), key);
MAKE_etype_basic (id, ci, type_sint, et);
MAKE_type_enumerate (cv_none, et, t);
if (!IS_NULL_type (q)) {
report (decl_loc, ERR_temp_decl_bad ());
}
COPY_type (id_enum_name_defn (id), t);
} else {
TYPE s;
GRAPH gr;
MEMBER mem;
NAMESPACE mns;
DECL_SPEC acc;
IDENTIFIER cid;
/* Allow for template classes */
if (!IS_NULL_type (q)) {
ds |= dspec_template;
ci |= cinfo_template;
}
/* Create the class member namespace */
MAKE_id_class_name (nm, ds, ns, decl_loc, NULL_type, id);
COPY_btype (id_class_name_rep (id), key);
mns = make_namespace (id, nspace_ctype_tag, 20);
/* Construct the base class graph */
acc = (dspec_public | dspec_defn | dspec_done);
MAKE_graph_basic (NULL_ctype, acc, gr);
COPY_graph (graph_top (gr), gr);
/* Construct the class */
ci = set_class_key (ci, key);
MAKE_ctype_basic (id, ci, cusage_none, mns, gr, 1, prev, ct);
COPY_ctype (graph_head (gr), ct);
/* Construct the class type */
MAKE_type_compound (cv_none, ct, t);
COPY_type (id_class_name_defn (id), t);
s = t;
if (!IS_NULL_type (q)) {
/* Allow for template qualifiers */
t = inject_pre_type (q, t, 0);
COPY_type (id_class_name_defn (id), t);
IGNORE check_templ_params (t, id);
}
/* Construct the constructor and destructor names */
IGNORE lookup_constr (s, id);
IGNORE lookup_destr (s, id);
/* Inject the class name into the class */
ds &= ~dspec_access;
ds |= (dspec_alias | dspec_implicit | dspec_public);
if (bds & dspec_instance) ds |= dspec_template;
mem = search_member (mns, nm, 1);
MAKE_id_class_name (nm, ds, mns, decl_loc, t, cid);
COPY_btype (id_class_name_rep (cid), key);
COPY_id (id_alias (cid), id);
COPY_id (member_alt (mem), cid);
#if LANGUAGE_CPP
COPY_id (member_id (mem), cid);
#endif
}
/* Deal with nested classes */
if (IS_nspace_ctype (ns)) {
CLASS_TYPE cr;
CLASS_INFO cj;
LIST (IDENTIFIER) fr;
IDENTIFIER rid = DEREF_id (nspace_name (ns));
TYPE r = DEREF_type (id_class_name_defn (rid));
while (IS_type_templ (r)) {
r = DEREF_type (type_templ_defn (r));
}
cr = DEREF_ctype (type_compound_defn (r));
cj = DEREF_cinfo (ctype_info (cr));
if (cj & cinfo_template) {
/* Mark nested template classes */
ci |= (cinfo_template | cinfo_rescan);
}
ci |= cinfo_nested;
if (!IS_NULL_ctype (ct)) COPY_cinfo (ctype_info (ct), ci);
if (!IS_NULL_etype (et)) COPY_cinfo (etype_info (et), ci);
fr = DEREF_list (ctype_nest (cr));
CONS_id (id, fr, fr);
COPY_list (ctype_nest (cr), fr);
}
return (id);
}
/*
* CHECK A CONSTRUCTOR NAME
*
* This routine is called for a declarator id which represents a type
* name in the namespace ns. It checks whether id is actually a
* constructor name, and if so returns the correct identifier.
*/
IDENTIFIER
constr_name(NAMESPACE ns, IDENTIFIER id)
{
unsigned tag = TAG_id (id);
if (tag == id_class_name_tag || tag == id_class_alias_tag) {
CLASS_TYPE ct;
NAMESPACE cns;
TYPE t = DEREF_type (id_class_name_etc_defn (id));
while (IS_type_templ (t)) {
t = DEREF_type (type_templ_defn (t));
}
ct = DEREF_ctype (type_compound_defn (t));
cns = DEREF_nspace (ctype_member (ct));
if (IS_NULL_nspace (ns)) ns = crt_namespace;
if (EQ_nspace (ns, cns)) {
/* This is a constructor */
IDENTIFIER cid = DEREF_id (ctype_constr (ct));
if (tag == id_class_alias_tag && is_constructor_next) {
/* Can't use type alias */
HASHID cnm = DEREF_hashid (id_name (cid));
IDENTIFIER tid = DEREF_id (hashid_constr_tid (cnm));
if (!EQ_id (tid, id)) {
report (crt_loc, ERR_dcl_typedef_constr (id, cnm));
}
}
set_hashid_loc (cid, id);
id = cid;
}
}
is_constructor_next = 0;
return (id);
}
/*
* HAS A TYPE BEEN DEFINED?
*
* This routine checks whether the type associated with the identifier id
* has been defined or just declared. A value of 2 is returned for
* tokenised types. The value associated with a defined type is returned
* via pt. If force is true then any template classes are completed.
*/
int
is_defined(IDENTIFIER id, TYPE *pt, int force)
{
if (IS_id_class_name_etc (id)) {
CLASS_INFO ci;
TYPE t = DEREF_type (id_class_name_etc_defn (id));
unsigned tag = TAG_type (t);
*pt = t;
while (tag == type_templ_tag) {
t = DEREF_type (type_templ_defn (t));
tag = TAG_type (t);
}
if (tag == type_compound_tag) {
/* Class type */
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
if (force) complete_class (ct, 0);
ci = DEREF_cinfo (ctype_info (ct));
} else if (tag == type_enumerate_tag) {
/* Enumeration type */
ENUM_TYPE et = DEREF_etype (type_enumerate_defn (t));
ci = DEREF_cinfo (etype_info (et));
} else {
return (1);
}
if (ci & cinfo_token) {
/* Tokenised types */
IDENTIFIER tid = find_token (id);
DECL_SPEC ds = DEREF_dspec (id_storage (tid));
if (ds & dspec_pure) return (1);
return (2);
}
if (ci & (cinfo_complete | cinfo_defined)) {
/* Defined types */
return (1);
}
}
return (0);
}
/*
* FIND THE KEY ASSOCIATED WITH A CLASS
*
* This routine returns the class key associated with the class type ct.
*/
BASE_TYPE
find_class_key(CLASS_TYPE ct)
{
CLASS_INFO ci = DEREF_cinfo (ctype_info (ct));
if (ci & cinfo_union) return (btype_union);
if (ci & cinfo_struct) return (btype_struct);
return (btype_class);
}
/*
* FIND THE KEY ASSOCIATED WITH A TYPE
*
* This routine returns the class key associated with the identifier id.
* Note that typedef names are only expanded to their definitions if
* expand is true. If id is a template type parameter which has not
* previously been qualified then its key is set to new_key.
*/
static BASE_TYPE
find_key(IDENTIFIER id, int expand, BASE_TYPE new_key)
{
switch (TAG_id (id)) {
case id_class_name_tag :
class_name_lab : {
/* Class names */
CLASS_TYPE ct;
BASE_TYPE key;
TYPE t = DEREF_type (id_class_name_etc_defn (id));
while (IS_type_templ (t)) {
t = DEREF_type (type_templ_defn (t));
}
ct = DEREF_ctype (type_compound_defn (t));
key = find_class_key (ct);
return (key);
}
case id_enum_name_tag : {
/* Enumeration names */
return (btype_enum);
}
case id_class_alias_tag : {
/* Class aliases */
if (expand) goto class_name_lab;
return (btype_alias);
}
case id_enum_alias_tag : {
/* Enumeration aliases */
if (expand) return (btype_enum);
return (btype_alias);
}
case id_type_alias_tag : {
/* Type aliases */
DECL_SPEC ds = DEREF_dspec (id_storage (id));
if (ds & dspec_token) {
/* Check tokenised types */
TYPE t = DEREF_type (id_type_alias_defn (id));
if (IS_type_token (t)) {
id = DEREF_id (type_token_tok (t));
return (find_key (id, expand, new_key));
}
}
return (btype_alias);
}
case id_token_tag : {
/* Tokenised types */
TOKEN tok = DEREF_tok (id_token_sort (id));
if (IS_tok_type (tok)) {
BASE_TYPE bt = DEREF_btype (tok_type_kind (tok));
if (bt & btype_template) {
/* Template parameter */
BASE_TYPE key = (bt & btype_named);
if (key == btype_none) {
key = new_key;
bt |= key;
COPY_btype (tok_type_kind (tok), bt);
}
return (key);
}
return (btype_alias);
}
break;
}
}
return (btype_none);
}
/*
* CHECK THAT TWO CLASS KEYS ARE CONSISTENT
*
* This routine checks whether the class keys key1 and key2 are consistent.
* Basically they are consistent if they are equal, but also 'class' is
* consistent with 'struct'.
*/
int
equal_key(BASE_TYPE key1, BASE_TYPE key2)
{
if (key1 == key2) return (1);
if (key1 == btype_class && key2 == btype_struct) return (1);
if (key1 == btype_struct && key2 == btype_class) return (1);
if (key1 == btype_any || key2 == btype_any) return (1);
return (0);
}
/*
* CHECK A CLASS KEY
*
* This routine checks the given class key for the type id. It returns
* true if either the new or the existing class key is 'enum'.
*/
static int
check_key(IDENTIFIER id, BASE_TYPE key)
{
int is_enum = 0;
BASE_TYPE prev = find_key (id, 1, key);
if (!equal_key (prev, key)) {
PTR (LOCATION) loc = id_loc (id);
ERROR err = ERR_dcl_type_elab_bad (key, prev, id, loc);
report (crt_loc, err);
if (prev == btype_enum) is_enum = 1;
if (key == btype_enum) is_enum = 1;
}
return (is_enum);
}
/*
* CREATE A DUMMY CLASS TYPE
*
* This routine creates a dummy class or union type (as indicated by key)
* representing the type 'id < args >' where id depends on a template
* parameter.
*/
TYPE
make_dummy_class(IDENTIFIER id, LIST (TOKEN) args, BASE_TYPE key)
{
TYPE t, s;
CLASS_TYPE ct;
CLASS_INFO ci;
IDENTIFIER tid;
HASHID nm = DEREF_hashid (id_name (id));
NAMESPACE ns = DEREF_nspace (id_parent (id));
decl_loc = crt_loc;
tid = make_class (ns, nm, key, dspec_public, NULL_type, NULL_type);
t = DEREF_type (id_class_name_defn (tid));
ct = DEREF_ctype (type_compound_defn (t));
ci = DEREF_cinfo (ctype_info (ct));
ci |= (cinfo_defined | cinfo_complete);
COPY_cinfo (ctype_info (ct), ci);
MAKE_type_token (cv_none, id, args, s);
COPY_type (ctype_form (ct), s);
return (t);
}
/*
* FIND THE CLASS ASSOCIATED WITH AN IDENTIFIER
*
* This routine returns the class type associated with the identifier id.
* The null class type is returned if id is not a class name.
*/
CLASS_TYPE
find_class(IDENTIFIER id)
{
unsigned tag = TAG_id (id);
if (tag == id_class_name_tag || tag == id_class_alias_tag) {
/* Simple class names */
TYPE t = DEREF_type (id_class_name_etc_defn (id));
if (IS_type_compound (t)) {
/* Simple classes */
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
return (ct);
} else {
/* Template classes */
while (IS_type_templ (t)) {
t = DEREF_type (type_templ_defn (t));
}
if (IS_type_compound (t)) {
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
if (defining_class (ct)) {
/* Only allow unqualified in definition */
return (ct);
}
}
}
} else if (tag == id_type_alias_tag) {
/* Check tokenised types */
TYPE t = DEREF_type (id_type_alias_defn (id));
while (IS_type_templ (t)) {
t = DEREF_type (type_templ_defn (t));
}
if (IS_type_token (t)) {
id = DEREF_id (type_token_tok (t));
return (find_class (id));
}
} else if (tag == id_token_tag && is_templ_param (id)) {
/* Check for template parameters */
int simple = 0;
BASE_TYPE key = btype_lang;
TOKEN sort = DEREF_tok (id_token_sort (id));
if (IS_tok_type (sort)) {
key = DEREF_btype (tok_type_kind (sort));
key &= btype_named;
simple = 1;
}
if (key != btype_enum) {
TYPE t;
if (simple) {
t = DEREF_type (tok_type_alt (sort));
} else {
t = DEREF_type (tok_class_alt (sort));
}
if (IS_NULL_type (t)) {
/* Create dummy class type */
if (key == btype_none) key = btype_lang;
t = make_dummy_class (id, NULL_list (TOKEN), key);
if (simple) {
COPY_type (tok_type_alt (sort), t);
} else {
COPY_type (tok_class_alt (sort), t);
}
}
if (IS_type_compound (t)) {
/* Return previous dummy class type */
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
return (ct);
}
}
}
return (NULL_ctype);
}
/*
* FIND A CLASS TYPE
*
* This routine returns the compound type associated with the class ct.
*/
TYPE
make_class_type(CLASS_TYPE ct)
{
IDENTIFIER cid = DEREF_id (ctype_name (ct));
TYPE t = DEREF_type (id_class_name_etc_defn (cid));
while (IS_type_templ (t)) {
t = DEREF_type (type_templ_defn (t));
}
return (t);
}
/*
* REDECLARE A TEMPLATE CLASS
*
* This routine redeclares the template class t using the template type
* qualifiers q.
*/
static TYPE
redecl_templ_class(TYPE q, TYPE t, IDENTIFIER *pid)
{
TYPE s = t;
IDENTIFIER id;
while (IS_type_templ (s)) {
s = DEREF_type (type_templ_defn (s));
}
s = inject_pre_type (q, s, 0);
s = bind_specialise (pid, s, dspec_none, 1, 0, 0);
id = *pid;
if (eq_type (s, t) == 1) {
/* Consistent redeclaration */
TYPE ps = s;
TYPE pt = t;
redecl_template (&pt, &ps, id);
} else {
/* Inconsistent redeclaration */
ERROR err = ERR_basic_link_incompat (s, t);
ERROR err2 = ERR_basic_link_decl_type (id, id_loc (id));
err = concat_error (err, err2);
report (crt_loc, err);
}
return (s);
}
/*
* EXTRACT THE TEMPLATE QUALIFIERS OF A TYPE
*
* This routine does the opposite of inject_pre_type by extracting the
* template qualifiers from the type t.
*/
static TYPE
extract_templ_qual(TYPE t)
{
if (!IS_NULL_type (t) && IS_type_templ (t)) {
TYPE s = DEREF_type (type_templ_defn (t));
s = extract_templ_qual (s);
COPY_type (type_templ_defn (t), s);
return (t);
}
return (NULL_type);
}
/*
* DECLARE A CLASS OR ENUMERATION NAME
*
* This routine declares a class or enumeration type with name nm,
* class key key (which can be btype_class, btype_struct, btype_union
* or btype_enum) and template specifiers q. The argument def is 1 if
* the type is about to be defined or 2 if it is about to be defined
* as a token. Note that it is possible for a class or enumeration
* to have the same name as an object in the same scope. In this case
* the type name is hidden by the object name.
*/
static IDENTIFIER
declare_type(NAMESPACE ns, HASHID nm, BASE_TYPE key, TYPE q, int def, int force)
{
TYPE t = NULL_type;
MEMBER mem = search_member (ns, nm, 1);
IDENTIFIER pid = DEREF_id (member_id (mem));
IDENTIFIER id = type_member (mem, 3);
if (!IS_NULL_id (id)) {
/* Check for reserved identifiers */
IDENTIFIER qid = id;
DECL_SPEC ds = DEREF_dspec (id_storage (id));
if (ds & dspec_reserve) {
PTR (LOCATION) loc = id_loc (id);
report (crt_loc, ERR_basic_odr_def_type (id, loc));
id = NULL_id;
} else {
id = redecl_inherit (id, crt_id_qualifier, in_class_defn, 0);
}
/* Check previous type declaration */
if (!IS_NULL_id (id)) {
switch (TAG_id (id)) {
case id_class_name_tag :
case id_enum_name_tag : {
/* Previously declared as class name */
int hide_prev = check_key (id, key);
int prev_def = is_defined (id, &t, 1);
if (!IS_NULL_type (q) || IS_type_templ (t)) {
/* Redeclaration of template type */
q = redecl_templ_class (q, t, &id);
}
if (def && prev_def) {
/* Multiple definitions */
if (def == 2) {
/* This is a token */
/* EMPTY */
} else if (prev_def == 2) {
/* Previous was a token */
/* EMPTY */
} else {
/* Neither is a token */
PTR (LOCATION) loc = id_loc (id);
ERROR err = ERR_basic_odr_def_type (id, loc);
report (crt_loc, err);
q = extract_templ_qual (q);
t = NULL_type;
}
break;
}
if (hide_prev) {
/* Hide previous if only one is an enumeration */
break;
}
/* This is a genuine type redeclaration */
found_elaborate_type = 1;
if (in_class_defn) {
/* Adjust access specifiers */
adjust_access (id, crt_access, 0);
}
if (def) {
/* Record location of definition */
if (!IS_NULL_type (q)) {
/* Update template class */
COPY_type (id_class_name_etc_defn (id), q);
reset_primary_templ (t, q);
}
COPY_loc (id_loc (id), decl_loc);
}
return (id);
}
case id_class_alias_tag :
case id_enum_alias_tag :
case id_type_alias_tag : {
/* Previously declared as typedef name */
PTR (LOCATION) loc = id_loc (id);
report (crt_loc, ERR_basic_odr_def_type (id, loc));
break;
}
case id_nspace_name_tag :
case id_nspace_alias_tag : {
/* Previously declared as namespace name */
PTR (LOCATION) loc = id_loc (id);
report (crt_loc, ERR_basic_odr_decl (id, loc));
break;
}
}
/* Clobber previous definition */
if (EQ_id (pid, qid)) {
COPY_id (member_id (mem), NULL_id);
pid = NULL_id;
}
COPY_id (member_alt (mem), NULL_id);
}
}
/* Check for template declarations */
if (!IS_NULL_type (q)) {
if (!IS_NULL_id (pid)) {
/* Already declared as object */
PTR (LOCATION) loc = id_loc (pid);
report (crt_loc, ERR_basic_odr_diff (pid, loc));
}
if (crt_linkage == dspec_c) {
report (crt_loc, ERR_temp_decl_linkage ());
}
}
/* Construct the type declaration */
if (force) {
id = make_class (ns, nm, key, dspec_none, q, t);
set_type_member (mem, id);
if (IS_nspace_param (ns)) {
/* Warn about function parameter scope */
report (crt_loc, ERR_basic_scope_pdecl_param (id));
}
}
found_elaborate_type = 0;
return (id);
}
/*
* FIND THE TYPE OF A CLASS MEMBER
*
* This routine returns the class type corresponding to the member
* identifier id. The null type is returned for non-members.
*/
CLASS_TYPE
parent_class(IDENTIFIER id)
{
if (!IS_NULL_id (id)) {
NAMESPACE ns = DEREF_nspace (id_parent (id));
if (!IS_NULL_nspace (ns) && IS_nspace_ctype (ns)) {
IDENTIFIER cid = DEREF_id (nspace_name (ns));
TYPE t = DEREF_type (id_class_name_etc_defn (cid));
while (IS_type_templ (t)) {
t = DEREF_type (type_templ_defn (t));
}
if (IS_type_compound (t)) {
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
return (ct);
}
}
}
return (NULL_ctype);
}
/*
* FIND THE TYPE CORRESPONDING TO A NAMESPACE
*
* This routine returns the class type corresponding to the namespace
* ns. The null type is returned if ns is not a class member namespace.
*/
CLASS_TYPE
namespace_class(NAMESPACE ns)
{
if (IS_nspace_ctype (ns)) {
CLASS_TYPE ct;
IDENTIFIER cid = DEREF_id (nspace_name (ns));
TYPE t = DEREF_type (id_class_name_etc_defn (cid));
while (IS_type_templ (t)) {
t = DEREF_type (type_templ_defn (t));
}
ct = DEREF_ctype (type_compound_defn (t));
return (ct);
}
return (NULL_ctype);
}
/*
* CLASS STACK
*
* The variable crt_class holds the class currently being defined. The
* stack class_stack allows for nested class definitions.
*/
CLASS_TYPE crt_class = NULL_ctype;
static STACK (CLASS_TYPE) class_stack = NULL_stack (CLASS_TYPE);
/*
* PUSH A CLASS ONTO THE CLASS STACK
*
* This routine sets the current class to ct pushing the previous class
* to the class stack.
*/
void
push_class(CLASS_TYPE ct)
{
PUSH_ctype (crt_class, class_stack);
crt_class = ct;
return;
}
/*
* POP A CLASS FROM THE CLASS STACK
*
* This routine sets the current class from the top of the class stack.
*/
void
pop_class(void)
{
POP_ctype (crt_class, class_stack);
return;
}
/*
* IS A CLASS BEING DEFINED?
*
* This routine checks whether the class ct is in the process of being
* defined by checking it against the current class and the various
* elements of the class stack.
*/
int
defining_class(CLASS_TYPE ct)
{
NAMESPACE nt;
LIST (NAMESPACE) q;
LIST (CLASS_TYPE) p;
if (EQ_ctype (ct, crt_class)) return (1);
p = LIST_stack (class_stack);
while (!IS_NULL_list (p)) {
CLASS_TYPE cs = DEREF_ctype (HEAD_list (p));
if (EQ_ctype (cs, ct)) return (1);
p = TAIL_list (p);
}
nt = DEREF_nspace (ctype_member (ct));
q = LIST_stack (namespace_stack);
while (!IS_NULL_list (q)) {
NAMESPACE ns = DEREF_nspace (HEAD_list (q));
if (EQ_nspace (ns, nt)) return (1);
q = TAIL_list (q);
}
return (0);
}
/*
* BEGIN A CLASS DEFINITION
*
* This routine begins the definition of a class type (this includes
* structures and unions). The class name is given by id and key is one
* of the values btype_class, btype_struct or btype_union indicating the
* class key. ci gives any initial class information and q gives any
* template class qualifiers.
*/
IDENTIFIER
begin_class_defn(IDENTIFIER id, BASE_TYPE key, CLASS_INFO ci, TYPE q)
{
TYPE t;
DECL_SPEC ds;
CLASS_TYPE ct;
CLASS_INFO cj;
int nested = 0;
IDENTIFIER cid = NULL_id;
QUALIFIER cq = crt_id_qualifier;
HASHID nm = DEREF_hashid (id_name (id));
NAMESPACE ns = crt_namespace;
begin_declarator (id, cq, qual_namespace, 1);
IGNORE incr_value (OPT_VAL_nested_class);
/* Check for template specialisations */
if (is_templ_decl (id, NULL_type) || is_templ_spec (q)) {
q = bind_specialise (&id, q, dspec_none, 1, 1, 1);
if (IS_NULL_id (id) || check_key (id, key)) {
nm = lookup_anon ();
id = DEREF_id (hashid_id (nm));
cq = qual_none;
} else {
cid = id;
ns = DEREF_nspace (id_parent (cid));
check_decl_nspace (cid, ns, 1, crt_namespace);
if (is_defined (cid, &t, 0)) {
/* Redefinition of template class */
PTR (LOCATION) loc = id_loc (cid);
ERROR err = ERR_basic_odr_def_type (cid, loc);
report (crt_loc, err);
}
}
}
/* Check for qualified identifiers */
if (IS_NULL_id (cid)) {
/* Check on class name */
int def = 1;
ERROR err = check_id_name (id, CONTEXT_CLASS);
if (!IS_NULL_err (err)) report (crt_loc, err);
if (IS_nspace_ctype (ns)) nested = 1;
if (cq == qual_none) {
/* Simple class name */
if (option (OPT_class_scope)) {
ns = crt_namespace;
if (IS_nspace_param (ns)) {
ns = nonclass_namespace;
if (nested) nested = 2;
}
} else {
ns = nonclass_namespace;
if (nested) nested = 2;
}
} else {
/* Definition of nested class */
ns = DEREF_nspace (id_parent (id));
check_decl_nspace (id, ns, 1, crt_namespace);
if (IS_id_undef (id)) nm = lookup_anon ();
if (nested) nested = 2;
}
/* Declare the type */
if (ci & cinfo_token) def = 2;
cid = declare_type (ns, nm, key, q, def, 1);
}
/* Find the class type */
t = DEREF_type (id_class_name_defn (cid));
while (IS_type_templ (t)) {
t = DEREF_type (type_templ_defn (t));
}
ct = DEREF_ctype (type_compound_defn (t));
ns = DEREF_nspace (ctype_member (ct));
/* Mark start of definition */
cj = DEREF_cinfo (ctype_info (ct));
cj = set_class_key (cj, key);
cj |= (ci | cinfo_defined);
if (nested == 1) cj |= cinfo_nested;
cj &= ~cinfo_complete;
COPY_cinfo (ctype_info (ct), cj);
/* Mark tokenised types */
ds = DEREF_dspec (id_storage (cid));
if (cj & cinfo_token) ds |= dspec_token;
COPY_dspec (id_storage (cid), (ds | dspec_defn));
#if LANGUAGE_CPP
/* Make sure that nested classes are nested */
if (nested == 2) {
NAMESPACE pns = crt_namespace;
HASHID pnm = lookup_anon ();
IDENTIFIER pid = declare_type (pns, pnm, key, q, 1, 1);
ds = DEREF_dspec (id_storage (pid));
COPY_dspec (id_storage (pid), (ds | dspec_defn));
t = DEREF_type (id_class_name_defn (cid));
COPY_type (id_class_name_defn (pid), t);
}
#endif
/* Force definition information */
COPY_loc (id_loc (cid), decl_loc);
if (do_dump) dump_declare (cid, &decl_loc, 1);
/* Push current class and namespace */
push_namespace (ns);
push_class (ct);
/* Set up default access specifier */
ds = (key == btype_class ? dspec_private : dspec_public);
crt_access = ds;
prev_access = ds;
return (cid);
}
/*
* END A CLASS DEFINITION
*
* This routine completes the definition of the class type id.
*/
IDENTIFIER
end_class_defn(IDENTIFIER id)
{
TYPE p;
CLASS_TYPE ct;
CLASS_INFO ci;
LIST (IDENTIFIER) ft;
HASHID nm = DEREF_hashid (id_name (id));
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));
/* Deal with implicitly declared constructors */
ci = DEREF_cinfo (ctype_info (ct));
if (ci & cinfo_empty) report (crt_loc, ERR_class_none ());
#if LANGUAGE_CPP
ci = implicit_decl (ct, ci, dspec_none);
#endif
if (ci & cinfo_non_aggregate) {
/* POD classes must be aggregate classes */
ci &= ~cinfo_pod;
}
ci |= cinfo_complete;
COPY_cinfo (ctype_info (ct), ci);
/* Deal with any inheritance issues */
inherit_class ();
/* Check for previous definitions */
p = DEREF_type (ctype_prev (ct));
if (!IS_NULL_type (p)) {
if (ci & cinfo_token) {
/* Make p the tokenised type */
TYPE q = p;
p = t;
t = q;
}
force_tokdef++;
IGNORE unify_type (p, t, cv_none, 0);
force_tokdef--;
}
/* Compile any inline functions */
if (is_exported (id)) export_template (id, 1);
ft = DEREF_list (ctype_pals (ct));
if (!IS_NULL_list (ft)) {
unsigned nf;
ft = REVERSE_list (ft);
COPY_list (ctype_pals (ct), ft);
nf = LENGTH_list (ft);
IGNORE check_value (OPT_VAL_friends, (ulong) nf);
}
ft = DEREF_list (ctype_nest (ct));
if (!IS_NULL_list (ft)) {
ft = REVERSE_list (ft);
COPY_list (ctype_nest (ct), ft);
if (!(ci & cinfo_nested) || in_class_defn == 1) {
rescan_functions ();
}
}
/* Pop current class and namespace */
if (do_dump) dump_undefine (id, &crt_loc, 0);
IGNORE pop_namespace ();
pop_class ();
decr_value (OPT_VAL_nested_class);
end_declarator (id, 1);
/* Set type declaration flag */
if (IS_hashid_anon (nm)) {
have_type_declaration = TYPE_DECL_ANON;
} else {
have_type_declaration = TYPE_DECL_NORMAL;
}
return (id);
}
/*
* CHECK CLASS INFORMATION
*
* This routine checks the effect of a non-static data member or base
* class (as indicated by base) with class information cj on a class
* with class information ci. In a class definition trivial_constr,
* for example, is true if all the base classes and members have
* trivial constructors. At the end of the definition, when the
* implicit constructors are declared, it is used to indicate that the
* class itself has a trivial constructor.
*/
CLASS_INFO
check_class_info(CLASS_INFO ci, CLASS_INFO cj, int base, DECL_SPEC acc)
{
if (!(cj & cinfo_pod)) ci &= ~cinfo_pod;
if (!(cj & cinfo_trivial_constr)) ci &= ~cinfo_trivial_constr;
if (!(cj & cinfo_trivial_copy)) ci &= ~cinfo_trivial_copy;
if (!(cj & cinfo_trivial_assign)) ci &= ~cinfo_trivial_assign;
if (!(cj & cinfo_trivial_destr)) ci &= ~cinfo_trivial_destr;
if (!(cj & cinfo_const_copy)) ci &= ~cinfo_const_copy;
if (!(cj & cinfo_const_assign)) ci &= ~cinfo_const_assign;
if (cj & cinfo_recursive) ci |= cinfo_recursive;
if (cj & cinfo_params) ci |= cinfo_params;
if (cj & cinfo_const) ci |= cinfo_const;
if (base) {
/* Base class checks */
if (cj & cinfo_multiple_base) ci |= cinfo_multiple_base;
if (cj & cinfo_templ_base) ci |= cinfo_templ_base;
if (cj & cinfo_function) ci |= cinfo_function;
if (cj & cinfo_static) ci |= cinfo_static;
ci &= ~cinfo_empty;
ci |= cinfo_base;
UNUSED (acc);
}
return (ci);
}
/*
* CHECK FOR TRIVIAL CLASSES
*
* This routine checks whether the class ct has trivial default
* constructors, destructors, copy constructors and copy assignment
* operators.
*/
ERROR
check_trivial_class(CLASS_TYPE ct)
{
ERROR err = NULL_err;
CLASS_INFO ci = DEREF_cinfo (ctype_info (ct));
CLASS_INFO cj = (ci & cinfo_trivial);
if (cj != cinfo_trivial) {
if (!(cj & cinfo_trivial_constr)) {
err = ERR_class_ctor_nontriv (ct);
} else if (!(cj & cinfo_trivial_destr)) {
err = ERR_class_dtor_nontriv (ct);
} else if (!(cj & cinfo_trivial_copy)) {
err = ERR_class_copy_nontriv_constr (ct);
} else if (!(cj & cinfo_trivial_assign)) {
err = ERR_class_copy_nontriv_assign (ct);
}
}
return (err);
}
/*
* CHECK A CLASS MEMBER TYPE
*
* This routine checks the type t of a non-static data member of the
* class ct. This is recorded in the effect on the class information ci.
* The criterion for spotting recursively defined classes is that it
* contains a pointer to an incomplete type (or a base class or member
* of such a type). This certainly contains all recursive types, and
* is about the best that can be done without any deep analysis.
*/
CLASS_INFO
check_member_type(CLASS_TYPE ct, CLASS_INFO ci, TYPE t, int ptr)
{
if (!ptr) {
/* Check for const members */
CV_SPEC cv = DEREF_cv (type_qual (t));
if (cv & cv_const) ci |= cinfo_const;
}
switch (TAG_type (t)) {
case type_compound_tag : {
/* Compound types */
CLASS_TYPE cs = DEREF_ctype (type_compound_defn (t));
CLASS_INFO cj = DEREF_cinfo (ctype_info (cs));
if (!(cj & cinfo_complete)) {
/* Could be a recursive type ... */
ci |= cinfo_recursive;
}
if (!ptr) {
if (ci & cinfo_union) {
/* Union component must be trivial */
ERROR err = check_trivial_class (cs);
if (!IS_NULL_err (err)) {
ERROR err2 = ERR_class_union_mem (ct, t);
err = concat_error (err, err2);
report (crt_loc, err);
}
}
ci = check_class_info (ci, cj, 0, dspec_none);
}
break;
}
case type_ptr_tag : {
/* Pointer types */
if (!ptr) {
TYPE s = DEREF_type (type_ptr_sub (t));
ci = check_member_type (ct, ci, s, 1);
}
break;
}
case type_ref_tag : {
/* Reference types */
if (!ptr) {
TYPE s = DEREF_type (type_ref_sub (t));
if (ci & cinfo_union) {
/* Unions can't have reference members */
report (crt_loc, ERR_class_union_ref (ct, t));
}
ci = check_member_type (ct, ci, s, 1);
ci &= ~cinfo_pod;
}
break;
}
case type_ptr_mem_tag : {
/* Pointer to member types */
if (!ptr) ci &= ~cinfo_pod;
break;
}
case type_array_tag : {
/* Array types */
TYPE s = DEREF_type (type_array_sub (t));
ci = check_member_type (ct, ci, s, ptr);
break;
}
}
if (is_templ_depend (t)) ci |= cinfo_params;
return (ci);
}
/*
* REPORT INFORMATION ABOUT A CLASS
*
* This routine reports the information about the class ct indicated by
* the class information mask cm. It returns an error message summarising
* those properties which hold for ct. At most n properties are reported.
*/
ERROR
class_info(CLASS_TYPE ct, CLASS_INFO cm, int n)
{
/* Find class information */
ERROR err = NULL_err;
CLASS_INFO ci = DEREF_cinfo (ctype_info (ct));
ci &= cm;
if (ci == cinfo_none) return (err);
/* Check for tokenised types */
if (ci & cinfo_token) {
IDENTIFIER id = DEREF_id (ctype_name (ct));
err = concat_error (err, ERR_token_info (id));
if (--n == 0) return (err);
}
/* Check for user-defined constructors */
if (ci & cinfo_usr_constr) {
err = concat_error (err, ERR_class_ctor_user (ct));
if (--n == 0) return (err);
}
/* Check for ambiguous base classes */
if (ci & cinfo_ambiguous) {
GRAPH gr = DEREF_graph (ctype_base (ct));
gr = find_ambig_base (gr);
if (!IS_NULL_graph (gr)) {
/* Ambiguous base class found */
CLASS_TYPE cs = DEREF_ctype (graph_head (gr));
ERROR err2 = ERR_class_member_lookup_ambig (cs, ct);
err = concat_error (err, err2);
if (--n == 0) return (err);
}
}
/* Check for base classes */
if (ci & cinfo_base) {
CLASS_TYPE cs;
GRAPH gr = DEREF_graph (ctype_base (ct));
LIST (GRAPH) tails = DEREF_list (graph_tails (gr));
gr = DEREF_graph (HEAD_list (tails));
cs = DEREF_ctype (graph_head (gr));
err = concat_error (err, ERR_class_derived_base (ct, cs));
if (--n == 0) return (err);
}
/* Check for private or protected members */
if (ci & cinfo_private) {
err = concat_error (err, ERR_class_access_spec_priv (ct));
if (--n == 0) return (err);
}
/* Check for abstract classes */
if (ci & cinfo_abstract) {
IDENTIFIER id = find_pure_function (ct);
err = concat_error (err, ERR_class_abstract_pure (id));
err = concat_error (err, ERR_class_abstract_class (ct));
if (--n == 0) return (err);
}
/* Check for polymorphic classes */
if (ci & cinfo_polymorphic) {
err = concat_error (err, ERR_class_virtual_poly (ct));
if (--n == 0) return (err);
}
/* Return the resultant error */
UNUSED (n);
return (err);
}
/*
* DOES A CLASS TYPE HAVE A NON-TRIVIAL MEMBER?
*
* This routine checks whether the class type ct has a non-trivial member,
* that is to say not all its base classes and members are empty classes.
*/
static int
is_empty_ctype(CLASS_TYPE ct)
{
GRAPH gr = DEREF_graph (ctype_base (ct));
LIST (GRAPH) br = DEREF_list (graph_tails (gr));
NAMESPACE ns = DEREF_nspace (ctype_member (ct));
MEMBER mem = DEREF_member (nspace_ctype_first (ns));
mem = next_data_member (mem, 2);
if (!IS_NULL_member (mem)) return (0);
while (!IS_NULL_list (br)) {
GRAPH gs = DEREF_graph (HEAD_list (br));
CLASS_TYPE cs = DEREF_ctype (graph_head (gs));
if (!is_empty_ctype (cs)) return (0);
br = TAIL_list (br);
}
return (1);
}
/*
* IS A TYPE A TRIVIAL CLASS TYPE?
*
* This routine checks whether the type t is an empty class type or an
* array of such.
*/
int
is_empty_class(TYPE t)
{
while (!IS_NULL_type (t)) {
switch (TAG_type (t)) {
case type_compound_tag : {
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
return (is_empty_ctype (ct));
}
case type_array_tag : {
t = DEREF_type (type_array_sub (t));
break;
}
case type_templ_tag : {
t = DEREF_type (type_templ_defn (t));
break;
}
default : {
return (0);
}
}
}
return (0);
}
/*
* BEGIN AN ENUMERATION DEFINITION
*
* This routine begins the definition on an enumeration type. The
* enumeration name is given by id and q gives any template type qualifiers.
* Note that an enumeration definition does not define a scope.
*/
IDENTIFIER
begin_enum_defn(IDENTIFIER id, TYPE q)
{
TYPE t;
ERROR err;
DECL_SPEC ds;
NAMESPACE ns;
ENUM_TYPE et;
CLASS_INFO ei;
IDENTIFIER eid = id;
QUALIFIER cq = crt_id_qualifier;
HASHID nm = DEREF_hashid (id_name (eid));
begin_declarator (id, cq, qual_namespace, 1);
/* Check on enumeration name */
if (is_templ_decl (id, NULL_type) || is_templ_spec (q)) {
/* Shouldn't have a template application */
q = bind_specialise (&eid, q, dspec_none, 1, 1, 1);
if (IS_NULL_id (eid) || check_key (eid, btype_enum)) {
nm = lookup_anon ();
eid = DEREF_id (hashid_id (nm));
cq = qual_none;
}
}
err = check_id_name (eid, CONTEXT_ENUM);
if (!IS_NULL_err (err)) report (crt_loc, err);
/* Check for qualified identifiers */
if (cq == qual_none) {
/* Simple enumeration name */
if (option (OPT_class_scope)) {
ns = crt_namespace;
if (IS_nspace_param (ns)) ns = nonclass_namespace;
} else {
ns = nonclass_namespace;
}
} else {
/* Definition of nested enumeration */
ns = DEREF_nspace (id_parent (eid));
check_decl_nspace (eid, ns, 1, crt_namespace);
if (IS_id_undef (eid)) nm = lookup_anon ();
}
/* Declare the enumeration */
eid = declare_type (ns, nm, btype_enum, q, 1, 1);
ds = DEREF_dspec (id_storage (eid));
COPY_dspec (id_storage (eid), (ds | dspec_defn));
t = DEREF_type (id_enum_name_defn (eid));
et = DEREF_etype (type_enumerate_defn (t));
/* Mark start of definition */
ei = DEREF_cinfo (etype_info (et));
ei |= cinfo_defined;
ei &= ~cinfo_complete;
COPY_cinfo (etype_info (et), ei);
if (do_dump) dump_declare (eid, &decl_loc, 1);
/* Force definition information */
COPY_loc (id_loc (eid), decl_loc);
return (eid);
}
/*
* END AN ENUMERATION DEFINITION
*
* This routine completes the definition of the enumeration type id.
* Note that only at this stage do the enumerators acquire the type
* of the enumeration in C++.
*/
IDENTIFIER
end_enum_defn(IDENTIFIER id)
{
HASHID nm = DEREF_hashid (id_name (id));
TYPE t = DEREF_type (id_enum_name_defn (id));
ENUM_TYPE et = DEREF_etype (type_enumerate_defn (t));
CLASS_INFO ei = DEREF_cinfo (etype_info (et));
/* Sort enumerators */
LIST (IDENTIFIER) ens = DEREF_list (etype_values (et));
unsigned nenums = LENGTH_list (ens);
if (nenums == 0) report (crt_loc, ERR_dcl_enum_none ());
IGNORE check_value (OPT_VAL_enum_consts, (ulong) nenums);
ens = REVERSE_list (ens);
COPY_list (etype_values (et), ens);
#if LANGUAGE_CPP
/* Convert enumerators to enumeration type */
while (!IS_NULL_list (ens)) {
IDENTIFIER eid = DEREF_id (HEAD_list (ens));
EXP e = DEREF_exp (id_enumerator_value (eid));
e = eval_exp (e, 0);
e = cast_exp (t, e, KILL_err, CAST_STATIC);
if (IS_exp_int_lit (e)) {
COPY_unsigned (exp_int_lit_etag (e), exp_identifier_tag);
if (is_zero_exp (e)) ei |= cinfo_usr_constr;
COPY_exp (id_enumerator_value (eid), e);
}
ens = TAIL_list (ens);
}
#endif
/* Mark end of definition */
ei |= cinfo_complete;
COPY_cinfo (etype_info (et), ei);
COPY_exp (etype_value (et), NULL_exp);
COPY_ulong (etype_plus (et), 0);
if (do_dump) dump_undefine (id, &crt_loc, 0);
end_declarator (id, 1);
/* Set type declaration flag */
if (IS_hashid_anon (nm) && nenums == 0) {
have_type_declaration = TYPE_DECL_ANON;
} else {
have_type_declaration = TYPE_DECL_NORMAL;
}
return (id);
}
/*
* LARGEST SIMPLE ENUMERATOR VALUE
*
* The underlying type of an enumeration can be int, unsigned int, long
* or unsigned long, depending on the values of the enumerators. This
* macro gives the maximum value which is guaranteed to fit into all of
* these types. Because unsigned types are involved, the minimum value
* is 0.
*/
#define ENUM_MAX ((unsigned long) 0x7fff)
/*
* DECLARE AN ENUMERATOR
*
* This routine declares an enumerator named id belonging to the enumeration
* type indicated by eid. The value of the enumerator is given by the
* integer constant expression val, if this is present, or one more than
* the previous enumerator otherwise. In C the value is converted to
* 'int'. In C++ the value is converted to the enumeration type, but
* this is only done at the end of the enumeration definition.
*/
IDENTIFIER
make_enumerator(IDENTIFIER eid, IDENTIFIER id, EXP val)
{
NAT n;
EXP e;
ERROR err;
int record = 0;
unsigned long v;
DECL_SPEC ds = (crt_access | dspec_defn | dspec_lang);
/* Find the current enumeration type */
TYPE t = DEREF_type (id_enum_name_defn (eid));
ENUM_TYPE et = DEREF_etype (type_enumerate_defn (t));
CLASS_INFO ei = DEREF_cinfo (etype_info (et));
LIST (IDENTIFIER) ens = DEREF_list (etype_values (et));
NAMESPACE ns = DEREF_nspace (id_parent (eid));
/* Look up the enumerator name */
IDENTIFIER nid = id;
HASHID nm = DEREF_hashid (id_name (nid));
MEMBER mem = search_member (ns, nm, 1);
/* Check on enumeration name */
err = check_id_name (nid, CONTEXT_ENUMERATOR);
if (!IS_NULL_err (err)) {
report (decl_loc, err);
err = NULL_err;
}
/* Check for redeclarations */
nid = DEREF_id (member_id (mem));
if (!IS_NULL_id (nid)) {
nid = redecl_inherit (nid, crt_id_qualifier, in_class_defn, 0);
if (!IS_NULL_id (nid)) {
IGNORE redecl_id (dspec_reserve, t, nid, 0, 0);
}
}
/* Declare the enumerator */
MAKE_id_enumerator (nm, ds, ns, decl_loc, t, val, nid);
if (do_dump) dump_declare (nid, &decl_loc, 1);
/* Find the enumerator value */
t = DEREF_type (etype_rep (et));
if (!IS_NULL_exp (val)) {
/* Check that any given val is a constant */
TYPE s = DEREF_type (exp_type (val));
#if LANGUAGE_CPP
s = promote_type (s);
val = convert_promote (s, val);
#else
switch (TAG_type (s)) {
case type_integer_tag :
case type_bitfield_tag :
case type_enumerate_tag : {
/* Convert integral values to 'int' */
s = t;
val = cast_int_int (s, val, &err, CAST_IMPLICIT, -1);
if (!IS_NULL_err (err)) {
report (crt_loc, err);
err = NULL_err;
}
break;
}
}
#endif
n = make_nat_exp (val, &err);
if (!IS_NULL_err (err)) {
/* Value is not an integral constant */
err = concat_error (err, ERR_dcl_enum_const (nid));
report (crt_loc, err);
s = t;
}
v = get_nat_value (n);
if (v <= ENUM_MAX) {
/* Small values */
if (!EQ_type (t, s)) {
/* Mark if enumerator has different type */
ei |= cinfo_polymorphic;
t = s;
}
if (v == 0) ei |= cinfo_usr_constr;
COPY_exp (etype_value (et), NULL_exp);
} else {
/* Large values */
EXP cond = crt_hash_cond;
if (!EQ_type (t, s)) {
/* Extend type range if necessary */
t = arith_type (t, s, NULL_exp, NULL_exp);
COPY_type (etype_rep (et), t);
ei |= cinfo_polymorphic;
t = s;
}
if (!IS_NULL_exp (cond) && is_calc_nat (n)) {
/* Propagate target dependent conditionals */
EXP alt = make_null_exp (t);
MAKE_exp_hash_if (t, cond, val, alt, val);
MAKE_nat_calc (val, n);
}
record = 1;
v = 0;
}
} else {
/* Other enumerators are one more than the previous one */
v = DEREF_ulong (etype_plus (et));
n = make_nat_value (v);
e = DEREF_exp (etype_value (et));
if (IS_NULL_exp (e)) {
if (ei & cinfo_polymorphic) {
/* Use type of last enumerator, if different */
IDENTIFIER pid = DEREF_id (HEAD_list (ens));
e = DEREF_exp (id_enumerator_value (pid));
t = DEREF_type (exp_type (e));
}
if (v == 0) ei |= cinfo_usr_constr;
} else {
EXP c;
t = DEREF_type (exp_type (e));
MAKE_exp_int_lit (t, n, exp_int_lit_tag, c);
MAKE_exp_plus (t, e, c, e);
MAKE_nat_calc (e, n);
}
}
MAKE_exp_int_lit (t, n, exp_identifier_tag, e);
COPY_exp (id_enumerator_value (nid), e);
/* Increment enumerator counter */
if (v >= ENUM_MAX) {
record = 1;
v = 0;
}
if (record) COPY_exp (etype_value (et), e);
COPY_ulong (etype_plus (et), v + 1);
/* Add enumerator to the enumerator list */
set_member (mem, nid);
CONS_id (nid, ens, ens);
COPY_list (etype_values (et), ens);
COPY_cinfo (etype_info (et), ei);
return (nid);
}
/*
* DOES A VALUE APPEAR AS AN ENUMERATOR?
*
* This routine checks whether the integer constant n is a valid enumerator
* for the enumeration et. If so it returns the enumerator identifier.
*/
IDENTIFIER
find_enumerator(ENUM_TYPE et, NAT n)
{
LIST (IDENTIFIER) p = DEREF_list (etype_values (et));
while (!IS_NULL_list (p)) {
IDENTIFIER eid = DEREF_id (HEAD_list (p));
EXP e = DEREF_exp (id_enumerator_value (eid));
NAT m = DEREF_nat (exp_int_lit_nat (e));
if (EQ_nat (n, m) || eq_nat (n, m)) return (eid);
p = TAIL_list (p);
}
return (NULL_id);
}
/*
* ELABORATE TYPE SPECIFIER FLAG
*
* This flag is set by find_elaborate_type and declare_type to indicate
* that the given type specifier referred to a pre-existing type.
*/
int found_elaborate_type = 0;
/*
* FIND AN ELABORATED TYPE SPECIFIER
*
* This routine finds the type identifier corresponding to the elaborated
* type specifier with identifier id, class key key (which can be
* btype_class, btype_struct, btype_union or btype_enum) and template
* type qualifiers q. The argument mode gives information on the
* context for the type specifier:
*
* dspec_defn for explicit declarations,
* dspec_friend for friend declarations,
* dspec_alias for qualified identifiers,
* dspec_auto if type is to be declared in current namespace,
* dspec_used if type is to be searched for.
*/
IDENTIFIER
find_elaborate_type(IDENTIFIER id, BASE_TYPE key, TYPE q, DECL_SPEC mode)
{
ERROR err;
LOCATION loc;
NAMESPACE ns;
IDENTIFIER tid;
int templ = is_templ_spec (q);
HASHID nm = DEREF_hashid (id_name (id));
/* Check for template applications */
if (templ || is_templ_decl (id, NULL_type)) {
tid = id;
if (mode & dspec_defn) {
/* Bind template specialisations */
DECL_SPEC ds = (mode & dspec_friend);
q = bind_specialise (&tid, q, ds, 1, 1, 0);
}
if (!IS_NULL_id (tid) && IS_id_class_name_etc (tid)) {
IGNORE check_key (tid, key);
if (templ) {
/* Check namespace for explicit declaration */
ns = DEREF_nspace (id_parent (tid));
check_decl_nspace (tid, ns, 0, crt_namespace);
}
found_elaborate_type = 1;
return (tid);
}
} else {
if (mode & dspec_alias) {
/* Qualified identifier */
NAMESPACE tns = DEREF_nspace (id_parent (id));
tid = find_qual_id (tns, nm, 0, 1);
if (IS_NULL_id (tid) || !IS_id_class_name_etc (tid)) {
if (!IS_NULL_id (tid) && IS_id_ambig (tid)) {
tid = report_ambiguous (tid, 1, 1, 1);
} else {
report (crt_loc, ERR_dcl_type_simple_undef (id));
tid = NULL_id;
q = NULL_type;
}
}
} else if (mode & dspec_register) {
/* Search enclosing namespace */
tid = find_extern_id (nm, nonclass_namespace, 1);
} else if (mode & dspec_used) {
/* Search for enclosing declaration */
tid = find_type_id (nm, 1);
} else {
/* Force a new declaration */
tid = NULL_id;
}
}
/* Check previous declaration */
while (!IS_NULL_id (tid)) {
if (IS_id_class_name_etc (tid)) {
/* Previous declaration was a type name */
BASE_TYPE prev = find_key (tid, 0, key);
if (prev == btype_alias) {
/* This was a typedef name */
err = ERR_lookup_elab_alias (key, tid);
report (crt_loc, err);
} else if (!equal_key (prev, key)) {
/* The class keys don't match */
PTR (LOCATION) ploc = id_loc (tid);
err = ERR_dcl_type_elab_bad (key, prev, tid, ploc);
report (crt_loc, err);
}
found_elaborate_type = 1;
return (tid);
}
if (IS_id_ambig (tid)) {
tid = report_ambiguous (tid, 1, 1, 1);
} else {
report (crt_loc, ERR_lookup_elab_invalid (key, tid));
tid = NULL_id;
}
}
/* Find namespace for declared type */
if (mode & dspec_alias) {
/* Declare in parent namespace */
ns = DEREF_nspace (id_parent (id));
} else if ((mode & dspec_auto) && option (OPT_class_scope)) {
/* Declare in the current namespace */
ns = crt_namespace;
} else if (mode & dspec_template) {
/* Declare in template namespace */
ns = templ_namespace;
} else {
/* Declare in enclosing namespace */
ns = nonclass_namespace;
}
/* Declare new type */
loc = decl_loc;
err = check_id_name (id, CONTEXT_CLASS);
id = underlying_id (id);
DEREF_loc (id_loc (id), decl_loc);
if (!IS_NULL_err (err)) report (decl_loc, err);
tid = declare_type (ns, nm, key, q, 0, 1);
if (do_dump) dump_declare (tid, &decl_loc, 0);
if (key == btype_enum) {
/* Can't declare enumerations (but have done) */
report (decl_loc, ERR_lookup_elab_enum (tid));
}
if (mode & dspec_friend) {
/* Warn about potential friend problems */
report (decl_loc, ERR_class_friend_pre (tid));
}
decl_loc = loc;
return (tid);
}
/*
* CREATE A TYPE ALIAS
*
* This routine creates a typedef with name nm and definition t
* in the namespace ns (but doesn't bring it into scope). Note that
* typedefs are split into class aliases, enumeration aliases and other
* type aliases. In the former two cases the class identifier is
* associated with t as the type name, and the member namespace name for
* classes, if this has not yet been defined.
*/
IDENTIFIER
make_typedef(NAMESPACE ns, HASHID nm, TYPE t, DECL_SPEC ds)
{
TYPE s;
unsigned tag;
IDENTIFIER id;
/* Force copy of type */
CV_SPEC cv = DEREF_cv (type_qual (t));
t = qualify_type (t, cv, 1);
s = t;
tag = TAG_type (s);
/* Check for template types */
if (ds == dspec_none) ds = (crt_access | dspec_defn);
while (tag == type_templ_tag) {
s = DEREF_type (type_templ_defn (s));
tag = TAG_type (s);
ds |= dspec_template;
}
/* Check for class aliases */
if (tag == type_compound_tag) {
CV_SPEC qual = DEREF_cv (type_qual (s));
if (qual == cv_none) {
/* Find the class name */
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (s));
IDENTIFIER cid = DEREF_id (ctype_name (ct));
HASHID cnm = DEREF_hashid (id_name (cid));
/* Set up the class alias */
MAKE_id_class_alias (nm, ds, ns, decl_loc, t, id);
if (IS_hashid_anon (cnm)) {
/* Set the class name if necessary */
NAMESPACE mns;
if (do_dump) {
dump_declare (id, &decl_loc, 1);
dump_anon_class = 1;
}
COPY_dspec (id_storage (id), (ds | dspec_lang));
mns = DEREF_nspace (ctype_member (ct));
COPY_id (nspace_name (mns), id);
COPY_id (ctype_name (ct), id);
/* Also set constructor and destructor names */
cid = DEREF_id (ctype_constr (ct));
cnm = DEREF_hashid (id_name (cid));
COPY_id (hashid_constr_tid (cnm), id);
cid = DEREF_id (ctype_destr (ct));
cnm = DEREF_hashid (id_name (cid));
COPY_id (hashid_destr_tid (cnm), id);
}
return (id);
}
}
/* Check for enumeration aliases */
if (tag == type_enumerate_tag) {
CV_SPEC qual = DEREF_cv (type_qual (s));
if (qual == cv_none) {
/* Find the enumeration name */
ENUM_TYPE et = DEREF_etype (type_enumerate_defn (s));
IDENTIFIER eid = DEREF_id (etype_name (et));
HASHID enm = DEREF_hashid (id_name (eid));
/* Set up the enumeration alias */
MAKE_id_enum_alias (nm, ds, ns, decl_loc, t, id);
/* Set the enumeration name if necessary */
if (IS_hashid_anon (enm)) {
if (do_dump) {
dump_declare (id, &decl_loc, 1);
dump_anon_class = 1;
}
COPY_dspec (id_storage (id), (ds | dspec_lang));
COPY_id (etype_name (et), id);
}
return (id);
}
}
/* Other type aliases */
MAKE_id_type_alias (nm, ds, ns, decl_loc, t, id);
return (id);
}
/*
* FIND THE COPIED VERSION OF A CLASS MEMBER
*
* This routine finds the member of the class cid corresponding to the
* class member id. cid will be a copy of the class containing id.
* Note that if res is false a set of overloaded functions is mapped to
* a set of overloaded functions, further resolutions based on type may be
* performed later. If res is true overload resolution is performed
* based on whether the result is an instantiation of id.
*/
IDENTIFIER
find_copied(IDENTIFIER cid, IDENTIFIER id, int res)
{
HASHID nm;
MEMBER mem;
NAMESPACE ns;
CLASS_TYPE ct;
IDENTIFIER mid;
/* Find class namespace */
TYPE t = DEREF_type (id_class_name_etc_defn (cid));
while (IS_type_templ (t)) {
t = DEREF_type (type_templ_defn (t));
}
ct = DEREF_ctype (type_compound_defn (t));
complete_class (ct, 1);
ns = DEREF_nspace (ctype_member (ct));
/* Look up name in namespace */
nm = DEREF_hashid (id_name (id));
nm = expand_name (nm, ct);
do {
mem = search_member (ns, nm, 0);
if (!IS_NULL_member (mem)) break;
nm = next_expand_name (nm);
} while (!IS_NULL_hashid (nm));
/* Check for corresponding identifier */
if (!IS_NULL_member (mem)) {
mid = DEREF_id (member_id (mem));
if (!IS_NULL_id (mid)) {
/* Identifier matches member */
if (IS_id_function_etc (mid) && IS_id_function_etc (id)) {
/* Matching functions */
if (res) {
IDENTIFIER fid = NULL_id;
TYPE f = DEREF_type (id_function_etc_form (id));
if (!IS_NULL_type (f) && IS_type_instance (f)) {
fid = DEREF_id (type_instance_id (f));
}
while (!IS_NULL_id (mid)) {
/* Perform overload resolution */
if (EQ_id (mid, id)) return (mid);
if (EQ_id (mid, fid)) return (mid);
f = DEREF_type (id_function_etc_form (mid));
if (!IS_NULL_type (f) && IS_type_instance (f)) {
IDENTIFIER nid;
nid = DEREF_id (type_instance_id (f));
if (EQ_id (nid, id)) return (mid);
if (EQ_id (nid, fid)) return (mid);
}
mid = DEREF_id (id_function_etc_over (mid));
}
mid = id;
}
return (mid);
}
if (TAG_id (mid) == TAG_id (id)) return (mid);
}
mid = DEREF_id (member_alt (mem));
if (!IS_NULL_id (mid) && TAG_id (mid) == TAG_id (id)) {
/* Identifier matches type member */
return (mid);
}
}
return (id);
}
/*
* COPY A CLASS TYPE
*
* This routine creates a new class which is a copy of t. This is used
* in the instantiation of template classes. Note that the members of
* the class are copied later by copy_members.
*/
TYPE
copy_class(TYPE t, DECL_SPEC ds)
{
LOCATION loc;
IDENTIFIER tid;
int r = really_in_class_defn;
int f = really_in_function_defn;
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
BASE_TYPE key = find_class_key (ct);
IDENTIFIER id = DEREF_id (ctype_name (ct));
HASHID nm = DEREF_hashid (id_name (id));
NAMESPACE ns = DEREF_nspace (id_parent (id));
DECL_SPEC acc = DEREF_dspec (id_storage (id));
ds |= (acc & dspec_access);
loc = crt_loc;
bad_crt_loc++;
really_in_class_defn = 0;
really_in_function_defn = 0;
DEREF_loc (id_loc (id), crt_loc);
decl_loc = crt_loc;
tid = make_class (ns, nm, key, ds, NULL_type, NULL_type);
t = DEREF_type (id_class_name_defn (tid));
really_in_function_defn = f;
really_in_class_defn = r;
bad_crt_loc--;
decl_loc = loc;
crt_loc = loc;
return (t);
}
/*
* COPY A LIST OF TEMPLATE SPECIALISATIONS
*
* This routine copies any partial or explicit specialisations of the
* template member tid of a template class to the corresponding member
* sid of an instance of that template class.
*/
static void
copy_specs(IDENTIFIER sid, IDENTIFIER tid, int type)
{
TYPE s, t;
if (type) {
/* Template classes */
s = DEREF_type (id_class_name_etc_defn (sid));
t = DEREF_type (id_class_name_etc_defn (tid));
} else {
/* Template functions */
s = DEREF_type (id_function_etc_type (sid));
t = DEREF_type (id_function_etc_type (tid));
}
if (IS_type_templ (s) && IS_type_templ (t)) {
TOKEN ps = DEREF_tok (type_templ_sort (s));
TOKEN pt = DEREF_tok (type_templ_sort (t));
INSTANCE as = DEREF_inst (tok_templ_apps (ps));
INSTANCE at = DEREF_inst (tok_templ_apps (pt));
while (!IS_NULL_inst (at)) {
DECL_SPEC acc = DEREF_dspec (inst_templ_access (at));
if (!(acc & (dspec_alias | dspec_main))) {
/* NOT YET IMPLEMENTED */
}
at = DEREF_inst (inst_next (at));
}
COPY_inst (tok_templ_apps (ps), as);
}
return;
}
/*
* COPY A NESTED CLASS
*
* This routine copies the nested class or enumeration type tid of a
* template class.
*/
static IDENTIFIER
copy_nested(IDENTIFIER tid, TYPE t, TYPE q, LOCATION *ploc)
{
IDENTIFIER id = tid;
switch (TAG_type (t)) {
case type_compound_tag : {
/* Non-template classes */
TYPE s;
TYPE form;
int def = 0;
DECL_SPEC ds;
CLASS_TYPE cs;
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
CLASS_INFO ci = DEREF_cinfo (ctype_info (ct));
BASE_TYPE key = find_class_key (ct);
IDENTIFIER cid = DEREF_id (ctype_name (ct));
HASHID nm = DEREF_hashid (id_name (cid));
NAMESPACE ns = crt_namespace;
/* Declare class */
if (!IS_id_class_name (tid)) break;
if (ci & cinfo_complete) def = 1;
id = declare_type (ns, nm, key, q, def, 1);
s = DEREF_type (id_class_name_defn (id));
while (IS_type_templ (s)) {
s = DEREF_type (type_templ_defn (s));
}
cs = DEREF_ctype (type_compound_defn (s));
ds = DEREF_dspec (id_storage (id));
ds |= dspec_instance;
COPY_dspec (id_storage (id), ds);
/* Set up instance type */
MAKE_type_instance (cv_none, tid, dspec_none, form);
COPY_id (type_name (form), id);
COPY_type (ctype_form (cs), form);
if (do_dump) dump_declare (id, ploc, 0);
/* complete_class (cs, 1) ; */
break;
}
case type_enumerate_tag : {
/* Enumeration type */
TYPE form;
DECL_SPEC ds;
ENUM_TYPE et = DEREF_etype (type_enumerate_defn (t));
CLASS_INFO ei = DEREF_cinfo (etype_info (et));
TYPE s = DEREF_type (etype_rep (et));
IDENTIFIER eid = DEREF_id (etype_name (et));
HASHID nm = DEREF_hashid (id_name (eid));
NAMESPACE ns = crt_namespace;
/* Declare enumeration */
if (!IS_id_enum_name (tid)) break;
id = declare_type (ns, nm, btype_enum, NULL_type, 1, 1);
ds = DEREF_dspec (id_storage (id));
ds |= dspec_instance;
COPY_dspec (id_storage (id), ds);
t = DEREF_type (id_enum_name_defn (id));
et = DEREF_etype (type_enumerate_defn (t));
COPY_cinfo (etype_info (et), ei);
s = expand_type (s, 1);
COPY_type (etype_rep (et), s);
/* Set up instance type */
MAKE_type_instance (cv_none, tid, dspec_none, form);
COPY_id (type_name (form), id);
COPY_type (etype_form (et), form);
if (do_dump) dump_declare (id, ploc, 0);
break;
}
case type_templ_tag : {
/* Template classes */
TYPE s;
TOKEN sort = DEREF_tok (type_templ_sort (t));
sort = expand_templ_sort (sort, 1);
MAKE_type_templ (cv_none, sort, NULL_type, 0, s);
q = inject_pre_type (q, s, 0);
t = DEREF_type (type_templ_defn (t));
id = copy_nested (tid, t, q, ploc);
reset_templ_sort (sort);
copy_specs (id, tid, 1);
break;
}
}
return (id);
}
/*
* COPY A MEMBER OF A CLASS
*
* This routine copies the class member id to the namespace ns, renaming
* it to nm.
*/
static IDENTIFIER
copy_member(IDENTIFIER id, HASHID nm, NAMESPACE ns, CLASS_TYPE ct,
LOCATION *ploc)
{
TYPE form;
IDENTIFIER tid = NULL_id;
unsigned tag = TAG_id (id);
/* Check for implicit and inherited members */
DECL_SPEC ds = DEREF_dspec (id_storage (id));
if (ds & (dspec_inherit | dspec_implicit)) {
/* Ignore implicit or inherited members */
if ((ds & dspec_alias) && (ds & dspec_inherit)) {
GRAPH gr;
tid = DEREF_id (id_alias (id));
tid = rescan_member (tid);
gr = is_subfield (ns, tid);
if (!IS_NULL_graph (gr)) {
DECL_SPEC acc = crt_access;
crt_access = (ds & dspec_access);
tid = search_subfield (ns, gr, tid);
tid = alias_id (tid, ns, NULL_id, 0);
if (TAG_id (tid) != tag) tid = NULL_id;
crt_access = acc;
} else {
report (crt_loc, ERR_dcl_nspace_udecl_base (tid, ct));
tid = NULL_id;
}
}
if (tag == id_mem_func_tag || tag == id_stat_mem_func_tag) {
IDENTIFIER fid = DEREF_id (id_function_etc_over (id));
if (!IS_NULL_id (fid)) {
/* Deal with overloaded functions */
DEREF_loc (id_loc (fid), crt_loc);
fid = copy_member (fid, nm, ns, ct, ploc);
if (!IS_NULL_id (tid)) {
COPY_id (id_function_etc_over (tid), fid);
if (!IS_NULL_id (fid)) {
tid = hide_functions (tid, fid, 1);
}
} else {
tid = fid;
}
}
}
return (tid);
}
/* Nested classes and enumerations already copied */
if (tag == id_class_name_tag || tag == id_enum_name_tag) {
return (NULL_id);
}
/* Copy member */
tid = copy_id (id, 2);
if (!EQ_id (tid, id)) {
int def = 0;
int virt = 0;
int templ = 0;
IDENTIFIER fid = NULL_id;
CLASS_INFO ci = DEREF_cinfo (ctype_info (ct));
ds = DEREF_dspec (id_storage (tid));
COPY_nspace (id_parent (tid), ns);
COPY_hashid (id_name (tid), nm);
switch (tag) {
case id_member_tag : {
/* Non-static data members */
OFFSET off;
DECL_SPEC acc = (ds & dspec_access);
TYPE t = DEREF_type (id_member_type (tid));
MAKE_off_member (tid, off);
COPY_off (id_member_off (tid), off);
check_mem_decl (ds, t, tid, ci);
ci = check_member_type (ct, ci, t, 0);
if (acc != dspec_public) ci |= cinfo_private;
def = 1;
break;
}
case id_stat_member_tag : {
/* Static data members */
EXP dummy;
TYPE t = DEREF_type (id_stat_member_type (tid));
check_mem_decl (ds, t, tid, ci);
MAKE_type_instance (cv_none, id, dspec_none, form);
COPY_id (type_name (form), tid);
MAKE_exp_paren (form, NULL_exp, dummy);
COPY_exp (id_stat_member_init (tid), NULL_exp);
COPY_exp (id_stat_member_term (tid), dummy);
ci |= cinfo_static;
ds &= ~dspec_defn;
break;
}
#if LANGUAGE_CPP
case id_mem_func_tag :
case id_stat_mem_func_tag : {
/* Member functions */
LIST (VIRTUAL) vt;
IDENTIFIER hide_id = NULL_id;
unsigned ntag = TAG_hashid (nm);
TYPE t = DEREF_type (id_function_etc_type (tid));
fid = DEREF_id (id_function_etc_over (id));
if (!IS_NULL_id (fid)) {
/* Deal with overloaded functions */
DEREF_loc (id_loc (fid), crt_loc);
fid = copy_member (fid, nm, ns, ct, ploc);
COPY_id (id_function_etc_over (tid), fid);
DEREF_loc (id_loc (tid), crt_loc);
}
if (ntag == hashid_op_tag) {
/* Check operator type */
int alloc = 0;
t = check_operator (t, tid, 1, &alloc);
if (alloc) recheck_allocator (tid, alloc);
}
decl_func_type (tid, t, 0);
special_func_mem (ct, tid, ntag, NULL_id);
vt = overrides_virtual (ct, nm, t, &hide_id);
if (!IS_NULL_list (vt)) {
/* Check for overriding virtual functions */
if (!(ds & dspec_virtual)) {
ERROR err = ERR_class_virtual_override (nm);
if (!IS_NULL_err (err)) report (crt_loc, err);
}
ds |= dspec_virtual;
}
if (ds & dspec_virtual) {
/* Deal with virtual functions */
add_virtual (ct, tid, vt);
ci |= cinfo_polymorphic;
if (!(ds & dspec_pure)) virt = 1;
}
MAKE_type_instance (cv_none, id, dspec_none, form);
COPY_id (type_name (form), tid);
COPY_type (id_function_etc_form (tid), form);
COPY_exp (id_function_etc_defn (tid), NULL_exp);
if (IS_type_templ (t)) templ = 1;
ci |= cinfo_function;
ds &= ~dspec_defn;
break;
}
#endif
case id_enumerator_tag : {
/* Enumerators */
TYPE t = DEREF_type (id_enumerator_etype (tid));
if (IS_type_enumerate (t)) {
/* Maintain list of enumerators */
LIST (IDENTIFIER) p, q;
ENUM_TYPE et = DEREF_etype (type_enumerate_defn (t));
p = DEREF_list (etype_values (et));
CONS_id (tid, NULL_list (IDENTIFIER), q);
p = APPEND_list (p, q);
COPY_list (etype_values (et), p);
}
break;
}
case id_class_alias_tag :
case id_enum_alias_tag :
case id_type_alias_tag : {
/* Typedefs */
LIST (IDENTIFIER) ft = DEREF_list (ctype_nest (ct));
CONS_id (tid, ft, ft);
COPY_list (ctype_nest (ct), ft);
break;
}
}
ds &= ~(dspec_used | dspec_called | dspec_done);
ds |= dspec_instance;
COPY_dspec (id_storage (tid), ds);
COPY_cinfo (ctype_info (ct), ci);
if (do_dump) dump_declare (tid, ploc, def);
if (templ) copy_specs (tid, id, 0);
if (virt) define_template (tid, 0);
if (!IS_NULL_id (fid)) {
/* Check overloaded functions */
tid = hide_functions (tid, fid, 1);
}
}
return (tid);
}
/*
* COPY A FRIEND CLASS
*
* This routine copies the friend class id of a template class. This may
* involve name injection.
*/
static IDENTIFIER
copy_friend_class(IDENTIFIER id)
{
TYPE t = DEREF_type (id_class_name_etc_defn (id));
TYPE s = expand_type (t, 1);
t = s;
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));
TYPE form = DEREF_type (ctype_form (cs));
id = DEREF_id (ctype_name (cs));
if (IS_NULL_type (form)) {
/* Allow for name injection */
HASHID nm = DEREF_hashid (id_name (id));
NAMESPACE ns = DEREF_nspace (id_parent (id));
MEMBER mem = search_member (ns, nm, 1);
TYPE q = extract_templ_qual (t);
BASE_TYPE key = find_key (id, 1, btype_none);
IDENTIFIER tid = declare_type (ns, nm, key, q, 0, 0);
IGNORE inject_pre_type (q, t, 0);
if (!IS_NULL_id (tid) && IS_id_class_name (tid)) {
/* Allow for redeclarations */
if (!EQ_id (tid, id)) {
IDENTIFIER pid = DEREF_id (id_alias (tid));
DECL_SPEC ds = DEREF_dspec (id_storage (id));
ds |= dspec_alias;
COPY_dspec (id_storage (id), ds);
COPY_id (id_alias (id), pid);
t = DEREF_type (id_class_name_defn (tid));
COPY_type (ctype_form (cs), t);
id = tid;
}
}
if (!in_template_decl) set_type_member (mem, id);
}
}
return (id);
}
/*
* COPY A FRIEND FUNCTION
*
* This routine copies the friend function id of a template class. This
* may involve name injection.
*/
static IDENTIFIER
copy_friend_func(IDENTIFIER id)
{
TYPE form;
MEMBER mem;
DECL_SPEC ds;
IDENTIFIER fid;
int changed = 0;
IDENTIFIER over = NULL_id;
HASHID nm = DEREF_hashid (id_name (id));
NAMESPACE ns = DEREF_nspace (id_parent (id));
HASHID nm1 = expand_name (nm, NULL_ctype);
NAMESPACE ns1 = rescan_nspace (ns);
TYPE t = DEREF_type (id_function_etc_type (id));
if (!IS_type_templ (t)) {
TYPE t1 = expand_type (t, 1);
if (!EQ_type (t1, t)) {
changed = 1;
t = t1;
}
}
if (!EQ_hashid (nm1, nm)) {
changed = 1;
nm = nm1;
}
if (!EQ_nspace (ns1, ns)) {
changed = 1;
ns = ns1;
}
if (changed) {
/* Copy identifier if necessary */
id = copy_id (id, 2);
COPY_nspace (id_parent (id), ns);
COPY_hashid (id_name (id), nm);
}
/* Check for template functions */
form = DEREF_type (id_function_etc_form (id));
if (!IS_NULL_type (form) && IS_type_token (form)) {
IDENTIFIER tid = DEREF_id (type_token_tok (form));
if (IS_id_function_etc (tid)) {
/* Template function instance */
TYPE t1 = DEREF_type (id_function_etc_type (tid));
t = injected_type (t, 1);
if (eq_type (t1, t) == 1) {
/* Allow for redeclarations */
id = tid;
} else {
LIST (TOKEN) args;
args = DEREF_list (type_token_args (form));
tid = copy_friend_func (tid);
if (do_dump) dump_declare (tid, &crt_loc, 0);
args = expand_args (args, 1, 1);
id = instance_func (tid, args, 0, 0);
return (id);
}
}
}
/* Look up matching declaration */
ds = DEREF_dspec (id_storage (id));
mem = search_member (ns, nm, 1);
fid = DEREF_id (member_id (mem));
if (!IS_NULL_id (fid)) {
unsigned tag = TAG_id (id);
DECL_SPEC cl = crt_linkage;
QUALIFIER cq = crt_id_qualifier;
crt_id_qualifier = qual_nested;
crt_linkage = (ds & dspec_language);
ds &= ~dspec_alias;
fid = redecl_func (ds, t, fid, tag, &over, -2);
crt_id_qualifier = cq;
crt_linkage = cl;
}
if (IS_NULL_id (fid)) {
/* Allow for name injection */
if (IS_nspace_ctype (ns)) {
report (crt_loc, ERR_basic_link_unmatch (t, id));
} else {
COPY_id (id_function_etc_over (id), over);
COPY_exp (id_function_etc_defn (id), NULL_exp);
if (!in_template_decl) set_member (mem, id);
}
} else {
/* Set up function alias */
if (!EQ_id (fid, id)) {
IDENTIFIER pid = DEREF_id (id_alias (fid));
ds |= dspec_alias;
COPY_dspec (id_storage (id), ds);
COPY_id (id_alias (id), pid);
id = fid;
}
}
return (id);
}
/*
* COPY THE MEMBERS OF A CLASS
*
* This routine copies the members of the class cs to the class ct.
* Note that this is done only if cs has been completely defined,
* partially defined classes are not copied.
*/
void
copy_members(CLASS_TYPE ct, CLASS_TYPE cs, CLASS_INFO ci, int def)
{
CLASS_INFO ck = DEREF_cinfo (ctype_info (cs));
CLASS_INFO cj = DEREF_cinfo (ctype_info (ct));
if (!(ck & cinfo_complete)) def = 0;
if (ck & cinfo_recursive) cj |= cinfo_recursive;
cj |= ci;
COPY_cinfo (ctype_info (ct), cj);
if (def && !(cj & cinfo_defined)) {
int ic;
GRAPH gr;
MEMBER mem;
DECL_SPEC ds;
LOCATION loc;
IDENTIFIER cid;
DECL_SPEC pacc;
ACCESS_LIST accs;
LIST (GRAPH) br;
LIST (IDENTIFIER) fr;
LIST (CLASS_TYPE) fc;
int lex = crt_lex_token;
int fn = in_function_defn;
int rfn = really_in_function_defn;
NAMESPACE nt = DEREF_nspace (ctype_member (ct));
NAMESPACE ns = DEREF_nspace (ctype_member (cs));
/* Save class information */
loc = crt_loc;
bad_crt_loc++;
ic = in_class_defn;
push_class (ct);
push_namespace (nt);
in_class_defn = 1;
in_function_defn = 0;
really_in_class_defn++;
really_in_function_defn = 0;
crt_lex_token = lex_ignore_token;
save_access (&accs);
cid = DEREF_id (ctype_name (ct));
DEREF_loc (id_loc (cid), crt_loc);
ds = DEREF_dspec (id_storage (cid));
ds |= dspec_defn;
COPY_dspec (id_storage (cid), ds);
cj |= (cinfo_complete | cinfo_defined);
COPY_cinfo (ctype_info (ct), cj);
if (do_dump) dump_declare (cid, &loc, 1);
/* Copy base classes */
pacc = prev_access;
gr = DEREF_graph (ctype_base (cs));
br = DEREF_list (graph_tails (gr));
while (!IS_NULL_list (br)) {
int virt = 0;
GRAPH gu = DEREF_graph (HEAD_list (br));
CLASS_TYPE cu = DEREF_ctype (graph_head (gu));
DECL_SPEC acc = DEREF_dspec (graph_access (gu));
cid = DEREF_id (ctype_name (cu));
if (acc & dspec_virtual) virt = 1;
acc &= dspec_access;
add_base_class (cid, acc, virt);
br = TAIL_list (br);
}
end_base_class (ct, 1);
prev_access = pacc;
/* Copy nested classes */
fr = DEREF_list (ctype_nest (cs));
while (!IS_NULL_list (fr)) {
IDENTIFIER fid = DEREF_id (HEAD_list (fr));
if (IS_id_class_name_etc (fid)) {
DECL_SPEC fds = DEREF_dspec (id_storage (fid));
if (!(fds & dspec_instance)) {
TYPE f;
DEREF_loc (id_loc (fid), crt_loc);
pacc = crt_access;
crt_access = (fds & dspec_access);
f = DEREF_type (id_class_name_etc_defn (fid));
IGNORE copy_nested (fid, f, NULL_type, &loc);
crt_access = pacc;
}
}
fr = TAIL_list (fr);
}
/* Copy class members */
mem = DEREF_member (nspace_ctype_first (ns));
while (!IS_NULL_member (mem)) {
HASHID tnm = NULL_hashid;
MEMBER tmem = NULL_member;
IDENTIFIER id = DEREF_id (member_id (mem));
IDENTIFIER alt = DEREF_id (member_alt (mem));
if (!IS_NULL_id (id)) {
IDENTIFIER tid;
HASHID nm = DEREF_hashid (id_name (id));
DEREF_loc (id_loc (id), crt_loc);
tnm = expand_name (nm, ct);
tmem = search_member (nt, tnm, 1);
tid = copy_member (id, tnm, nt, ct, &loc);
if (!IS_NULL_id (tid)) {
set_member (tmem, tid);
}
}
if (!IS_NULL_id (alt) && !EQ_id (id, alt)) {
IDENTIFIER talt;
DEREF_loc (id_loc (alt), crt_loc);
if (IS_NULL_member (tmem)) {
HASHID nm = DEREF_hashid (id_name (alt));
tnm = expand_name (nm, ct);
tmem = search_member (nt, tnm, 1);
}
talt = copy_member (alt, tnm, nt, ct, &loc);
if (!IS_NULL_id (talt)) {
set_type_member (tmem, talt);
}
}
mem = DEREF_member (member_next (mem));
}
/* Copy chums */
fc = DEREF_list (ctype_chums (cs));
while (!IS_NULL_list (fc)) {
TYPE r = NULL_type;
CLASS_TYPE cr = DEREF_ctype (HEAD_list (fc));
cr = expand_ctype (cr, 2, &r);
friend_class (cr, cid, 0);
fc = TAIL_list (fc);
}
/* Copy pals */
fr = DEREF_list (ctype_pals (cs));
if (!IS_NULL_list (fr)) {
while (!IS_NULL_list (fr)) {
IDENTIFIER fid = DEREF_id (HEAD_list (fr));
DEREF_loc (id_loc (fid), decl_loc);
DEREF_loc (id_loc (fid), crt_loc);
if (IS_id_class_name (fid)) {
fid = copy_friend_class (fid);
friend_class (ct, fid, 0);
} else {
EXP e = DEREF_exp (id_function_etc_defn (fid));
fid = copy_friend_func (fid);
friend_function (ct, fid, 0);
if (!IS_NULL_exp (e) && !IS_exp_value (e)) {
copy_object (fid, e);
}
}
if (do_dump) dump_declare (fid, &crt_loc, 0);
fr = TAIL_list (fr);
}
fr = DEREF_list (ctype_pals (ct));
fr = REVERSE_list (fr);
COPY_list (ctype_pals (ct), fr);
}
/* Update class information */
cj = DEREF_cinfo (ctype_info (ct));
#if LANGUAGE_CPP
cj = implicit_decl (ct, cj, dspec_instance);
#endif
if (cj & cinfo_non_aggregate) {
/* POD classes must be aggregate classes */
cj &= ~cinfo_pod;
}
cj |= cinfo_complete;
COPY_cinfo (ctype_info (ct), cj);
inherit_class ();
IGNORE restore_access (cid, &accs);
in_class_defn = ic;
really_in_class_defn--;
really_in_function_defn = rfn;
in_function_defn = fn;
crt_lex_token = lex;
IGNORE pop_namespace ();
pop_class ();
decl_loc = loc;
crt_loc = loc;
bad_crt_loc--;
}
return;
}
syntax highlighted by Code2HTML, v. 0.9.1