Rev 5 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* Copyright (c) 2002-2006 The TenDRA Project <http://www.tendra.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,
* 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.
* 3. Neither the name of The TenDRA Project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific, prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``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 COPYRIGHT HOLDERS OR
* CONTRIBUTORS 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.
*
* $Id$
*/
/*
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.
*/
#include "config.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 = 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);
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;
}