/* * 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 * * 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/redeclare.c,v 1.10 2005/11/07 18:42:37 stefanf Exp $ */ #include "config.h" #include "producer.h" #include "c_types.h" #include "ctype_ops.h" #include "err_ops.h" #include "exp_ops.h" #include "graph_ops.h" #include "hashid_ops.h" #include "id_ops.h" #include "member_ops.h" #include "off_ops.h" #include "nspace_ops.h" #include "str_ops.h" #include "tok_ops.h" #include "type_ops.h" #include "error.h" #include "catalog.h" #include "access.h" #include "basetype.h" #include "char.h" #include "check.h" #include "chktype.h" #include "class.h" #include "compile.h" #include "constant.h" #include "copy.h" #include "declare.h" #include "derive.h" #include "dump.h" #include "file.h" #include "function.h" #include "identifier.h" #include "instance.h" #include "literal.h" #include "namespace.h" #include "option.h" #include "overload.h" #include "predict.h" #include "redeclare.h" #include "syntax.h" #include "template.h" #include "tokdef.h" #include "token.h" #include "ustring.h" /* * CURRENT LINKAGE SPECIFIER * * The current linkage specifier is handled by means of this global * variable. The default, of no linkage being given, is interpreted * according to the source language. */ DECL_SPEC crt_linkage = dspec_none; DECL_SPEC new_linkage = dspec_none; /* * FIND A LINKAGE SPECIFIER * * This routine translates the string literal expression e into a linkage * specifier. The only recognised strings are "C" and "C++". */ DECL_SPEC find_linkage(EXP e) { STRING s = DEREF_str (exp_string_lit_str (e)); unsigned kind = DEREF_unsigned (str_simple_kind (s)); /* Can only occur in namespace scope */ if (in_function_defn || in_class_defn) { report (crt_loc, ERR_dcl_link_scope ()); } /* Check the linkage string */ if (kind == STRING_NONE) { char *t = strlit (DEREF_string (str_simple_text (s))); unsigned long len = DEREF_ulong (str_simple_len (s)); if (len == 1 && streq (t, "C")) { return (dspec_c); } if (len == 3 && streq (t, "C++")) { return (dspec_cpp); } } /* Report unknown strings */ report (crt_loc, ERR_dcl_link_unknown (s)); return (crt_linkage); } /* * FIND A LINKAGE STRING * * This routine returns the string corresponding to the linkage specifiers * given by ds and cv. */ string linkage_string(DECL_SPEC ds, CV_SPEC cv) { const char *str; if ((ds & dspec_c) || (cv & cv_c)) { str = "C"; } else { str = "C++"; } return (ustrlit (str)); } /* * ADJUST DECLARATION SPECIFIER FOR LANGUAGE * * This routine adds the current language specifier to the declaration * specifier ds. mem is true for a member declaration (which always * has C++ linkage). ds may contain a language specifier from a * previous declaration, otherwise it is deduced from crt_linkage. */ DECL_SPEC adjust_linkage(DECL_SPEC ds, int mem) { DECL_SPEC rs = (ds & ~dspec_language); if (mem) { /* Members have C++ linkage */ rs |= dspec_cpp; } else if (rs & dspec_linkage) { /* Only applies to objects with linkage */ DECL_SPEC ln = (ds | crt_linkage); if (ln & dspec_c) { rs |= dspec_c; } else { rs |= dspec_cpp; } } return (rs); } /* * CHECK C LINKAGE DECLARATIONS * * This routine checks the identifier id declared with C linkage. Objects * with C linkage in different namespaces are actually the same. */ void c_linkage(IDENTIFIER id, int def) { TYPE t = NULL_type; unsigned tag = TAG_id (id); if (tag == id_function_tag) { /* Template functions can't have C linkage */ t = DEREF_type (id_function_type (id)); if (IS_type_templ (t)) { report (decl_loc, ERR_temp_decl_linkage ()); } } else if (tag == id_variable_tag) { t = DEREF_type (id_variable_type (id)); } if (!IS_NULL_type (t)) { NAMESPACE ns = c_namespace; if (!IS_NULL_nspace (ns)) { HASHID nm = DEREF_hashid (id_name (id)); MEMBER mem = search_member (ns, nm, 1); IDENTIFIER pid = DEREF_id (member_id (mem)); if (!IS_NULL_id (pid) && !EQ_id (id, pid)) { NAMESPACE cns = DEREF_nspace (id_parent (id)); NAMESPACE pns = DEREF_nspace (id_parent (pid)); if (!EQ_nspace (cns, pns)) { DECL_SPEC cl = crt_linkage; QUALIFIER cq = crt_id_qualifier; DECL_SPEC ds = DEREF_dspec (id_storage (id)); crt_linkage = (ds & dspec_language); crt_id_qualifier = qual_none; pid = redecl_id (ds, t, pid, 3, -1); if (!IS_NULL_id (pid)) { /* Set up alias */ if (IS_id_function (pid)) { TYPE s = DEREF_type (id_function_type (pid)); s = redecl_func_type (pid, s, t, def, 0); COPY_type (id_function_type (pid), s); } ds |= dspec_alias; COPY_dspec (id_storage (id), ds); pid = DEREF_id (id_alias (pid)); COPY_id (id_alias (id), pid); if (do_dump) dump_alias (id, pid, &decl_loc); id = pid; } crt_id_qualifier = cq; crt_linkage = cl; } } COPY_id (member_id (mem), id); } } return; } /* * FIND A PREVIOUS DECLARATION * * If a declaration in block scope is declared extern then it has external * linkage unless the declaration matches a visible declaration of namespace * scope. This routine finds such a declaration for the identifier id * of type t. */ IDENTIFIER find_previous(TYPE t, IDENTIFIER id) { if (crt_id_qualifier == qual_none) { NAMESPACE ns = nonblock_namespace; HASHID nm = DEREF_hashid (id_name (id)); IDENTIFIER pid = find_extern_id (nm, ns, 0); if (!IS_NULL_id (pid)) { TYPE s; DECL_SPEC st; switch (TAG_id (pid)) { case id_variable_tag : { /* Variables may be redeclared */ s = DEREF_type (id_variable_type (pid)); break; } case id_function_tag : { /* Functions may be redeclared */ #if LANGUAGE_CPP int eq = 0; LIST (IDENTIFIER) pids = NULL_list (IDENTIFIER); pid = resolve_func (pid, t, 0, 0, pids, &eq); if (IS_NULL_id (pid)) return (NULL_id); if (!IS_id_function (pid)) return (NULL_id); #endif s = DEREF_type (id_function_type (pid)); break; } default : { /* Nothing else can be redeclared */ return (NULL_id); } } st = DEREF_dspec (id_storage (pid)); if (st & dspec_linkage) { /* Previous declaration must have linkage */ s = type_composite (s, t, 0, 0, KILL_err, 0); if (!IS_NULL_type (s)) return (pid); } } } return (NULL_id); } /* * UNIFY AN EXTERNAL IDENTIFIER * * This routine checks the identifier id, which is a variable declared * extern in a block, against conflicts with the namespace ns into * which it is injected. p gives all the other extern block identifiers * declared before id. The routine returns any previous identifier. */ IDENTIFIER unify_extern(IDENTIFIER id, TYPE t, NAMESPACE ns, LIST (IDENTIFIER) p) { IDENTIFIER pid = NULL_id; HASHID nm = DEREF_hashid (id_name (id)); LIST (IDENTIFIER) pids = NULL_list (IDENTIFIER); while (!IS_NULL_list (p)) { /* Check other block externs */ IDENTIFIER bid = DEREF_id (HEAD_list (p)); HASHID bnm = DEREF_hashid (id_name (bid)); if (EQ_hashid (bnm, nm)) { bid = DEREF_id (id_alias (bid)); CONS_id (bid, pids, pids); } p = TAIL_list (p); } if (!IS_NULL_nspace (ns)) { /* Check actual namespace */ MEMBER mem = search_member (ns, nm, 0); if (!IS_NULL_member (mem)) { IDENTIFIER bid = DEREF_id (member_id (mem)); if (!IS_NULL_id (bid)) { bid = DEREF_id (id_alias (bid)); CONS_id (bid, pids, pids); } } } if (!IS_NULL_list (pids)) { /* Match found */ if (IS_NULL_type (t)) { if (IS_NULL_list (TAIL_list (pids))) { pid = DEREF_id (HEAD_list (pids)); DESTROY_list (pids, SIZE_id); } else { DECL_SPEC ds; pids = REVERSE_list (pids); ds = find_ambig_dspec (pids); MAKE_id_ambig (nm, ds, ns, crt_loc, pids, 1, pid); } } else { LIST (IDENTIFIER) qids; DECL_SPEC cl = crt_linkage; QUALIFIER cq = crt_id_qualifier; DECL_SPEC ds = DEREF_dspec (id_storage (id)); crt_linkage = (ds & dspec_language); crt_id_qualifier = qual_none; DEREF_loc (id_loc (id), decl_loc); pids = REVERSE_list (pids); qids = pids; while (!IS_NULL_list (qids)) { IDENTIFIER qid = DEREF_id (HEAD_list (qids)); qid = DEREF_id (id_alias (qid)); if (IS_type_func (t)) { /* Check function redeclaration */ IDENTIFIER over = NULL_id; unsigned tag = TAG_id (id); qid = redecl_func (ds, t, qid, tag, &over, -1); } else { /* Check variable redeclaration */ qid = redecl_id (ds, t, qid, 0, -1); } if (!IS_NULL_id (qid)) pid = qid; qids = TAIL_list (qids); } DESTROY_list (pids, SIZE_id); crt_id_qualifier = cq; crt_linkage = cl; } } return (pid); } /* * UNIFY A BLOCK DECLARATION WITH A PREVIOUS DECLARATION * * This routine is used to unify the external block declaration id of * type t with its previous declaration pid (as returned by find_previous). * def is true is id is a function definition. The routine returns id. * If there is no previous declaration then one is created and added to * the extra identifier list of the enclosing non-block namespace. */ IDENTIFIER unify_previous(IDENTIFIER id, TYPE t, IDENTIFIER pid, int def) { /* Unify external linkage */ if (IS_NULL_id (pid)) { LIST (IDENTIFIER) p; NAMESPACE ns = nonblock_namespace; p = DEREF_list (nspace_named_etc_extra (ns)); pid = unify_extern (id, t, ns, p); if (IS_NULL_id (pid)) { if (!is_templ_depend (t)) { /* Declare new external object */ DECL_SPEC ds; pid = copy_id (id, 0); ds = DEREF_dspec (id_storage (pid)); if (!(ds & dspec_linkage)) ds |= dspec_extern; ds &= ~dspec_alias; COPY_dspec (id_storage (pid), ds); COPY_nspace (id_parent (pid), ns); COPY_id (id_alias (pid), pid); CONS_id (pid, p, p); COPY_list (nspace_named_etc_extra (ns), p); } /* Check object type */ if (!is_global_type (t)) { report (crt_loc, ERR_basic_link_none (t, id)); } } } /* Alias id to be pid */ if (!IS_NULL_id (pid)) { if (IS_id_function_etc (pid)) { TYPE s = DEREF_type (id_function_etc_type (pid)); s = redecl_func_type (pid, s, t, def, 0); COPY_type (id_function_etc_type (pid), s); } pid = DEREF_id (id_alias (pid)); COPY_id (id_alias (id), pid); } return (id); } /* * UNIFY A DECLARATION WITH A PREVIOUS BLOCK DECLARATION * * This routine is used to unify the external declaration id of type * t with any previous external block declaration of the same object. * def is true if id is a function definition. The routine returns id. */ IDENTIFIER unify_subsequent(IDENTIFIER id, TYPE t, int def) { NAMESPACE ns = DEREF_nspace (id_parent (id)); if (IS_nspace_named_etc (ns)) { LIST (IDENTIFIER) p; p = DEREF_list (nspace_named_etc_extra (ns)); if (!IS_NULL_list (p)) { IDENTIFIER pid = unify_extern (id, t, NULL_nspace, p); if (!IS_NULL_id (pid)) { /* Alias id to be pid */ if (IS_id_function_etc (pid)) { TYPE s = DEREF_type (id_function_etc_type (pid)); s = redecl_func_type (pid, s, t, def, 0); COPY_type (id_function_etc_type (pid), s); } pid = DEREF_id (id_alias (pid)); COPY_id (id_alias (id), pid); } } } return (id); } /* * CHECK FOR CLASS-LIKE TYPEDEF NAMES * * This routine checks whether the typedef name id behaves like a class * or an object with respect to name hiding. It is not entirely clear * whether it is just original class and enumeration names or all class * and enumeration names (including those introduced using typedef) * which behave in this way. */ int is_tagged_type(IDENTIFIER id) { switch (TAG_id (id)) { case id_class_name_tag : case id_enum_name_tag : { /* Original class and enumeration names */ return (1); } case id_class_alias_tag : case id_enum_alias_tag : case id_type_alias_tag : { /* Type aliases */ return (0); } } return (0); } /* * REPORT AN OVERLOADING ERROR * * This routine reports the overloading error err for the function id * which cannot be overloaded for the reason corresponding to reason. * It returns the severity of the error. */ static int overload_error(IDENTIFIER id, ERROR err, int reason) { int sev = ERROR_NONE; switch (reason) { case 1 : { /* Two functions with C linkage */ err = concat_error (err, ERR_dcl_link_over ()); break; } case 2 : { /* Two functions with indistinguishable parameters */ err = concat_error (err, ERR_over_load_pars ()); break; } case 3 : { /* Two objects with C linkage */ PTR (LOCATION) loc = id_loc (id); HASHID nm = DEREF_hashid (id_name (id)); err = concat_error (err, ERR_dcl_link_redecl (nm, loc)); break; } } if (!IS_NULL_err (err)) { sev = DEREF_int (err_severity (err)); report (decl_loc, err); } return (sev); } /* * REDECLARE AN OBJECT IDENTIFIER * * This routine checks the redeclaration of the identifier id as an object * with declaration specifiers ds and type t. It returns id for a valid * redeclaration and the null identifier otherwise, reporting any errors * if necessary. Note that it is possible to reserve an identifier using * the reserve declaration specifier. At present this is only done for * the fields of an anonymous union and enumerators. Also a class or * enumeration name can be hidden by an object in the same scope. A * redeclared identifier will be marked as defined according to whether * the redeclaration is a definition. Whether the initial declaration * was a definition may be determined from the initialiser expression. */ IDENTIFIER redecl_id(DECL_SPEC ds, TYPE t, IDENTIFIER id, int reason, int def) { TYPE s; DECL_SPEC ln; PTR (TYPE) pt; int changed = 0; int is_member = 0; int is_function = 0; ERROR err = NULL_err; DECL_SPEC ds_old, ln_old; /* Check previous definition */ switch (TAG_id (id)) { case id_variable_tag : { /* Variables may be redeclared */ pt = id_variable_type (id); break; } case id_function_tag : { /* Functions may be redeclared */ is_function = 1; pt = id_function_type (id); break; } case id_class_name_tag : case id_enum_name_tag : case id_class_alias_tag : case id_enum_alias_tag : case id_type_alias_tag : { /* Unqualified class and enumeration names can be hidden */ PTR (LOCATION) loc; if (!is_tagged_type (id)) { loc = id_loc (id); report (decl_loc, ERR_basic_odr_diff (id, loc)); return (NULL_id); } if (crt_id_qualifier == qual_none) { /* Check for templates */ ds_old = DEREF_dspec (id_storage (id)); if (!(ds_old & dspec_template)) return (NULL_id); } loc = id_loc (id); report (decl_loc, ERR_basic_odr_diff (id, loc)); return (NULL_id); } case id_stat_member_tag : { /* Members may be defined outside their class */ is_member = 1; if (crt_id_qualifier == qual_none) goto error_lab; pt = id_stat_member_type (id); break; } case id_mem_func_tag : case id_stat_mem_func_tag : { /* Members may be defined outside their class */ is_member = 1; is_function = 1; if (crt_id_qualifier == qual_none) goto error_lab; pt = id_function_etc_type (id); break; } case id_member_tag : { /* Non-static members cannot be redeclared */ is_member = 1; if (crt_id_qualifier == qual_none) goto error_lab; report (decl_loc, ERR_class_mem_def (id)); return (NULL_id); } case id_token_tag : { /* Allow for token definitions */ return (NULL_id); } case id_undef_tag : case id_ambig_tag : { /* Allow for error propagation */ return (NULL_id); } default : error_lab : { /* No other identifiers can be redeclared */ if (is_member) { /* Member redeclaration */ err = ERR_class_mem_redecl (id, id_loc (id)); } else { /* Object redeclaration */ err = ERR_basic_odr_decl (id, id_loc (id)); } IGNORE overload_error (id, err, reason); return (NULL_id); } } /* Check declaration specifiers */ ds_old = DEREF_dspec (id_storage (id)); if ((ds | ds_old) & dspec_reserve) { /* Reserved names can't be redeclared */ reason = 0; goto error_lab; } /* Check for objects with no linkage */ ln = (ds & dspec_linkage); ln_old = (ds_old & dspec_linkage); if (ln == dspec_none || ln_old == dspec_none) { /* Can't redeclare objects with no linkage */ if (!is_function) { reason = 0; goto error_lab; } } /* Check previous type */ s = DEREF_type (pt); s = check_compatible (s, t, 0, &err, 1); if (!IS_NULL_err (err)) { /* Incompatible declaration */ PTR (LOCATION) loc = id_loc (id); err = concat_error (err, ERR_basic_link_decl_type (id, loc)); if ((ds | ds_old) & dspec_token) { /* Allow for interface declarations */ err = set_severity (err, OPT_interf_incompat, -1); } if (overload_error (id, err, reason) == ERROR_SERIOUS) { return (NULL_id); } } if (is_function) { /* Sanity check for error types */ if (type_tag (s) != type_func_tag) return (NULL_id); } else { if (type_tag (s) == type_func_tag) return (NULL_id); } if (def >= 0) COPY_type (pt, s); /* Check for redeclaration of aliases */ if ((ds | ds_old) & dspec_alias) { PTR (LOCATION) loc = id_loc (id); report (decl_loc, ERR_dcl_nspace_udecl_redecl (id, loc)); } /* Check for inconsistent linkage */ if (ln != ln_old) { ERROR err1; DECL_SPEC ln_new; PTR (LOCATION) loc = id_loc (id); if (ln_old == dspec_static) { err1 = ERR_dcl_stc_internal (id, loc); } else { err1 = ERR_dcl_stc_external (id, loc); if (is_member) { /* Members have external linkage */ ERROR err2 = ERR_basic_link_mem_extern (id); err1 = concat_error (err2, err1); } } if (reason == 3) { /* Identification of objects with C linkage */ HASHID nm = DEREF_hashid (id_name (id)); ERROR err2 = ERR_dcl_link_redecl (nm, loc); err1 = concat_error (err1, err2); } if (def == -1 && option (OPT_link_internal) == OPTION_OFF) { ln_new = dspec_extern; } else { ln_new = dspec_static; } ds_old = (ln_new | (ds_old & ~dspec_linkage)); report (decl_loc, err1); changed = 1; } /* Check language specifier */ ln = crt_linkage; if (ln != dspec_none) { /* Check against the current language */ ln_old = (ds_old & dspec_language); if ((ds_old & dspec_extern) && ln != ln_old) { /* Report inconsistent linkage */ if (!is_member) { /* Should this only apply to functions? */ PTR (LOCATION) loc = id_loc (id); string lang = linkage_string (ln_old, cv_none); report (decl_loc, ERR_dcl_link_lang (id, lang, loc)); ds_old = adjust_linkage (ds_old, is_member); changed = 1; } } } /* Check for inline specifier */ if (ds & dspec_inline) { ds_old |= dspec_inline; changed = 1; } /* Mark whether this declaration is a definition */ if (def >= 0) { if (ds & dspec_defn) { ds_old |= dspec_defn; } else { ds_old &= ~dspec_defn; } } /* Compatible redeclaration */ COPY_dspec (id_storage (id), ds_old); if (changed) update_tag (id, 0); return (id); } /* * REDECLARE A FUNCTION IDENTIFIER * * This routine is similar to redecl_id except that it allows for function * overloading. As before it returns id if this is a redeclaration of an * existing function, and the null identifier otherwise. However in the * latter case any functions overloaded by the declaration are returned * via over. */ IDENTIFIER redecl_func(DECL_SPEC ds, TYPE t, IDENTIFIER id, unsigned tag, IDENTIFIER *over, int def) { int reason = 0; IDENTIFIER fid = id; #if LANGUAGE_CPP if (IS_id_function_etc (fid)) { DECL_SPEC ds_old; *over = fid; /* Scan through overloaded functions for a match */ while (!IS_NULL_id (fid)) { int m; TYPE s; int mq = 1; if ((ds & dspec_extern) && crt_linkage == dspec_c) { /* Two functions with C linkage are the same */ ds_old = DEREF_dspec (id_storage (fid)); if ((ds_old & dspec_c) && IS_id_function (fid)) { reason = 1; break; } } /* Two functions with the same parameters are the same */ s = DEREF_type (id_function_etc_type (fid)); if (tag == id_stat_mem_func_tag) mq = 0; if (IS_id_stat_mem_func (fid)) mq = 0; m = eq_func_type (t, s, mq, 0); if (m) { /* Function types basically match */ if (m == 1) { /* Return types don't match */ reason = 2; } break; } fid = DEREF_id (id_function_etc_over (fid)); } if (IS_NULL_id (fid)) { /* No match found */ IDENTIFIER tid = find_template (id, 0); if (!IS_NULL_id (tid)) { /* Must have match with template specialisation */ report (decl_loc, ERR_temp_spec_type (t, id)); return (NULL_id); } if (crt_id_qualifier != qual_none) { /* Must have match with qualified identifier */ if (def == -2 && tag == id_function_tag) { /* Allow for name injection */ /* EMPTY */ } else { report (decl_loc, ERR_basic_link_unmatch (t, id)); } return (NULL_id); } if (reason == 0) return (NULL_id); fid = id; } /* Match found */ ds_old = DEREF_dspec (id_storage (fid)); if ((ds_old & dspec_implicit) && !(ds & dspec_implicit)) { if (IS_id_mem_func (fid)) { /* Matches implicitly declared member function */ report (decl_loc, ERR_class_special_decl (fid)); return (NULL_id); } } if (ds_old & dspec_inherit) { /* Inherited functions (including aliases) are hidden */ return (NULL_id); } /* *over = NULL_id; */ } #else /* Don't check overloading in C */ *over = NULL_id; UNUSED (tag); #endif /* Redeclare id */ fid = redecl_id (ds, t, fid, reason, def); if (!IS_NULL_id (fid)) { TYPE form = DEREF_type (id_function_etc_form (id)); if (def >= 0) { /* Allow for default arguments etc. */ TYPE s = DEREF_type (id_function_etc_type (fid)); s = redecl_func_type (fid, s, t, def, 1); COPY_type (id_function_etc_type (fid), s); } if (!IS_NULL_type (form) && IS_type_token (form)) { IDENTIFIER ext = DEREF_id (type_token_tok (form)); if (!IS_NULL_id (ext) && IS_id_token (ext)) { /* Check for tokenised functions */ ds = DEREF_dspec (id_storage (ext)); ds |= dspec_explicit; COPY_dspec (id_storage (ext), ds); if (def) { /* Check for token definitions */ IGNORE define_func_token (ext, fid); if (ds & dspec_pure) { report (decl_loc, ERR_token_def_not (ext)); } } } } } return (fid); } /* * REDECLARE AN INHERITED OR ALIASED MEMBER * * This routine is used to allow for declarations of class members to * override any inherited value of the member. id gives the inherited * value, mem is true for a member declaration, fn is true for a function * declaration or a declaration which can't coexist with a function * declaration. The null identifier is returned to indicate that id is * to be overridden. */ IDENTIFIER redecl_inherit(IDENTIFIER id, QUALIFIER qual, int mem, int fn) { if (!IS_NULL_id (id)) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (ds & dspec_alias) { if (fn && IS_id_function_etc (id)) { /* Everything is a function */ return (id); } if (mem && IS_id_class_name (id)) { /* Allow for injected type names */ if (ds & dspec_implicit) return (id); } if (qual == qual_none) { /* New declaration */ PTR (LOCATION) loc = id_loc (id); report (decl_loc, ERR_dcl_nspace_udecl_multi (id, loc)); return (NULL_id); } } if (ds & dspec_inherit) { NAMESPACE ns; if (mem) return (NULL_id); ns = DEREF_nspace (id_parent (id)); id = DEREF_id (id_alias (id)); report (decl_loc, ERR_lookup_qual_decl (id, ns)); } } return (id); } /* * COPY AN IDENTIFIER * * This routine creates a copy of the identifier id. If type is 1 * then any type components in id are copied using copy_typedef, if it * is 2 they are further expanded using expand_type. */ IDENTIFIER copy_id(IDENTIFIER id, int type) { TYPE t; ulong no; ulong dno; HASHID nm; unsigned tag; LOCATION loc; NAMESPACE ns; DECL_SPEC ds; IDENTIFIER lid; IDENTIFIER cid = id; /* Examine various cases */ if (IS_NULL_id (cid)) return (NULL_id); tag = TAG_id (cid); switch (tag) { case id_class_name_tag : case id_class_alias_tag : case id_enum_name_tag : case id_enum_alias_tag : case id_type_alias_tag : { /* Types */ BASE_TYPE bt; DECONS_id_class_name_etc (nm, ds, ns, loc, lid, no, dno, t, bt, cid); if (type) { t = copy_typedef (cid, t, cv_none); if (type == 2) { t = expand_type (t, 1); if (tag == id_class_name_tag) { /* Name already copied by copy_class */ CLASS_TYPE ct; while (IS_type_templ (t)) { t = DEREF_type (type_templ_defn (t)); } ct = DEREF_ctype (type_compound_defn (t)); cid = DEREF_id (ctype_name (ct)); if (!EQ_id (cid, id)) { COPY_hashid (id_name (cid), nm); COPY_dspec (id_storage (cid), ds); COPY_nspace (id_parent (cid), ns); COPY_loc (id_loc (cid), loc); break; } } if (tag != id_enum_name_tag) { /* Find type alias tag */ unsigned ta = type_tag (t); if (ta == type_compound_tag) { tag = id_class_alias_tag; } else if (ta == type_enumerate_tag) { tag = id_enum_alias_tag; } else { tag = id_type_alias_tag; } } } } MAKE_id_class_name_etc (tag, nm, ds, ns, loc, t, cid); COPY_btype (id_class_name_etc_rep (cid), bt); break; } case id_variable_tag : case id_parameter_tag : case id_stat_member_tag : { /* Objects */ EXP a, b; DECONS_id_variable_etc (nm, ds, ns, loc, lid, no, dno, t, a, b, cid); if (type) { t = copy_typedef (cid, t, cv_none); if (type == 2) t = expand_type (t, 1); } MAKE_id_variable_etc (tag, nm, ds, ns, loc, t, cid); COPY_exp (id_variable_etc_init (cid), a); COPY_exp (id_variable_etc_term (cid), b); break; } case id_function_tag : case id_mem_func_tag : case id_stat_mem_func_tag : { /* Functions */ EXP a; TYPE form; IDENTIFIER over; LIST (CLASS_TYPE) fr; int idef; IDENTIFIER sdef, sref; DECONS_id_function_etc (nm, ds, ns, loc, lid, no, dno, t, over, form, fr, idef, sdef, sref, a, cid); if (type) { t = copy_typedef (cid, t, cv_none); if (type == 2) t = expand_type (t, 1); } MAKE_id_function_etc (tag, nm, ds, ns, loc, t, over, cid); COPY_type (id_function_etc_form (cid), form); COPY_int (id_function_etc_inline_def (cid), idef); COPY_id (id_function_etc_static_def (cid), sdef); COPY_id (id_function_etc_static_ref (cid), sref); COPY_exp (id_function_etc_defn (cid), a); if (type == 2) { /* Copy friend classes */ while (!IS_NULL_list (fr)) { TYPE r = NULL_type; CLASS_TYPE cr = DEREF_ctype (HEAD_list (fr)); cr = expand_ctype (cr, 2, &r); friend_function (cr, cid, 0); fr = TAIL_list (fr); } } else { COPY_list (id_function_etc_chums (cid), fr); } break; } case id_member_tag : { /* Members */ GRAPH gr; OFFSET off; DECONS_id_member (nm, ds, ns, loc, lid, no, dno, t, off, gr, cid); if (type) { t = copy_typedef (cid, t, cv_none); if (type == 2) { if (IS_hashid_anon (nm)) { /* Allow for anonymous bitfields */ expand_anon_bitfield = 1; } t = expand_type (t, 1); expand_anon_bitfield = 0; } } MAKE_id_member (nm, ds, ns, loc, t, cid); COPY_graph (id_member_base (cid), gr); COPY_off (id_member_off (cid), off); break; } case id_enumerator_tag : { /* Enumerators */ EXP a; ERROR err = NULL_err; DECONS_id_enumerator (nm, ds, ns, loc, lid, no, dno, t, a, cid); if (type == 2) { /* Copy enumerator value */ TYPE s = expand_type (t, 1); a = copy_exp (a, t, s); IGNORE make_nat_exp (a, &err); t = s; } MAKE_id_enumerator (nm, ds, ns, loc, t, a, cid); if (!IS_NULL_err (err)) { err = concat_error (err, ERR_dcl_enum_const (cid)); report (crt_loc, err); } break; } case id_token_tag : { /* Tokens */ TOKEN sort; IDENTIFIER alt; DECONS_id_token (nm, ds, ns, loc, lid, no, dno, sort, alt, cid); if (type == 2) { /* Expand token sort */ sort = expand_sort (sort, 1, 1); } MAKE_id_token (nm, ds, ns, loc, sort, alt, cid); break; } default : { /* Don't copy other identifiers */ return (cid); } } if (type != 2) { COPY_id (id_alias (cid), lid); COPY_ulong (id_no (cid), no); COPY_ulong (id_dump (cid), dno); } return (cid); } /* * CREATE AN IDENTIFIER ALIAS * * This routine creates an alias for the identifier id in the namespace * ns. fn gives a list of function which the alias will overload if * it is a function. */ IDENTIFIER alias_id(IDENTIFIER id, NAMESPACE ns, IDENTIFIER fn, int rec) { IDENTIFIER cid = copy_id (id, 1); if (!EQ_id (cid, id)) { DECL_SPEC ds = DEREF_dspec (id_storage (cid)); DECL_SPEC acc = (ds & dspec_access); if (acc) { IDENTIFIER sid = DEREF_id (nspace_name (ns)); immediate_access (sid, cid); } ds = ((ds & ~dspec_access) | dspec_alias | crt_access); COPY_dspec (id_storage (cid), ds); COPY_nspace (id_parent (cid), ns); if (do_dump) dump_alias (cid, id, &crt_loc); if (IS_id_function_etc (cid)) { /* Deal with overloaded functions */ IDENTIFIER over; if (rec) { over = DEREF_id (id_function_etc_over (cid)); if (IS_NULL_id (over)) { over = fn; } else { over = alias_id (over, ns, fn, rec); } } else { over = fn; } COPY_id (id_function_etc_over (cid), over); } } return (cid); } /* * DUMMY DECLARATION SPECIFIER * * This value is used as a dummy declaration specifier in the adjusting * of overloaded functions. */ #define dspec_mark ((DECL_SPEC) 0x7fffffff) /* * REMOVE HIDDEN FUNCTIONS * * This routine adjusts the set of overloaded functions id by removing * any with storage field equal to dspec_mark. */ static IDENTIFIER remove_functions(IDENTIFIER id) { if (!IS_NULL_id (id)) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); IDENTIFIER over = DEREF_id (id_function_etc_over (id)); over = remove_functions (over); if (ds == dspec_mark) { id = over; } else { COPY_id (id_function_etc_over (id), over); } } return (id); } /* * COMPARE HIDING FUNCTIONS * * This routine compares two functions id and over, one declared in the * normal fashion and the other by a using-declaration. It returns * true if the former overrides the latter. */ static int compare_functions(IDENTIFIER id, IDENTIFIER over, int mem) { TYPE t = DEREF_type (id_function_etc_type (id)); TYPE s = DEREF_type (id_function_etc_type (over)); int eq = eq_func_type (t, s, 1, 0); if (eq) { /* Equal parameter types */ if (mem) return (1); } if (eq >= 2) { /* Equal types */ PTR (LOCATION) loc = id_loc (over); report (crt_loc, ERR_dcl_nspace_udecl_multi (over, loc)); return (1); } return (0); } /* * MARK HIDDEN FUNCTIONS * * This routine marks any functions which hide, or are hidden by, id in * its set of overloaded functions. mem is true for member functions. * Any hidden function is marked by setting its storage field to the * value dspec_mark. */ static int mark_functions(IDENTIFIER id, int mem) { int ret = 0; DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (ds != dspec_mark) { IDENTIFIER over = DEREF_id (id_function_etc_over (id)); while (!IS_NULL_id (over)) { DECL_SPEC pds = DEREF_dspec (id_storage (over)); if (pds != dspec_mark) { if (ds & dspec_alias) { if (pds & dspec_alias) { /* Both are using declarations */ IDENTIFIER a = DEREF_id (id_alias (id)); IDENTIFIER b = DEREF_id (id_alias (over)); if (EQ_id (a, b)) { /* Duplicate declarations */ if (mem) { ERROR err; PTR (LOCATION) loc = id_loc (over); err = ERR_class_mem_redecl (over, loc); report (crt_loc, err); } COPY_dspec (id_storage (over), dspec_mark); ret++; } } else { /* The first is a using declaration */ if (compare_functions (id, over, mem)) { COPY_dspec (id_storage (id), dspec_mark); ret++; } } } else if (pds & dspec_alias) { /* The second is a using declaration */ if (compare_functions (id, over, mem)) { COPY_dspec (id_storage (over), dspec_mark); ret++; break; } } } over = DEREF_id (id_function_etc_over (over)); } } return (ret); } /* * HANDLE HIDDEN FUNCTIONS WITH USING DECLARATIONS * * The interaction of using declarations with the hiding and overriding * of member functions is somewhat complex. It is implemented by this * routine which adjusts the declarations of the overloaded functions id * up to the existing declarations over. mem is true for member functions. */ IDENTIFIER hide_functions(IDENTIFIER id, IDENTIFIER over, int mem) { if (!IS_NULL_id (over)) { int marked = 0; IDENTIFIER pid = id; while (!EQ_id (pid, over)) { marked += mark_functions (pid, mem); pid = DEREF_id (id_function_etc_over (pid)); } if (marked) id = remove_functions (id); pid = id; while (!IS_NULL_id (pid)) { /* Mark template functions */ DECL_SPEC ds = DEREF_dspec (id_storage (pid)); if (ds & dspec_template) { templ_func_decl (id); break; } pid = DEREF_id (id_function_etc_over (pid)); } } return (id); } /* * CHECK THE VISIBILITY OF AN IDENTIFIER * * A member name in a using declaration should be visible from a direct * base class. This routine checks whether the member id meets this * criterion by comparing it with its look-up in the direct base * classes, pid. */ static int using_visible(IDENTIFIER id, IDENTIFIER pid) { while (!IS_NULL_id (pid)) { IDENTIFIER qid = DEREF_id (id_alias (pid)); if (EQ_id (qid, id)) return (1); switch (TAG_id (pid)) { case id_function_tag : case id_mem_func_tag : case id_stat_mem_func_tag : { /* Check overloaded functions */ pid = DEREF_id (id_function_etc_over (pid)); break; } case id_ambig_tag : { /* Check ambiguous identifiers */ LIST (IDENTIFIER) pids; pids = DEREF_list (id_ambig_ids (pid)); while (!IS_NULL_list (pids)) { pid = DEREF_id (HEAD_list (pids)); if (using_visible (id, pid)) return (1); pids = TAIL_list (pids); } return (0); } default : { /* Other identifiers */ return (0); } } } return (0); } /* * PROCESS A CLASS USING DECLARATION * * This routine processes a using-declaration of the identifier id in * the case when this declaration is a member-declaration. */ static IDENTIFIER using_member(IDENTIFIER id, int type) { MEMBER mem; IDENTIFIER aid; IDENTIFIER pid; /* Check the identifier */ NAMESPACE cns = crt_namespace; HASHID nm = DEREF_hashid (id_name (id)); GRAPH gr = is_subfield (cns, id); if (IS_NULL_graph (gr)) { /* id is not a member of a base class */ CLASS_TYPE ct = crt_class; report (crt_loc, ERR_dcl_nspace_udecl_base (id, ct)); return (NULL_id); } else { GRAPH gu = DEREF_graph (graph_up (gr)); GRAPH gt = DEREF_graph (graph_top (gr)); if (EQ_graph (gt, gr)) { /* id is a member of the current class */ report (crt_loc, ERR_dcl_nspace_udecl_mem (id)); return (id); } if (!EQ_graph (gt, gu)) { /* Not a member of a direct base class */ IDENTIFIER bid = search_base_field (cns, nm, type, 0); aid = id; while (!IS_NULL_id (aid)) { IDENTIFIER qid = find_template (aid, 1); if (IS_NULL_id (qid)) qid = aid; qid = DEREF_id (id_alias (qid)); if (!using_visible (qid, bid)) { CLASS_TYPE ct = crt_class; report (crt_loc, ERR_dcl_nspace_udecl_vis (aid, ct)); break; } if (!IS_id_function_etc (aid)) break; aid = DEREF_id (id_function_etc_over (aid)); } } } /* Check declarations */ mem = search_member (cns, nm, 1); if (type) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (ds & dspec_template) { pid = DEREF_id (member_id (mem)); } else { pid = type_member (mem, 3); } } else { pid = DEREF_id (member_id (mem)); if (!IS_NULL_id (pid) && is_tagged_type (pid)) { /* Allow hiding of non-template classes */ DECL_SPEC ds = DEREF_dspec (id_storage (pid)); if (!(ds & dspec_template)) pid = NULL_id; } } if (!IS_NULL_id (pid)) { DECL_SPEC ds = DEREF_dspec (id_storage (pid)); if ((ds & dspec_inherit) && !(ds & dspec_alias)) { /* Ignore inherited members */ pid = NULL_id; } else { IDENTIFIER rid = DEREF_id (id_alias (id)); IDENTIFIER qid = DEREF_id (id_alias (pid)); if (EQ_id (rid, qid)) { /* Redeclaration of existing meaning */ if (!type) { PTR (LOCATION) loc = id_loc (pid); ERROR err = ERR_class_mem_redecl (pid, loc); report (crt_loc, err); } adjust_access (pid, crt_access, 1); return (pid); } if (IS_id_function_etc (id) && IS_id_function_etc (pid)) { /* Both new and old meanings are functions */ /* EMPTY */ } else { /* One meaning is not a function */ PTR (LOCATION) loc = id_loc (pid); ERROR err = ERR_dcl_nspace_udecl_multi (pid, loc); report (crt_loc, err); return (NULL_id); } } } /* Find inherited member */ id = search_subfield (cns, gr, id); aid = alias_id (id, cns, pid, 1); if (!IS_NULL_id (pid)) { /* Deal with function hiding */ aid = hide_functions (aid, pid, 1); } adjust_access (id, crt_access, 1); if (type) { set_type_member (mem, aid); } else { set_member (mem, aid); } return (aid); } /* * PROCESS A NAMESPACE USING DECLARATION * * This routine processes a using-declaration of the identifier id in * the case when this declaration is not a member-declaration. */ static IDENTIFIER using_name(IDENTIFIER id) { int type; HASHID nm; MEMBER mem; IDENTIFIER pid; /* Check the identifier */ NAMESPACE cns = crt_namespace; NAMESPACE ns = DEREF_nspace (id_parent (id)); if (IS_nspace_ctype (ns)) { /* id denotes a class member */ report (crt_loc, ERR_dcl_nspace_udecl_id (id)); switch (TAG_id (id)) { case id_member_tag : case id_stat_member_tag : case id_mem_func_tag : case id_stat_mem_func_tag : { /* Don't even try in these cases */ return (NULL_id); } } } /* Check declarations */ nm = DEREF_hashid (id_name (id)); mem = search_member (cns, nm, 1); type = is_tagged_type (id); if (type) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (ds & dspec_template) { pid = DEREF_id (member_id (mem)); } else { pid = type_member (mem, 3); } } else { pid = DEREF_id (member_id (mem)); if (!IS_id_nspace_name_etc (id)) { if (!IS_NULL_id (pid) && is_tagged_type (pid)) { /* Allow hiding of non-template classes */ DECL_SPEC ds = DEREF_dspec (id_storage (pid)); if (!(ds & dspec_template)) pid = NULL_id; } } } if (!IS_NULL_id (pid)) { IDENTIFIER qid = DEREF_id (id_alias (pid)); if (EQ_id (id, qid)) { /* Redeclaration of existing meaning */ if (EQ_id (id, pid)) { report (crt_loc, ERR_dcl_nspace_udecl_mem (id)); } return (pid); } if (IS_id_function_etc (id) && IS_id_function_etc (pid)) { /* Both new and old meanings are functions */ /* EMPTY */ } else { /* Invalid redeclaration */ PTR (LOCATION) loc = id_loc (pid); ERROR err = ERR_dcl_nspace_udecl_multi (pid, loc); report (crt_loc, err); pid = NULL_id; } } /* Create the alias */ id = alias_id (id, cns, pid, 1); if (!IS_NULL_id (pid)) { /* Deal with function hiding */ id = hide_functions (id, pid, 0); } if (type) { set_type_member (mem, id); } else { set_member (mem, id); } return (id); } /* * PROCESS A USING DECLARATION * * This routine processes a using-declaration of the identifier id. Note * that this includes the access declarations used to modify access to * class members. */ IDENTIFIER using_identifier(IDENTIFIER id) { /* Identifier must be qualified */ MEMBER mem; HASHID unm; IDENTIFIER cid; IDENTIFIER uid = id; NAMESPACE uns = DEREF_nspace (id_parent (uid)); uid = constr_name (uns, uid); unm = DEREF_hashid (id_name (uid)); if (crt_id_qualifier == qual_none) { report (crt_loc, ERR_dcl_nspace_udecl_unqual ()); return (uid); } /* Report undefined and ambiguous identifiers */ switch (TAG_id (uid)) { case id_ambig_tag : { /* Introduce all the ambiguous meanings */ LIST (IDENTIFIER) pids = DEREF_list (id_ambig_ids (uid)); while (!IS_NULL_list (pids)) { IDENTIFIER pid = DEREF_id (HEAD_list (pids)); IGNORE using_identifier (pid); pids = TAIL_list (pids); } uid = find_qual_id (crt_namespace, unm, 0, 0); return (uid); } case id_undef_tag : { /* Report undeclared identifiers */ report (crt_loc, ERR_lookup_qual_undef (unm, uns)); return (uid); } } /* Can have constructors or destructors */ switch (TAG_hashid (unm)) { case hashid_constr_tag : case hashid_destr_tag : { report (crt_loc, ERR_dcl_nspace_udecl_constr (uid)); return (uid); } } /* Check for hidden type names */ mem = search_member (uns, unm, 0); cid = type_member (mem, 1); if (EQ_id (cid, uid)) cid = NULL_id; /* Process the declaration */ if (in_class_defn) { if (!IS_NULL_id (cid)) { IGNORE using_member (cid, 1); } uid = using_member (uid, 0); } else { if (!IS_NULL_id (cid)) { cid = DEREF_id (id_alias (cid)); IGNORE using_name (cid); } uid = DEREF_id (id_alias (uid)); uid = using_name (uid); } if (IS_NULL_id (uid)) { uid = id; } else { /* Check for hiding */ if (option (OPT_decl_hide)) { switch (TAG_id (id)) { case id_variable_tag : case id_function_tag : { check_hiding (uid); break; } } } } return (uid); } /* * PROCESS A USING TYPENAME DECLARATION * * This routine processes a using-declaration involving the type t * declared using typename. */ void using_typename(TYPE t) { UNUSED (t); return; } /* * REDECLARE AN IDENTIFIER * * This routine redeclares the identifier id in the namespace ns. */ IDENTIFIER redeclare_id(NAMESPACE ns, IDENTIFIER id) { IDENTIFIER old_id; int cl = is_tagged_type (id); HASHID nm = DEREF_hashid (id_name (id)); MEMBER mem = search_member (ns, nm, 1); DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (cl) { old_id = type_member (mem, 3); } else { old_id = DEREF_id (member_id (mem)); } if (!IS_NULL_id (old_id)) { PTR (LOCATION) loc = id_loc (old_id); report (crt_loc, ERR_basic_odr_decl (old_id, loc)); } if (cl) { set_type_member (mem, id); } else { set_member (mem, id); } ds |= dspec_reserve; COPY_dspec (id_storage (id), ds); COPY_nspace (id_parent (id), ns); return (id); } /* * CHECK ANONYMOUS UNION MEMBER * * This routine checks whether the identifier id is member of an * anonymous union. */ int is_anon_member(IDENTIFIER id) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (ds & dspec_reserve) { IDENTIFIER pid = DEREF_id (id_alias (id)); if (!EQ_id (pid, id)) { TYPE s = DEREF_type (id_variable_etc_type (pid)); if (IS_type_compound (s)) { TYPE t = DEREF_type (id_variable_etc_type (id)); if (!eq_type (s, t)) return (1); } } } return (0); } /* * REDECLARE A MEMBER OF AN ANONYMOUS UNION * * This routine redeclares the member id of an anonymous union. The * remaining arguments are as in redecl_anon_union. */ static IDENTIFIER redecl_anon_member(IDENTIFIER id, CLASS_TYPE ct, DECL_SPEC ds, IDENTIFIER obj) { IDENTIFIER pid = NULL_id; HASHID nm = DEREF_hashid (id_name (id)); if (!IS_hashid_anon (nm)) { switch (TAG_id (id)) { case id_member_tag : { /* Redeclare a type member */ TYPE t = DEREF_type (id_member_type (id)); DEREF_loc (id_loc (id), crt_loc); if (IS_id_member (obj)) { NAMESPACE cns = crt_namespace; OFFSET off1 = DEREF_off (id_member_off (id)); OFFSET off2 = DEREF_off (id_member_off (obj)); id = find_id (nm); id = constr_name (cns, id); id = make_member_decl (ds, t, id, 0); MAKE_off_plus (off2, off1, off1); COPY_off (id_member_off (id), off1); } else { id = make_object_decl (ds, t, id, 0); obj = DEREF_id (id_alias (obj)); COPY_id (id_alias (id), obj); } pid = id; break; } case id_class_name_tag : { /* Redeclare a class name */ int templ = 0; CLASS_TYPE cs; TYPE t = DEREF_type (id_class_name_defn (id)); while (IS_type_templ (t)) { templ = 1; t = DEREF_type (type_templ_defn (t)); } cs = DEREF_ctype (type_compound_defn (t)); if (!eq_ctype (ct, cs)) { NAMESPACE cns = crt_namespace; if (templ) { /* Shouldn't be a template class */ LOCATION loc; DEREF_loc (id_loc (id), loc); report (loc, ERR_temp_decl_bad ()); } pid = redeclare_id (cns, id); } break; } case id_enum_name_tag : case id_class_alias_tag : case id_enum_alias_tag : case id_type_alias_tag : case id_enumerator_tag : { /* Redeclare other identifiers */ NAMESPACE cns = crt_namespace; pid = redeclare_id (cns, id); break; } } } return (pid); } /* * REDECLARE AN ANONYMOUS UNION * * This routine redeclares all the members of the anonymous union obj of * type ct in the current namespace using the declaration specifiers ds. * The routine returns false if there are no members to redeclare. The * redeclared members are added to the extra field of the namespace given * by ct. */ int redecl_anon_union(CLASS_TYPE ct, DECL_SPEC ds, IDENTIFIER obj) { int ok = 0; MEMBER mem; NAMESPACE ns; LOCATION old_loc; bad_crt_loc++; old_loc = crt_loc; ds |= dspec_reserve; crt_id_qualifier = qual_none; crt_templ_qualifier = 0; ns = DEREF_nspace (ctype_member (ct)); mem = DEREF_member (nspace_ctype_first (ns)); while (!IS_NULL_member (mem)) { IDENTIFIER id = DEREF_id (member_id (mem)); IDENTIFIER aid = DEREF_id (member_alt (mem)); if (!IS_NULL_id (aid) && !EQ_id (aid, id)) { aid = redecl_anon_member (aid, ct, ds, obj); if (!IS_NULL_id (aid)) ok = 1; } if (!IS_NULL_id (id)) { id = redecl_anon_member (id, ct, ds, obj); if (!IS_NULL_id (id)) ok = 1; } mem = DEREF_member (member_next (mem)); } crt_loc = old_loc; bad_crt_loc--; return (ok); }