/* * Copyright (c) 2002, The Tendra Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * Crown Copyright (c) 1997, 1998 * * This TenDRA(r) Computer Program is subject to Copyright * owned by the United Kingdom Secretary of State for Defence * acting through the Defence Evaluation and Research Agency * (DERA). It is made available to Recipients with a * royalty-free licence for its use, reproduction, transfer * to other parties and amendment for any purpose not excluding * product development provided that any such use et cetera * shall be deemed to be acceptance of the following conditions:- * * (1) Its Recipients shall ensure that this Notice is * reproduced upon any copies or amended versions of it; * * (2) Any amended version of it shall be clearly marked to * show both the nature of and the organisation responsible * for the relevant amendment or amendments; * * (3) Its onward transfer from a recipient to another * party shall be deemed to be that party's acceptance of * these conditions; * * (4) DERA gives no warranty or assurance as to its * quality or suitability for any purpose and DERA accepts * no liability whatsoever in relation to any use to which * it may be put. * * $TenDRA: tendra/src/producers/common/construct/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; }