/* * 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/declare.c,v 1.18 2005/11/09 17:09:47 stefanf Exp $ */ #include "config.h" #include "producer.h" #include "msgcat.h" #include "c_types.h" #include "ctype_ops.h" #include "hashid_ops.h" #include "id_ops.h" #include "loc_ext.h" #include "member_ops.h" #include "nspace_ops.h" #include "off_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 "capsule.h" #include "chktype.h" #include "class.h" #include "compile.h" #include "construct.h" #include "declare.h" #include "derive.h" #include "dump.h" #include "exception.h" #include "file.h" #include "function.h" #include "hash.h" #include "identifier.h" #include "initialise.h" #include "instance.h" #include "inttype.h" #include "namespace.h" #include "operator.h" #include "overload.h" #include "predict.h" #include "preproc.h" #include "redeclare.h" #include "syntax.h" #include "template.h" #include "tokdef.h" #include "token.h" #include "virtual.h" /* * DECLARATION LOCATION * * This variable is used to record the location of the current declaration. * This is primarily so that the location of a declaration can be set to * the location of the declarator rather than the end of the corresponding * initialiser. */ LOCATION decl_loc = NULL_loc; int is_redeclared = 0; /* * DEFAULT LINKAGE FOR INLINE FUNCTIONS AND CONST OBJECTS * * These variables give the default linkages for inline functions and * const objects and the default cv-qualifiers for external objects. */ DECL_SPEC inline_linkage = dspec_static; DECL_SPEC const_linkage = dspec_static; CV_SPEC cv_extern = cv_none; /* * DUMMY EMPTY DECLARATION SPECIFIER * * The value dspec_empty is used during the processing of declarations * to mark any declaration specifier which does not contain an explicit * specifier. The value dspec_nonempty gives those declaration * specifiers which constitute an explicit specifier. */ #define dspec_empty dspec_pure #define dspec_nonempty dspec_keyword /* * COMPLETE A DECLARATION SPECIFIER * * This routine completes the declaration specifier given by the * specifiers ds, the type t and the cv-qualifier cv. If these are * all empty then the result is marked using dspec_empty. The special * case 'extern "LANG" typedef' is checked. */ DECL_SPEC complete_dspec(DECL_SPEC ds, BASE_TYPE bt, TYPE t, CV_SPEC cv) { DECL_SPEC key = (ds & dspec_nonempty); #if LANGUAGE_C if (in_for_decl) { /* Can't have specifiers other than 'auto' or 'register' */ DECL_SPEC mask = ~(dspec_auto | dspec_register); if (ds & mask) { report (crt_loc, ERR_stmt_for_storage (ds & mask)); ds &= ~mask; } } #endif if (key || bt || !IS_NULL_type (t) || cv) { /* Have a declaration specifier */ if (ds & dspec_c) { /* Have a linkage specification */ if (ds & dspec_typedef) ds &= ~dspec_extern; ds &= ~dspec_c; } } else { ds |= dspec_empty; } return (ds); } /* * CHECK INFERRED OBJECT TYPES * * This routine checks the declaration specifiers ds and the type *p for * inferred types and empty specifier lists. It is used in object, * parameter and class member declarations. */ static DECL_SPEC check_inferred_type(DECL_SPEC ds, TYPE *p, int mem) { int infer; TYPE t = *p; int empty = 0; ERROR err = NULL_err; /* Report if there are no declaration specifiers */ if (ds & dspec_empty) { if (mem) { err = ERR_class_mem_ds_empty (); } else { err = ERR_dcl_dcl_ds_empty (); } ds &= ~dspec_empty; empty = 1; } /* Check on inferred types */ infer = is_type_inferred (t); if (infer != INFERRED_NOT) { ERROR err2; t = clean_inferred_type (t); if (empty) { err2 = ERR_dcl_type_infer (t); } else { err2 = report_inferred_type (t, infer); } err = concat_error (err, err2); *p = t; } if (!IS_NULL_err (err)) report (crt_loc, err); return (ds); } /* * CHECK INFERRED FUNCTION TYPES * * This routine checks the declaration specifiers ds and the function * type t for inferred types and empty specifier lists. It is used in * function declarations and definitions (as indicated by def). */ static DECL_SPEC check_func_type(DECL_SPEC ds, TYPE t, int def, int chk, int mem) { int empty = 0; ERROR err = NULL_err; /* Report if there are no declaration specifiers */ if (ds & dspec_empty) { if (mem) { err = ERR_class_mem_ds_empty (); } else if (def) { err = ERR_dcl_dcl_ds_func (); } else { err = ERR_dcl_dcl_ds_empty (); } ds &= ~dspec_empty; empty = 1; } /* Check for template types */ while (IS_type_templ (t)) { ds |= dspec_template; t = DEREF_type (type_templ_defn (t)); } /* Check the return type */ if (chk) { TYPE r = DEREF_type (type_func_ret (t)); int infer = is_type_inferred (r); if (infer != INFERRED_NOT) { ERROR err2; r = clean_inferred_type (r); if (empty) { err2 = ERR_dcl_type_infer (r); } else { err2 = report_inferred_type (r, infer); } err = concat_error (err, err2); COPY_type (type_func_ret (t), r); } } if (!IS_NULL_err (err)) report (crt_loc, err); return (ds); } /* * SHIFT A STORAGE CLASS * * This macro is used to shift a storage class specifier into a more * sensible range. */ #define DSPEC_STORAGE(A) ((A) >> 6) /* * CHECK STORAGE CLASS SPECIFIERS * * This routine extracts the storage class specifiers from the declaration * specifiers ds in the context given by loc. It returns a valid storage * class specifier. */ static DECL_SPEC check_storage(DECL_SPEC ds, int loc, IDENTIFIER id) { DECL_SPEC st = (ds & dspec_storage); /* Check on storage class */ switch_label : { switch (DSPEC_STORAGE (st)) { case DSPEC_STORAGE (dspec_none) : { /* No storage class given */ break; } case DSPEC_STORAGE (dspec_auto) : case DSPEC_STORAGE (dspec_register) : { /* Deal with auto and register */ switch (loc) { case CONTEXT_OBJECT : { /* Objects declared in a block are alright */ if (!in_function_defn) goto bad_auto_lab; break; } case CONTEXT_FUNCTION : { /* Functions can't be auto */ if (!in_function_defn) goto bad_auto_lab; report (crt_loc, ERR_dcl_stc_auto_func (st)); st = dspec_none; break; } case CONTEXT_PARAMETER : case CONTEXT_WEAK_PARAM : { /* Function parameters are alright */ if (st == dspec_auto) { /* Can't have auto parameters in C */ report (crt_loc, ERR_dcl_stc_auto_par ()); } break; } case CONTEXT_TEMPL_PARAM : { /* Template parameters can't have storage class */ report (crt_loc, ERR_temp_param_dcl_stc (st)); st = dspec_none; break; } default : bad_auto_lab : { /* Anything outside a block can't be auto */ report (crt_loc, ERR_dcl_stc_auto_bad (st)); st = dspec_none; break; } } break; } case DSPEC_STORAGE (dspec_static) : { /* Deal with static */ switch (loc) { case CONTEXT_PARAMETER : case CONTEXT_WEAK_PARAM : { /* Function parameters can't be static */ report (crt_loc, ERR_dcl_stc_param (st)); st = dspec_none; break; } case CONTEXT_TEMPL_PARAM : { /* Template parameters can't have storage class */ report (crt_loc, ERR_temp_param_dcl_stc (st)); st = dspec_none; break; } } break; } case DSPEC_STORAGE (dspec_extern) : { /* Deal with extern */ switch (loc) { case CONTEXT_OBJECT : case CONTEXT_FUNCTION : { /* Objects and functions can be extern */ if (!IS_NULL_id (id)) { switch (TAG_id (id)) { case id_member_tag : case id_mem_func_tag : case id_stat_member_tag : case id_stat_mem_func_tag : { /* But not class members */ ERROR err = ERR_dcl_stc_ext_mem (); report (crt_loc, err); break; } } } break; } case CONTEXT_PARAMETER : case CONTEXT_WEAK_PARAM : { /* Function parameters can't be extern */ report (crt_loc, ERR_dcl_stc_param (st)); st = dspec_none; break; } case CONTEXT_TEMPL_PARAM : { /* Template parameters can't have storage class */ report (crt_loc, ERR_temp_param_dcl_stc (st)); st = dspec_none; break; } default : { /* Class members can't be extern */ report (crt_loc, ERR_dcl_stc_ext_mem ()); st = dspec_none; break; } } break; } case DSPEC_STORAGE (dspec_mutable) : { /* Deal with mutable */ if (loc != CONTEXT_MEMBER) { /* Only data members can be mutable */ report (crt_loc, ERR_dcl_stc_mut_bad ()); st = dspec_none; } break; } default : { /* More than one storage class - select one */ DECL_SPEC nst = dspec_static; while (!(st & nst)) { ASSERT (nst != dspec_none); nst <<= 1; } report (crt_loc, ERR_dcl_stc_dup (st, nst)); st = nst; goto switch_label; } } } return (st); } /* * CHECK STORAGE CLASS SPECIFIERS * * This routine extracts the function specifiers (plus friend specifiers) * from the declaration specifiers ds in the context given by loc (as * above). It returns a valid combination of function and friend * specifiers. */ static DECL_SPEC check_func_spec(DECL_SPEC ds, int loc) { DECL_SPEC fn = dspec_none; /* Only functions can be inline */ if (ds & dspec_inline) { if (loc == CONTEXT_FUNCTION || loc == CONTEXT_FUNC_MEMBER) { fn |= dspec_inline; } else { report (crt_loc, ERR_dcl_fct_spec_inline_bad ()); } } /* Only function members can be virtual */ if (ds & dspec_virtual) { if (loc == CONTEXT_FUNC_MEMBER) { fn |= dspec_virtual; } else { report (crt_loc, ERR_dcl_fct_spec_virtual ()); } } /* Only function members can be explicit */ if (ds & dspec_explicit) { if (loc == CONTEXT_FUNC_MEMBER) { fn |= dspec_explicit; } else { report (crt_loc, ERR_dcl_fct_spec_explicit ()); } } /* Only functions declared in a class can be friends */ if (ds & dspec_friend) { if (loc == CONTEXT_FUNCTION && in_class_defn) { /* Don't add to specifier list */ /* EMPTY */ } else if (in_class_defn) { report (crt_loc, ERR_class_friend_decl ()); } else { report (crt_loc, ERR_dcl_friend_class ()); } } /* Allow for function discarding */ if (loc == CONTEXT_FUNCTION || loc == CONTEXT_FUNC_MEMBER) { fn |= dspec_ignore; } return (fn); } /* * CONSTRUCT A TYPE DECLARATION * * This routine constructs the declaration of a type with declaration * specifiers ds (which will include typedef), type t and name id in the * namespace ns. mem gives the member of ns corresponding to id or the * null member for class member redeclarations. */ static IDENTIFIER make_type_decl(NAMESPACE ns, DECL_SPEC ds, TYPE t, MEMBER mem, IDENTIFIER id) { int reported = 0; IDENTIFIER old_id; unsigned tag = TAG_type (t); QUALIFIER cq = crt_id_qualifier; HASHID nm = DEREF_hashid (id_name (id)); /* Can't have other declaration specifiers with typedef */ DECL_SPEC st = (ds & dspec_keyword); if (st != dspec_typedef) { st &= ~dspec_typedef; report (crt_loc, ERR_dcl_typedef_dspec (st)); } /* Check for function cv-qualifiers and exception specifiers */ object_type (t, id_type_alias_tag); /* Check for previous declaration */ if (IS_NULL_member (mem)) { mem = search_member (ns, nm, 1); old_id = DEREF_id (member_id (mem)); old_id = redecl_inherit (old_id, cq, in_class_defn, 2); if (IS_NULL_id (old_id)) { report (crt_loc, ERR_lookup_qual_undef (nm, ns)); } } else { old_id = DEREF_id (member_id (mem)); old_id = redecl_inherit (old_id, cq, in_class_defn, 2); } /* Allow for type redeclarations */ #if LANGUAGE_CPP id = type_member (mem, 3); id = redecl_inherit (id, cq, in_class_defn, 2); #else id = old_id; #endif if (!IS_NULL_id (id) && IS_id_class_name_etc (id)) { /* Already declared as a type name */ TYPE s; ERROR err = NULL_err; PTR (LOCATION) loc = id_loc (id); unsigned long tokdefs = no_token_defns; /* Check for reserved identifiers */ DECL_SPEC ods = DEREF_dspec (id_storage (id)); if ((ds | ods) & dspec_reserve) { report (crt_loc, ERR_basic_odr_decl (id, loc)); return (id); } /* Check type compatibility */ s = DEREF_type (id_class_name_etc_defn (id)); s = check_compatible (s, t, 0, &err, 1); /* QUERY: or is type equality required? */ /* Compatible redefinition */ if (IS_NULL_err (err)) { NAMESPACE cns = crt_namespace; if (cq != qual_none) { /* Check qualified definitions */ check_decl_nspace (id, ns, 1, cns); } if (in_class_defn && EQ_nspace (ns, cns)) { if (!is_tagged_type (id)) { /* Still not allowed in a class definition */ report (crt_loc, ERR_class_mem_redecl (id, loc)); } } else if (tokdefs == no_token_defns && !in_pragma_dir) { /* Can't redeclare types in C */ report (crt_loc, ERR_basic_odr_typedef (id, loc)); } if (tag == type_func_tag) { /* Check function types */ s = redecl_func_type (id, s, t, 0, 1); } COPY_type (id_class_name_etc_defn (id), s); adjust_access (id, crt_access, 0); return (id); } /* Incompatible redefinition */ err = concat_error (err, ERR_basic_link_typedef (id, loc)); report (crt_loc, err); reported = 1; } /* Declare the type */ id = make_typedef (ns, nm, t, dspec_none); if (is_tagged_type (id)) { /* Class-like typedef-names */ set_type_member (mem, id); } else { /* Object-like typedef-names */ if (!IS_NULL_id (old_id) && !reported) { /* Already declared as an object */ PTR (LOCATION) loc = id_loc (old_id); report (crt_loc, ERR_basic_odr_diff (old_id, loc)); } set_member (mem, id); } if (tag == type_func_tag) { /* Check function type */ decl_func_type (id, t, 0); } else if (tag == type_templ_tag) { IGNORE check_templ_params (t, id); report (crt_loc, ERR_temp_decl_bad ()); } return (id); } /* * CREATE A SPECIAL TYPE DEFINITION * * This routine creates a typedef of the identifier id to the special * type t. */ void typedef_special(IDENTIFIER id, TYPE t) { int pushed = 0; NAMESPACE ns = nonblock_namespace; if (!EQ_nspace (ns, crt_namespace)) { push_namespace (ns); pushed = 1; } decl_loc = preproc_loc; if (in_class_defn) { id = make_member_decl (dspec_typedef, t, id, 0); } else { id = make_object_decl (dspec_typedef, t, id, 0); } if (do_dump) dump_declare (id, &decl_loc, 1); if (pushed) { IGNORE pop_namespace (); } return; } /* * FIND THE LINKAGE OF AN IDENTIFIER * * This routine finds the linkage of the identifier id (including the * language specifier), returning the default value st if id does not * represent an object or function. */ static DECL_SPEC find_storage(IDENTIFIER id, DECL_SPEC st, TYPE t) { if (!IS_NULL_id (id)) { switch (TAG_id (id)) { case id_variable_tag : case id_parameter_tag : case id_stat_member_tag : case id_weak_param_tag : { /* Objects */ DECL_SPEC ds = DEREF_dspec (id_storage (id)); st = (ds & (dspec_storage | dspec_language)); break; } case id_function_tag : case id_mem_func_tag : case id_stat_mem_func_tag : { /* Functions */ DECL_SPEC ds; #if LANGUAGE_CPP LIST (IDENTIFIER) pids = NULL_list (IDENTIFIER); if (!IS_NULL_type (t)) { int eq = 0; id = resolve_func (id, t, 0, 0, pids, &eq); if (IS_NULL_id (id) || !IS_id_function_etc (id)) { return (st); } } #else UNUSED (t); #endif ds = DEREF_dspec (id_storage (id)); st = (ds & (dspec_storage | dspec_language)); break; } } } return (st); } /* * CHECK THE LOCATION OF A DECLARATION * * This routine checks whether the namespace cns is a suitable location * for redeclaring the object id, which is a member of the namespace ns. * def is true for a definition. */ void check_decl_nspace(IDENTIFIER id, NAMESPACE ns, int def, NAMESPACE cns) { int func = 0; int local_def = really_in_function_defn; switch (TAG_id (id)) { 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 : { /* Can define local types */ local_def = 0; break; } case id_mem_func_tag : case id_stat_mem_func_tag : { /* Member function */ DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (ds & dspec_implicit) { /* Ignore implicit constructors etc */ return; } if (!def && !is_templ_nspace (ns)) { /* Can't even redeclare in this case */ report (crt_loc, ERR_class_mfct_redecl (id)); return; } func = 1; break; } case id_undef_tag : { /* Report undeclared members */ HASHID nm = DEREF_hashid (id_name (id)); report (crt_loc, ERR_lookup_qual_undef (nm, ns)); return; } } if (def) { /* Check for enclosing namespace scope */ if (local_def || !is_subnspace (cns, ns)) { /* Report badly placed definition */ ERROR err; if (IS_nspace_ctype (ns)) { if (func) { /* Member functions */ err = ERR_class_mfct_scope (id); } else { /* Other class members */ err = ERR_class_static_data_scope (id); } } else { /* Namespace members */ err = ERR_dcl_nspace_memdef_scope (id); } report (crt_loc, err); } } return; } /* * CHECK AN OBJECT TYPE * * This routine checks the type t for the object id with declaration * specifiers ds. */ void check_obj_decl(DECL_SPEC ds, TYPE t, IDENTIFIER id, int tentative) { unsigned tag = TAG_type (t); if (tag == type_top_tag || tag == type_bottom_tag) { /* Always report void declarations */ report (crt_loc, ERR_basic_fund_void_decl (id, t)); } else if (tag == type_templ_tag) { /* Shouldn't have template type */ report (crt_loc, ERR_temp_decl_bad ()); } else if (ds & dspec_defn) { /* Only check otherwise if this is a definition */ if (tag == type_array_tag) { /* Arrays may be completed by the initialiser */ /* EMPTY */ } else if (tag == type_ref_tag) { /* References don't need checking */ /* EMPTY */ } else { ERROR err; /* Tentative definitions with internal linkage must have * complete type. */ if (!tentative || (ds & dspec_static)) { err = check_complete (t); if (!IS_NULL_err (err)) { /* Other definitions should have complete type */ ERROR err2 = ERR_basic_types_def_incompl (id); err = concat_error (err, err2); report (crt_loc, err); } } err = check_abstract (t); if (!IS_NULL_err (err)) { /* Objects can't have abstract type */ ERROR err2 = ERR_class_abstract_decl (id); err = concat_error (err, err2); report (crt_loc, err); } } } return; } /* * DECLARE AN OBJECT * * This routine constructs the declaration of an object with declaration * specifiers ds, type t and name id. */ IDENTIFIER make_object_decl(DECL_SPEC ds, TYPE t, IDENTIFIER id, int def) { ERROR err; MEMBER mem; NAMESPACE ns; int redef = 0; int simple_id = 1; int tentative = 0; IDENTIFIER old_id; IDENTIFIER alt_id; DECL_SPEC st, df, rs; IDENTIFIER prev_id = NULL_id; unsigned tag = TAG_type (t); unsigned itag = id_variable_tag; HASHID nm = DEREF_hashid (id_name (id)); /* Check for template specialisations */ bound_specialise = 0; if (is_templ_decl (id, NULL_type) || is_templ_spec (t)) { t = bind_specialise (&id, t, ds, 0, 1, def); if (IS_NULL_id (id)) { /* Invalid specialisation */ crt_id_qualifier = qual_none; crt_templ_qualifier = 0; id = DEREF_id (hashid_id (nm)); while (IS_type_templ (t)) { t = DEREF_type (type_templ_defn (t)); } id = make_object_decl (ds, t, id, def); return (id); } ns = DEREF_nspace (id_parent (id)); check_decl_nspace (id, ns, 0, crt_namespace); old_id = id; mem = NULL_member; simple_id = 0; } else { /* Check on identifier name */ QUALIFIER cq = crt_id_qualifier; err = check_id_name (id, CONTEXT_OBJECT); if (!IS_NULL_err (err)) report (crt_loc, err); /* Check for qualified identifiers */ if (cq == qual_none) { /* Declaration of simple identifier */ ns = crt_namespace; mem = search_member (ns, nm, 1); old_id = DEREF_id (member_id (mem)); alt_id = DEREF_id (member_alt (mem)); if (!IS_NULL_id (old_id)) { if (in_function_defn && (ds & dspec_extern)) { /* Redeclaration of block external */ prev_id = find_previous (t, id); if (EQ_id (prev_id, old_id)) old_id = NULL_id; } else { old_id = redecl_inherit (old_id, cq, 0, 2); } redef = 1; } else if (!IS_NULL_id (alt_id)) { redef = 1; } } else { /* Redeclaration of class or namespace member */ ns = DEREF_nspace (id_parent (id)); check_decl_nspace (id, ns, 0, crt_namespace); if (IS_id_undef (id)) { if (IS_nspace_ctype (ns)) itag = id_stat_member_tag; mem = search_member (ns, nm, 1); old_id = NULL_id; } else { mem = NULL_member; old_id = redecl_inherit (id, cq, 0, 2); t = bind_specialise (&old_id, t, ds, 0, 0, def); if (!IS_NULL_id (old_id)) { id = old_id; itag = TAG_id (id); ns = DEREF_nspace (id_parent (id)); } } simple_id = 0; } } /* Deal with inferred types */ ds = check_inferred_type (ds, &t, 0); /* Check on storage class specifiers */ st = check_storage (ds, CONTEXT_OBJECT, old_id); /* Deal with type definitions */ if (ds & dspec_typedef) { id = make_type_decl (ns, ds, t, mem, id); return (id); } /* Check on function specifiers */ IGNORE check_func_spec (ds, CONTEXT_OBJECT); /* Find the object linkage and whether it is a definition */ if (st == dspec_extern) { /* Explicit extern indicates a declaration (probably) */ df = dspec_none; if (in_function_defn && simple_id) { if (IS_NULL_id (prev_id)) { prev_id = find_previous (t, id); } st = find_storage (prev_id, st, NULL_type); } else { prev_id = old_id; st = find_storage (old_id, st, t); } } else { if (tag == type_templ_tag && bound_specialise) { /* A template specialisation is a declaration (probably) */ df = dspec_none; } else { /* Everything else is a definition */ df = dspec_defn; } if (in_function_defn) { /* Objects declared in a block have no linkage */ if (IS_NULL_member (mem)) { /* Use old linkage if explicitly qualified */ st = find_storage (old_id, dspec_none, t); } else if (st == dspec_static) { st = dspec_none; } else if (st == dspec_register) { st = (dspec_auto | dspec_register); used_register = 1; } else { st = dspec_auto; } } else if (st == dspec_static) { /* Check static declarations */ if (!def) tentative = LANGUAGE_C; } else if (st == dspec_none) { /* Objects declared const have internal linkage */ CV_SPEC qual = find_cv_qual (t); if (qual & cv_const) { st = const_linkage; if (st & dspec_static) { st = find_storage (old_id, st, t); } } else { st = dspec_extern; } /* find_storage is not applied for objects */ if (!def) tentative = LANGUAGE_C; } } /* Create the declaration */ t = lvalue_type (t); rs = (ds & dspec_other); ds = (st | df | rs); if (!IS_NULL_id (old_id)) { /* Check redeclarations */ old_id = redecl_id (ds, t, old_id, 0, 0); if (IS_NULL_id (old_id) && IS_NULL_member (mem)) { /* Bad redeclaration of class or namespace member */ nm = lookup_anon (); mem = search_member (ns, nm, 1); itag = id_stat_member_tag; } } object_type (t, itag); if (IS_NULL_id (old_id)) { /* Construct the declaration */ ds = adjust_linkage (ds, 0); MAKE_id_variable_etc (itag, nm, ds, ns, decl_loc, t, id); if (in_function_defn) { if (ds & dspec_linkage) { /* Block function declarations */ id = unify_previous (id, t, prev_id, 0); } else if (redef) { /* Redeclarations of local variables */ mem = update_member (ns, mem); } } else { id = unify_subsequent (id, t, 0); } set_member (mem, id); if (itag == id_variable_tag && option (OPT_decl_hide)) { check_hiding (id); } is_redeclared = 0; } else { /* Redeclare an existing object */ id = old_id; if (IS_id_member (id)) { t = DEREF_type (id_member_type (id)); } else { t = DEREF_type (id_variable_etc_type (id)); } ds = DEREF_dspec (id_storage (id)); is_redeclared = 1; } #if LANGUAGE_CPP if (ds & dspec_c) c_linkage (id, 0); #endif check_obj_decl (ds, t, id, tentative); return (id); } /* * DECLARE A FUNCTION * * This routine constructs a function declaration for a function with * declaration specifiers ds, type t and name id. The argument def is * true to distinguish function definitions from function declarations. */ IDENTIFIER make_func_decl(DECL_SPEC ds, TYPE t, IDENTIFIER id, int def) { ERROR err; MEMBER mem; int ok = 1; int chk = 1; unsigned it; int simple_id = 1; int main_func = 0; IDENTIFIER old_id; NAMESPACE ns, ens; DECL_SPEC st, df, fn, rs; IDENTIFIER over_id = NULL_id; IDENTIFIER prev_id = NULL_id; unsigned itag = id_function_tag; HASHID nm = DEREF_hashid (id_name (id)); int inline_def = 0; #if LANGUAGE_CPP int allocator = 0; #endif /* Check for template specialisations */ if (is_templ_decl (id, t) || is_templ_spec (t)) { t = bind_specialise (&id, t, ds, 0, 1, def); if (IS_NULL_id (id)) { /* Invalid specialisation */ crt_id_qualifier = qual_none; crt_templ_qualifier = 0; id = DEREF_id (hashid_id (nm)); while (IS_type_templ (t)) { t = DEREF_type (type_templ_defn (t)); } id = make_func_decl (ds, t, id, def); return (id); } ns = DEREF_nspace (id_parent (id)); check_decl_nspace (id, ns, def, crt_namespace); ens = ns; mem = NULL_member; old_id = id; simple_id = 0; } else { /* Check on identifier name */ QUALIFIER cq = crt_id_qualifier; err = check_id_name (id, CONTEXT_FUNCTION); if (!IS_NULL_err (err)) { report (crt_loc, err); ok = 0; } /* Check for qualified identifiers */ if (cq == qual_none) { /* Declaration of simple identifier */ ns = crt_namespace; ens = nonblock_namespace; mem = search_member (ns, nm, 1); old_id = DEREF_id (member_id (mem)); if (!IS_NULL_id (old_id)) { old_id = redecl_inherit (old_id, cq, 0, 1); } if (def && in_function_defn) { /* Check for nested function definitions */ report (crt_loc, ERR_dcl_fct_def_scope ()); } } else { /* Redeclaration of class or namespace member */ ns = DEREF_nspace (id_parent (id)); check_decl_nspace (id, ns, def, crt_namespace); ens = ns; if (IS_id_undef (id)) { if (IS_nspace_ctype (ns)) itag = id_mem_func_tag; mem = search_member (ns, nm, 1); old_id = NULL_id; } else { mem = NULL_member; old_id = redecl_inherit (id, cq, 0, 1); t = bind_specialise (&old_id, t, ds, 0, 0, def); if (!IS_NULL_id (old_id)) { id = old_id; itag = TAG_id (id); ns = DEREF_nspace (id_parent (id)); ens = ns; } } simple_id = 0; } } /* Allow for special functions */ if (EQ_KEYWORD (nm, lex_main) && IS_nspace_global (ens)) { if (ds & dspec_typedef) { /* Ignore type definition */ /* EMPTY */ } else { t = check_main (t, nm); main_func = 1; } } it = TAG_hashid (nm); #if LANGUAGE_CPP switch (it) { case hashid_constr_tag : { t = check_constr (t, id, ns); ds &= ~dspec_empty; ds |= dspec_main; break; } case hashid_destr_tag : { t = check_destr (t, id, ns); ds &= ~dspec_empty; ds |= dspec_main; break; } case hashid_op_tag : { int cl = IS_nspace_ctype (ns); t = check_operator (t, id, cl, &allocator); if (!allocator) ds |= dspec_ignore; break; } case hashid_conv_tag : { t = check_conv (t, id); ds &= ~dspec_empty; chk = 0; break; } } #endif /* Deal with inferred types */ ds = check_func_type (ds, t, def, chk, 0); if (main_func) ds |= dspec_main; /* Handle function definitions */ df = (def ? dspec_defn : dspec_none); /* Check on storage class specifiers */ st = check_storage (ds, CONTEXT_FUNCTION, old_id); if (st == dspec_static) { /* Check on static functions */ if (main_func) { err = ERR_basic_start_main_static (nm); if (!IS_NULL_err (err)) { report (crt_loc, err); st = dspec_extern; } } else { /* Check static declarations */ /* EMPTY */ } } else if (ds & dspec_inline) { if (st != dspec_extern) inline_def = 1; /* Check on inline functions */ if (main_func) { fn = dspec_inline; report (crt_loc, ERR_basic_start_main_link (nm, fn)); ds &= ~dspec_inline; } else { if (st == dspec_extern && inline_linkage == dspec_static) { /* Inline functions can't be extern */ report (crt_loc, ERR_dcl_stc_ext_inline ()); } if (in_function_defn) { /* Can't declare inline functions in a block */ report (crt_loc, ERR_dcl_fct_spec_block ()); st = dspec_none; } } } /* Deal with type definitions */ if (ds & dspec_typedef) { /* Can only apply typedef to declarations, not definitions */ if (!def) { if (ok) { /* Recheck identifier name */ err = check_id_name (id, CONTEXT_OBJECT); if (!IS_NULL_err (err)) report (crt_loc, err); } id = make_type_decl (ns, ds, t, mem, id); return (id); } report (crt_loc, ERR_dcl_typedef_func ()); } /* Check on function specifiers */ fn = check_func_spec (ds, CONTEXT_FUNCTION); /* Find the function linkage */ if (st == dspec_extern) { if (in_function_defn && simple_id) { prev_id = find_previous (t, id); st = find_storage (prev_id, st, NULL_type); } else { prev_id = old_id; st = find_storage (old_id, st, t); } } else if (st == dspec_static) { if (in_function_defn) { /* Can't declare static functions in a block */ report (crt_loc, ERR_dcl_stc_stat_block ()); if (simple_id) { prev_id = find_previous (t, id); } else { prev_id = old_id; } } } else if (st == dspec_none) { /* Inline functions have internal linkage */ if (fn & dspec_inline) { st = inline_linkage; } else { st = dspec_extern; } if (in_function_defn) { prev_id = find_previous (t, id); st = find_storage (prev_id, st, NULL_type); } else { prev_id = old_id; st = find_storage (old_id, st, t); } } /* Create the declaration */ t = lvalue_type (t); rs = (ds & dspec_other); ds = (st | df | fn | rs); if (!IS_NULL_id (old_id)) { /* Check redeclarations */ old_id = redecl_func (ds, t, old_id, itag, &over_id, def); if (IS_NULL_id (old_id) && IS_NULL_member (mem)) { /* Bad redeclaration of class or namespace member */ nm = lookup_anon (); mem = search_member (ns, nm, 1); if (IS_nspace_ctype (ns)) itag = id_mem_func_tag; over_id = NULL_id; } } object_type (t, itag); if (IS_NULL_id (old_id)) { /* Declare the function */ ds = adjust_linkage (ds, 0); MAKE_id_function_etc (itag, nm, ds, ns, decl_loc, t, over_id, id); COPY_int (id_function_etc_inline_def (id), inline_def); if (in_function_defn) { id = unify_previous (id, t, prev_id, def); } else { id = unify_subsequent (id, t, def); } set_member (mem, id); decl_func_type (id, t, def); /* Check for conversion functions */ if (it == hashid_conv_tag && itag != id_mem_func_tag) { report (crt_loc, ERR_class_conv_fct_mem ()); } if (itag == id_function_tag && option (OPT_decl_hide)) { check_hiding (id); } is_redeclared = 0; } else { /* Redeclare the function */ id = old_id; inline_def &= DEREF_int (id_function_etc_inline_def (id)); COPY_int (id_function_etc_inline_def (id), inline_def); is_redeclared = 1; } ds = DEREF_dspec (id_storage (id)); #if LANGUAGE_CPP if (ds & dspec_c) c_linkage (id, def); #endif /* Allow for discarded functions */ if (!(rs & dspec_ignore) && option (OPT_discard_func)) { ds &= ~dspec_ignore; COPY_dspec (id_storage (id), ds); } #if LANGUAGE_CPP if (allocator) recheck_allocator (id, allocator); #endif if (main_func) recheck_main (id); return (id); } /* * CHECK A PARAMETER DECLARATION * * This routine checks the type of the parameter id declared with type t. */ void check_par_decl(TYPE t, IDENTIFIER id, int loc) { unsigned tag = TAG_type (t); if (tag == type_compound_tag) { /* Parameters can't have abstract type */ ERROR err = check_abstract (t); if (!IS_NULL_err (err)) { err = concat_error (err, ERR_class_abstract_par ()); report (crt_loc, err); } } else if (tag == type_templ_tag) { /* Shouldn't have template type */ report (crt_loc, ERR_temp_decl_bad ()); } if (loc == CONTEXT_WEAK_PARAM) { /* Check for 'void' and other types */ ERROR err = check_param_type (id, t); if (!IS_NULL_err (err)) report (crt_loc, err); } return; } /* * DECLARE A FUNCTION PARAMETER * * This routine constructs the declaration of a function parameter or * non-type template parameter (as indicated by loc) with declaration * specifiers ds, type t and name id. Note that t is not checked - this * is only a declaration, and t may still legitimately be void, however * function and array parameters are adjusted to pointer parameters at * this stage. */ IDENTIFIER make_param_decl(DECL_SPEC ds, TYPE t, IDENTIFIER id, int loc) { ERROR err; DECL_SPEC st, rs; NAMESPACE ns = crt_namespace; HASHID nm = DEREF_hashid (id_name (id)); MEMBER mem = search_member (ns, nm, 1); IDENTIFIER old_id = DEREF_id (member_id (mem)); /* Check on identifier name */ err = check_id_name (id, loc); if (!IS_NULL_err (err)) report (decl_loc, err); /* Deal with inferred types */ ds = check_inferred_type (ds, &t, 0); func_type_defn (1); /* Check on storage class specifiers */ st = check_storage (ds, loc, old_id); if (st == dspec_register) { st = (dspec_auto | dspec_register); used_register = 1; } else { st = dspec_auto; } /* Deal with type definitions */ if (ds & dspec_typedef) { /* Can't have typedef in function parameters */ report (decl_loc, ERR_dcl_typedef_par ()); } /* Check on function specifiers */ IGNORE check_func_spec (ds, loc); /* Create the parameter declaration */ t = make_param_type (t, loc); rs = (ds & dspec_other); ds = (st | rs | dspec_defn); if (!IS_NULL_id (old_id)) { /* Check for redeclarations */ if (loc == CONTEXT_TEMPL_PARAM) { report (decl_loc, ERR_temp_param_dup (nm)); nm = lookup_anon (); mem = search_member (ns, nm, 1); id = DEREF_id (hashid_id (nm)); } else { if (loc == CONTEXT_WEAK_PARAM) { if (IS_id_weak_param (old_id)) { /* Check for order of declaration */ MEMBER mem1 = DEREF_member (nspace_last (ns)); while (!EQ_member (mem1, mem)) { IDENTIFIER mid = DEREF_id (member_id (mem1)); if (!IS_NULL_id (mid) && IS_id_parameter (mid)) { report (decl_loc, ERR_dcl_fct_par_order ()); break; } mem1 = DEREF_member (member_next (mem1)); } old_id = NULL_id; } else if (!IS_id_parameter (old_id)) { report (decl_loc, ERR_dcl_fct_par_undecl (nm)); } } if (!IS_NULL_id (old_id)) { if (IS_id_parameter (old_id)) { /* Make up new name for parameter */ nm = lookup_anon (); mem = search_member (ns, nm, 1); } IGNORE redecl_id (ds, t, old_id, 0, 0); } } } else { if (loc == CONTEXT_WEAK_PARAM) { report (decl_loc, ERR_dcl_fct_par_undecl (nm)); } } ds = adjust_linkage (ds, 0); if (loc == CONTEXT_TEMPL_PARAM) { IDENTIFIER pid; object_type (t, id_token_tag); id = make_exp_param (t, id); pid = DEREF_id (id_token_alt (id)); set_member (mem, pid); } else { t = lvalue_type (t); object_type (t, id_parameter_tag); MAKE_id_parameter (nm, ds, ns, decl_loc, t, id); set_member (mem, id); } check_par_decl (t, id, loc); is_redeclared = 0; return (id); } /* * DECLARE A NON-PROTOTYPE FUNCTION PARAMETER * * This routine is used to declare a non-prototype function parameter. */ IDENTIFIER weak_param_decl(IDENTIFIER id) { NAMESPACE ns = crt_namespace; HASHID nm = DEREF_hashid (id_name (id)); MEMBER mem = search_member (ns, nm, 1); IDENTIFIER old_id = DEREF_id (member_id (mem)); if (!IS_NULL_id (old_id)) { nm = lookup_anon (); mem = search_member (ns, nm, 1); IGNORE redecl_id (dspec_none, NULL_type, old_id, 0, 0); } MAKE_id_weak_param (nm, dspec_none, ns, decl_loc, id); set_member (mem, id); is_redeclared = 0; return (id); } /** * LOOK FOR A FLEXIBLE ARRAY MEMBER * * This routine recursively checks whether the type t contains a struct * with a flexible array member. If one is found the function returns * an error. */ ERROR check_flex_mem(TYPE t) { ERROR err = NULL_err; if (IS_type_compound (t)) { CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); if (!IS_NULL_id (DEREF_id (ctype_flex_mem (ct)))) { err = ERR_class_mem_flex (t); } else { NAMESPACE ns = DEREF_nspace (ctype_member (ct)); MEMBER mem = DEREF_member (nspace_ctype_first (ns)); mem = next_data_member (mem, 2); while (!IS_NULL_member (mem)) { IDENTIFIER id = DEREF_id (member_id (mem)); TYPE s = DEREF_type (id_member_type (id)); err = check_flex_mem (s); if (!IS_NULL_err (err)) break; mem = DEREF_member (member_next (mem)); mem = next_data_member (mem, 2); } } } return (err); } /* * CHECK A MEMBER DECLARATION * * This routine checks the declaration of the class member id with type * t and declaration specifiers ds. ci is the class information for the * class the member is added to. */ void check_mem_decl(DECL_SPEC ds, TYPE t, IDENTIFIER id, CLASS_INFO ci) { int allow_flex_mem = (option (OPT_flex_array_member) != OPTION_DISALLOW); unsigned tag = TAG_type (t); IDENTIFIER mid = DEREF_id (ctype_flex_mem (crt_class)); if (!IS_NULL_id (mid)) { /* Member after flexible array member */ ERROR err = ERR_class_mem_flex_not_last (id, mid); report (crt_loc, err); } if (ds & dspec_mutable) { /* Can't apply mutable to a const member */ CV_SPEC qual = find_cv_qual (t); if (qual & cv_const) { report (crt_loc, ERR_dcl_stc_mut_const (id)); if (IS_id_member (id)) { qual &= ~cv_const; t = qualify_type (t, qual, 0); COPY_type (id_member_type (id), t); } } } if (tag == type_top_tag || tag == type_bottom_tag) { /* Always report void members */ report (crt_loc, ERR_basic_fund_void_mem (id, t)); } else if (tag == type_templ_tag) { /* Shouldn't have template type */ report (crt_loc, ERR_temp_decl_bad ()); } else if (ds & dspec_defn) { /* Only check otherwise for defined (non-static) members */ if (tag == type_ref_tag) { /* References don't need checking */ /* EMPTY */ } else { ERROR err = check_complete (t); if (!IS_NULL_err (err) && tag == type_array_tag) { if ((ci & cinfo_struct) && allow_flex_mem) { /* Flexible array member */ NAMESPACE ns = DEREF_nspace (ctype_member (crt_class)); MEMBER m = DEREF_member (nspace_ctype_first (ns)); m = next_data_member (m, 0); if (!IS_NULL_member (m) && DEREF_id (member_id (m)) != id) { /* Found another member */ COPY_id (ctype_flex_mem (crt_class), id); destroy_error (err, 1); err = NULL_err; } else { /* First member */ ERROR err2 = ERR_class_mem_flex_first (); err = concat_error (err, err2); } } } if (!IS_NULL_err (err)) { /* Other members should have complete type */ ERROR err2 = ERR_class_mem_incompl_mem (id); err = concat_error (err, err2); report (crt_loc, err); } else { /* Members can't have abstract type */ err = check_abstract (t); if (!IS_NULL_err (err)) { ERROR err2 = ERR_class_abstract_mem (id); err = concat_error (err, err2); report (crt_loc, err); } /* A struct with a flexible array member can't be a member * of a struct */ if (ci & cinfo_struct) { err = check_flex_mem (t); if (!IS_NULL_err (err)) { ERROR err2 = ERR_class_mem_flex_nested (); err = concat_error (err, err2); report (crt_loc, err); } } } } } return; } /* * DECLARE A CLASS MEMBER * * This routine constructs the declaration of a class member with * declaration specifiers ds, type t and name id. Note that the access * declarations (i.e. just a qualified-id and a semicolon) can only be * spotted at this stage. The argument sm is true if this is the first * declarator in a list and the next token is a semicolon. */ IDENTIFIER make_member_decl(DECL_SPEC ds, TYPE t, IDENTIFIER id, int sm) { ERROR err; HASHID nm; MEMBER mem; int redef = 0; int tokenised = 0; IDENTIFIER old_id; IDENTIFIER alt_id; DECL_SPEC st, df, rs; OFFSET off = NULL_off; CLASS_TYPE ct = crt_class; IDENTIFIER tok_id = NULL_id; NAMESPACE ns = crt_namespace; unsigned tag = TAG_type (t); QUALIFIER cq = crt_id_qualifier; CLASS_INFO ci = DEREF_cinfo (ctype_info (ct)); /* Check for template specialisations */ if (is_templ_decl (id, NULL_type)) { IGNORE bind_specialise (&id, t, dspec_extern, 0, 1, 0); if (!IS_NULL_id (id)) { report (crt_loc, ERR_temp_spec_member (id)); } return (id); } /* Find previous declaration */ nm = DEREF_hashid (id_name (id)); if (IS_hashid_constr (nm) && cq == qual_none) { DECL_SPEC sds = (dspec_static | dspec_typedef | dspec_reserve); if (!(ds & sds)) { /* Can use class name for non-static member */ report (crt_loc, ERR_class_mem_ctor_data (id)); id = DEREF_id (hashid_constr_tid (nm)); nm = DEREF_hashid (id_name (id)); } } mem = search_member (ns, nm, 1); old_id = DEREF_id (member_id (mem)); alt_id = DEREF_id (member_alt (mem)); if (!IS_NULL_id (old_id)) { old_id = redecl_inherit (old_id, cq, 1, 2); } /* Check on member qualifications */ if (cq != qual_none) { if ((ds & dspec_empty) && sm) { /* Spot access declarations */ id = access_decl (id); return (id); } ns = DEREF_nspace (id_parent (id)); if (EQ_nspace (ns, crt_namespace)) { /* Qualifier indicates the current class */ report (crt_loc, ERR_dcl_meaning_mem (cq, id)); crt_id_qualifier = qual_none; } else { /* Qualifier indicates some other namespace */ id = make_object_decl (ds, t, id, 0); return (id); } } /* Check on identifier name */ err = check_id_name (id, CONTEXT_MEMBER); if (!IS_NULL_err (err)) report (crt_loc, err); /* Deal with inferred types */ ds = check_inferred_type (ds, &t, 1); /* Check on storage class specifiers */ st = check_storage (ds, CONTEXT_MEMBER, old_id); if (st == dspec_static) { if (tag == type_bitfield_tag) { /* Bitfield members can't be static */ report (crt_loc, ERR_class_bit_static ()); st = dspec_none; df = dspec_defn; } else { if (ci & cinfo_union) { /* Unions can't have static data members */ report (crt_loc, ERR_class_union_static (ct)); st = dspec_none; df = dspec_defn; } else { /* Static members are only declared */ df = dspec_none; } } } else { /* Other members are defined */ df = dspec_defn; } /* Deal with type definitions */ if (ds & dspec_typedef) { LIST (IDENTIFIER) ft = DEREF_list (ctype_nest (ct)); if (tag == type_bitfield_tag) { report (crt_loc, ERR_class_bit_typedef ()); t = find_bitfield_type (t); } id = make_type_decl (ns, ds, t, mem, id); CONS_id (id, ft, ft); COPY_list (ctype_nest (ct), ft); return (id); } /* Check on function specifiers */ IGNORE check_func_spec (ds, CONTEXT_MEMBER); /* Record class properties */ rs = (ds & dspec_other); if (rs & dspec_token) tokenised = 1; if (st == dspec_static) { ds = (df | rs | crt_access); } else { ds = (st | df | rs | crt_access); } /* Check for redeclarations */ t = lvalue_type (t); if (!IS_NULL_id (old_id)) { if (st != dspec_static && IS_id_member (old_id)) { /* Allow for token definitions */ if (tokenised) { /* Token with previous definition */ off = DEREF_off (id_member_off (old_id)); t = DEREF_type (id_member_type (old_id)); tokenised = 3; } else { tok_id = find_token (old_id); if (IS_id_token (tok_id)) { /* Member was previously tokenised */ DECL_SPEC tds = DEREF_dspec (id_storage (tok_id)); if (!(tds & (dspec_pure | dspec_auto))) { /* Token can't be defined */ tokenised = 2; } } } } if (tokenised == 0) { /* Redeclare if neither is a token */ old_id = redecl_id (ds, t, old_id, 0, 0); if (IS_NULL_id (old_id)) redef = 1; } } else if (!IS_NULL_id (alt_id)) { redef = 1; } /* Create the declaration */ ds = adjust_linkage (ds, 1); if (!really_in_function_defn) ds |= dspec_extern; if (st == dspec_static) { object_type (t, id_stat_member_tag); MAKE_id_stat_member (nm, ds, ns, decl_loc, t, id); } else { object_type (t, id_member_tag); MAKE_id_member (nm, ds, ns, decl_loc, t, id); if (tokenised == 0 || tokenised == 2) { /* Construct member offset if not tokenised */ MAKE_off_member (id, off); } COPY_off (id_member_off (id), off); if (redef) mem = update_member (ns, mem); } /* Set the namespace member */ if (tokenised >= 2) { /* Create dummy member */ MEMBER mem_old = DEREF_member (nspace_last (ns)); if (tokenised == 2) { /* Define existing token */ IGNORE define_mem_token (tok_id, off, t, 1); } else { /* Token is defined later ... */ /* EMPTY */ } MAKE_member_large (NULL_member, NULL_member, mem); COPY_id (member_id (mem), id); COPY_member (nspace_last (ns), mem); COPY_member (member_next (mem_old), mem); } set_member (mem, id); check_mem_decl (ds, t, id, ci); is_redeclared = 0; /* Adjust class information */ if (st == dspec_static) { if (really_in_function_defn) { /* Can't have static members in local classes */ report (crt_loc, ERR_class_local_static (id)); } ci |= cinfo_static; } else { /* Check member types */ if (crt_access != dspec_public) ci |= cinfo_private; ci = check_member_type (ct, ci, t, 0); ci &= ~cinfo_empty; } COPY_cinfo (ctype_info (ct), ci); return (id); } /* * MAINTAIN SPECIAL MEMBER FUNCTIONS FOR A CLASS * * This routine updates the special member function information for * the class ct using the function id. tag gives the identifier name tag. */ void special_func_mem(CLASS_TYPE ct, IDENTIFIER id, unsigned tag, IDENTIFIER prev) { switch (tag) { case hashid_constr_tag : { /* Set constructor */ COPY_id (ctype_constr (ct), id); break; } case hashid_destr_tag : { /* Set destructor */ COPY_id (ctype_destr (ct), id); break; } case hashid_conv_tag : { /* Maintain list of conversion functions */ HASHID nm = DEREF_hashid (id_name (id)); LIST (IDENTIFIER) conv = DEREF_list (ctype_conv (ct)); LIST (IDENTIFIER) p = conv; while (!IS_NULL_list (p)) { IDENTIFIER pid = DEREF_id (HEAD_list (p)); HASHID pnm = DEREF_hashid (id_name (pid)); if (EQ_hashid (nm, pnm)) { /* Already member of list */ IDENTIFIER over; over = DEREF_id (id_function_etc_over (id)); if (!EQ_id (pid, over) && !EQ_id (pid, prev)) { /* Template function has produced duplicate */ PTR (LOCATION) ploc = id_loc (pid); report (crt_loc, ERR_class_mem_redecl (id, ploc)); } COPY_id (HEAD_list (p), id); return; } p = TAIL_list (p); } CONS_id (id, conv, conv); COPY_list (ctype_conv (ct), conv); break; } } return; } /* * DECLARE A CLASS FUNCTION MEMBER * * This routine constructs a function declaration for a class member * function with declaration specifiers ds, type t and name id. The * argument def is true to distinguish function definitions from function * declarations. */ #if LANGUAGE_CPP IDENTIFIER make_func_mem_decl(DECL_SPEC ds, TYPE t, IDENTIFIER id, int def) { ERROR err; MEMBER mem; int ok = 1; int chk = 1; unsigned it; unsigned itag; int allocator = 0; IDENTIFIER old_id; LIST (VIRTUAL) vt; DECL_SPEC st, df, fn, rs; IDENTIFIER over_id = NULL_id; IDENTIFIER hide_id = NULL_id; NAMESPACE ns = crt_namespace; QUALIFIER cq = crt_id_qualifier; HASHID nm = DEREF_hashid (id_name (id)); CLASS_TYPE ct = crt_class; CLASS_INFO ci = DEREF_cinfo (ctype_info (ct)); /* Check for template specialisations */ if (is_templ_decl (id, t) || is_templ_spec (t)) { st = (dspec_extern | (ds & dspec_inline)); IGNORE bind_specialise (&id, t, st, 0, 1, def); if (!IS_NULL_id (id)) { report (crt_loc, ERR_temp_spec_member (id)); } return (id); } /* Find previous declaration */ mem = search_member (ns, nm, 1); old_id = DEREF_id (member_id (mem)); if (!IS_NULL_id (old_id)) { old_id = redecl_inherit (old_id, cq, 1, 1); } /* Check on member qualifications */ if (cq != qual_none) { ns = DEREF_nspace (id_parent (id)); if (EQ_nspace (ns, crt_namespace)) { /* Qualifier indicates the current class */ report (crt_loc, ERR_dcl_meaning_mem (cq, id)); crt_id_qualifier = qual_none; } else { /* Qualifier indicates some other namespace */ id = make_func_decl (ds, t, id, def); return (id); } } /* Check on identifier name */ err = check_id_name (id, CONTEXT_FUNC_MEMBER); if (!IS_NULL_err (err)) { report (crt_loc, err); ok = 0; } /* Allow for special functions */ it = TAG_hashid (nm); switch (it) { case hashid_constr_tag : { t = check_constr (t, id, ns); ds &= ~dspec_empty; ds |= dspec_main; break; } case hashid_destr_tag : { t = check_destr (t, id, ns); ds &= ~dspec_empty; ds |= dspec_main; break; } case hashid_op_tag : { t = check_operator (t, id, 1, &allocator); if (!allocator) ds |= dspec_ignore; break; } case hashid_conv_tag : { t = check_conv (t, id); ds &= ~dspec_empty; chk = 0; break; } } /* Deal with inferred types */ ds = check_func_type (ds, t, def, chk, 1); /* Handle function definitions */ if (def) { /* Functions defined in a class are inline */ df = dspec_defn; ds |= dspec_inline; } else { df = dspec_none; } /* Check on storage class specifiers */ st = check_storage (ds, CONTEXT_FUNC_MEMBER, old_id); /* Deal with type definitions */ if (ds & dspec_typedef) { /* Can only apply typedef to declarations, not definitions */ if (!def) { if (ok) { /* Recheck identifier name */ err = check_id_name (id, CONTEXT_MEMBER); if (!IS_NULL_err (err)) report (crt_loc, err); } id = make_type_decl (ns, ds, t, mem, id); return (id); } report (crt_loc, ERR_dcl_typedef_func ()); } /* Check special functions */ if (allocator) { /* Allocator functions are implicitly static */ if (st != dspec_static) { st = dspec_static; allocator |= 0x4; } } else if (st == dspec_static) { switch (it) { case hashid_constr_tag : { /* Constructors can't be static */ report (crt_loc, ERR_class_ctor_static ()); st = dspec_none; break; } case hashid_destr_tag : { /* Destructors can't be static */ report (crt_loc, ERR_class_dtor_static ()); st = dspec_none; break; } case hashid_op_tag : { /* Overloaded operators can't be static */ report (crt_loc, ERR_over_oper_static ()); st = dspec_none; break; } case hashid_conv_tag : { /* Conversion functions can't be static */ report (crt_loc, ERR_class_conv_fct_mem ()); st = dspec_none; break; } } } /* Check on function specifiers */ fn = check_func_spec (ds, CONTEXT_FUNC_MEMBER); vt = overrides_virtual (ct, nm, t, &hide_id); if (!IS_NULL_list (vt)) { /* Check for overriding of virtual functions */ if (!(fn & dspec_virtual)) { if (!(ds & dspec_implicit)) { err = ERR_class_virtual_override (nm); if (!IS_NULL_err (err)) report (crt_loc, err); } fn |= dspec_virtual; } } else if (!IS_NULL_id (hide_id)) { err = ERR_class_virtual_hide (nm, hide_id); if (!IS_NULL_err (err)) report (crt_loc, err); } if (fn & dspec_virtual) { if (st == dspec_static) { /* Static members can't be virtual */ err = ERR_class_static_mfct_virt (); if (allocator & 0x4) { /* Allocator functions are implicitly static */ err = concat_error (ERR_class_free_static (nm), err); } report (crt_loc, err); fn &= ~dspec_virtual; } else if (it == hashid_constr_tag) { /* Constructors can't be virtual */ report (crt_loc, ERR_class_ctor_virtual ()); fn &= ~dspec_virtual; } else { if (ci & cinfo_union) { /* Unions can't have virtual functions */ report (crt_loc, ERR_class_union_virtual (ct)); fn &= ~dspec_virtual; } else if (ds & dspec_template) { /* Can't have a virtual template function */ report (crt_loc, ERR_temp_mem_virtual ()); fn &= ~dspec_virtual; } else { /* The current class is polymorphic */ ci |= cinfo_polymorphic; ci &= ~cinfo_empty; } } } if (fn & dspec_explicit) { /* Only constructors can be explicit */ if (it == hashid_constr_tag) { have_constr_expl = 1; } else { if (it == hashid_conv_tag) { report (crt_loc, ERR_dcl_fct_spec_expl_conv ()); have_conv_expl = 1; } else { report (crt_loc, ERR_dcl_fct_spec_expl_constr ()); fn &= ~dspec_explicit; } } } if (ds & dspec_template) { /* Check for template function members */ if (it == hashid_destr_tag) { report (crt_loc, ERR_temp_mem_destr ()); } } /* Record class properties */ rs = (ds & dspec_other); if (st == dspec_static) { itag = id_stat_mem_func_tag; ds = (df | fn | rs | crt_access); } else { itag = id_mem_func_tag; ds = (st | df | fn | rs | crt_access); } if (!(ds & dspec_implicit)) ci |= cinfo_function; COPY_cinfo (ctype_info (ct), ci); /* Create the function declaration */ t = lvalue_type (t); if (!IS_NULL_id (old_id)) { /* Check for redeclarations */ IGNORE redecl_func (ds, t, old_id, itag, &over_id, def); } object_type (t, itag); ds = adjust_linkage (ds, 1); if (!really_in_function_defn) ds |= dspec_extern; MAKE_id_function_etc (itag, nm, ds, ns, decl_loc, t, over_id, id); if (!IS_NULL_id (over_id)) { id = hide_functions (id, over_id, 1); } set_member (mem, id); decl_func_type (id, t, def); is_redeclared = 0; ds = DEREF_dspec (id_storage (id)); /* Maintain lists of functions */ special_func_mem (ct, id, it, old_id); if (def) { LIST (IDENTIFIER) ft = DEREF_list (ctype_nest (ct)); CONS_id (id, ft, ft); COPY_list (ctype_nest (ct), ft); } if (ds & dspec_virtual) { add_virtual (ct, id, vt); } if (allocator) { allocator &= 0x3; recheck_allocator (id, allocator); } /* Allow for discarded functions */ if (!(rs & dspec_ignore) && option (OPT_discard_func)) { ds &= ~dspec_ignore; COPY_dspec (id_storage (id), ds); } return (id); } #endif /* * DECLARE A FRIEND FUNCTION * * This routine is used to handle the declaration of a friend function * within a class. The parameters are identical to those in the previous * routine. */ #if LANGUAGE_CPP IDENTIFIER make_friend_decl(DECL_SPEC ds, TYPE t, IDENTIFIER id, int def, int chum) { ERROR err; MEMBER mem; int chk = 1; unsigned it; int allocator = 0; int main_func = 0; IDENTIFIER old_id; NAMESPACE ns, ens; DECL_SPEC st, df, fn, rs; IDENTIFIER over_id = NULL_id; unsigned itag = id_function_tag; QUALIFIER cq = crt_id_qualifier; int td = crt_templ_qualifier; HASHID nm = DEREF_hashid (id_name (id)); /* Check for template specialisations */ if (in_template_decl && cq == qual_none && td == 0 && chum) { TYPE s = injected_type (t, 1); if (!EQ_type (s, t)) { /* Friend declaration is implicitly a template */ int eq = 0; IDENTIFIER tid = make_friend_decl (ds, s, id, 0, 0); if (do_dump) dump_declare (tid, &decl_loc, 0); id = deduce_func (tid, t, &eq); if (IS_NULL_id (id)) return (tid); crt_templ_qualifier = 1; } } if (is_templ_decl (id, t) || is_templ_spec (t)) { t = bind_specialise (&id, t, ds, 0, 1, def); if (IS_NULL_id (id)) { /* Invalid specialisation */ crt_id_qualifier = qual_none; crt_templ_qualifier = 0; id = DEREF_id (hashid_id (nm)); while (IS_type_templ (t)) { t = DEREF_type (type_templ_defn (t)); } id = make_friend_decl (ds, t, id, def, chum); return (id); } ns = DEREF_nspace (id_parent (id)); ens = ns; mem = NULL_member; old_id = id; if (def) { /* Check enclosing namespace scope */ check_decl_nspace (id, ns, def, nonclass_namespace); } } else { /* Deal with typedef immediately */ if ((ds & dspec_typedef) && !def) { id = make_func_mem_decl (ds, t, id, def); return (id); } /* Check on identifier name */ err = check_id_name (id, CONTEXT_FUNCTION); if (!IS_NULL_err (err)) report (crt_loc, err); /* Check on member qualification */ if (cq == qual_none) { /* Declaration of simple identifier */ ns = nonclass_namespace; ens = nonblock_namespace; mem = search_member (ns, nm, 1); old_id = DEREF_id (member_id (mem)); if (!IS_NULL_id (old_id)) { old_id = redecl_inherit (old_id, cq, 0, 1); } if (in_template_decl && is_templ_nspace (crt_namespace)) { /* Friend of template class */ NAMESPACE tns = templ_namespace; mem = search_member (tns, nm, 1); } } else { /* Redeclaration of class or namespace member */ ns = DEREF_nspace (id_parent (id)); ens = ns; /* QUERY: Any other restrictions? */ if (IS_id_undef (id)) { report (crt_loc, ERR_lookup_qual_undef (nm, ns)); if (IS_nspace_ctype (ns)) itag = id_mem_func_tag; mem = search_member (ns, nm, 1); old_id = NULL_id; } else { mem = NULL_member; old_id = redecl_inherit (id, cq, 0, 1); t = bind_specialise (&old_id, t, ds, 0, 0, def); if (!IS_NULL_id (old_id)) { id = old_id; itag = TAG_id (id); ns = DEREF_nspace (id_parent (id)); ens = ns; if (def) { /* Check enclosing namespace scope */ check_decl_nspace (id, ns, def, nonclass_namespace); } } } } } /* Can't define function in local class */ if (def && really_in_function_defn) { report (crt_loc, ERR_class_friend_local ()); } /* Allow for special functions */ if (EQ_KEYWORD (nm, lex_main) && IS_nspace_global (ens)) { /* Declare main as a friend - it could happen */ t = check_main (t, nm); main_func = 1; } it = TAG_hashid (nm); switch (it) { case hashid_constr_tag : { t = check_constr (t, id, ns); ds |= dspec_main; break; } case hashid_destr_tag : { t = check_destr (t, id, ns); ds |= dspec_main; break; } case hashid_op_tag : { int cl = IS_nspace_ctype (ns); t = check_operator (t, id, cl, &allocator); if (!allocator) ds |= dspec_ignore; break; } case hashid_conv_tag : { t = check_conv (t, id); chk = 0; break; } } /* Deal with inferred types */ ds = check_func_type (ds, t, def, chk, 1); if (main_func) ds |= dspec_main; /* Check on storage class specifiers */ st = check_storage (ds, CONTEXT_FUNCTION, old_id); if (st != dspec_none) { /* Can't have storage class with friend */ report (crt_loc, ERR_class_friend_storage (st)); } if (def) { /* Functions defined in a class are inline */ df = dspec_defn; ds |= dspec_inline; st = find_storage (old_id, inline_linkage, t); } else if (ds & dspec_inline) { df = dspec_none; st = find_storage (old_id, inline_linkage, t); } else { df = dspec_none; st = find_storage (old_id, dspec_extern, t); } if ((ds & dspec_inline) && main_func) { report (crt_loc, ERR_basic_start_main_link (nm, dspec_inline)); ds &= ~dspec_inline; st = dspec_extern; } /* Check on function specifiers */ fn = check_func_spec (ds, CONTEXT_FUNCTION); /* Create the declaration */ t = lvalue_type (t); rs = (ds & dspec_other); ds = (st | df | fn | rs); if (!IS_NULL_id (old_id)) { /* Check redeclarations */ old_id = redecl_func (ds, t, old_id, itag, &over_id, def); if (IS_NULL_id (old_id) && IS_NULL_member (mem)) { /* Bad redeclaration of class or namespace member */ nm = lookup_anon (); mem = search_member (ns, nm, 1); if (IS_nspace_ctype (ns)) itag = id_mem_func_tag; over_id = NULL_id; } } object_type (t, itag); if (IS_NULL_id (old_id)) { /* Declare the function */ ds = adjust_linkage (ds, 0); MAKE_id_function_etc (itag, nm, ds, ns, decl_loc, t, over_id, id); id = unify_subsequent (id, t, def); set_member (mem, id); decl_func_type (id, t, def); report (decl_loc, ERR_class_friend_pre (id)); /* Check for conversion functions */ if (it == hashid_conv_tag && itag != id_mem_func_tag) { report (crt_loc, ERR_class_conv_fct_mem ()); } if (itag == id_function_tag && option (OPT_decl_hide)) { check_hiding (id); } is_redeclared = 0; } else { /* Redeclare the function */ id = old_id; is_redeclared = 1; } ds = DEREF_dspec (id_storage (id)); #if LANGUAGE_CPP if (ds & dspec_c) c_linkage (id, def); #endif /* Maintain list of inline functions */ if (def) { CLASS_TYPE ct = crt_class; LIST (IDENTIFIER) ft = DEREF_list (ctype_nest (ct)); CONS_id (id, ft, ft); COPY_list (ctype_nest (ct), ft); } /* Allow for discarded functions */ if (!(rs & dspec_ignore) && option (OPT_discard_func)) { ds &= ~dspec_ignore; COPY_dspec (id_storage (id), ds); } /* Make the function a friend */ if (chum) friend_function (crt_class, id, 1); if (main_func) recheck_main (id); if (allocator) recheck_allocator (id, allocator); return (id); } #endif /* * CHECK ON AN ANONYMOUS UNION * * An anonymous union cannot have private or protected members or member * functions (in addition, no union can have static data members). This * information is readily accessible from the class information field. * The routine class_info is not used in this case because it includes * the name of ct in its errors, which is not particularly useful when * ct is anonymous. */ #if LANGUAGE_CPP static void check_anon_union(CLASS_TYPE ct) { CLASS_INFO ci = DEREF_cinfo (ctype_info (ct)); if (ci & cinfo_private) { report (crt_loc, ERR_class_union_anon_private ()); } if (ci & cinfo_function) { report (crt_loc, ERR_class_union_anon_func ()); } return; } #endif /* * CHECK AN EMPTY OBJECT DECLARATION * * This routine handles a declaration with no declarators, comprising the * declaration specifiers ds, the template type qualifiers q and the type * specifiers t (which may be an elaborate pre-type). Whether this is * legal depends on the value of the flag have_type_specifier described * in predict.c, which indicates whether t contained a type declaration * or definition. Note that anonymous unions come under this heading * (I hate anonymous unions). */ static IDENTIFIER empty_object_decl(DECL_SPEC ds, TYPE q, TYPE t) { CV_SPEC qual; DECL_SPEC st; IDENTIFIER tid; BASE_TYPE key = btype_class; int td = have_type_declaration; /* Check for type declarations */ if (IS_type_pre (t)) { QUALIFIER it; DESTROY_type_pre (destroy, qual, tid, key, it, t); if (it == qual_none) { /* Unqualified identifier */ DECL_SPEC mode = (dspec_defn | dspec_auto); td = TYPE_DECL_ELABORATE; tid = find_elaborate_type (tid, key, q, mode); } else { /* Qualified identifier */ DECL_SPEC mode = (dspec_defn | dspec_alias); td = TYPE_DECL_OVER_ELAB; if (!IS_NULL_type (q)) td = TYPE_DECL_ELABORATE; tid = find_elaborate_type (tid, key, q, mode); } #if LANGUAGE_CPP t = DEREF_type (id_class_name_etc_defn (tid)); t = qualify_type (t, qual, 0); #endif } else { tid = DEREF_id (type_name (t)); qual = DEREF_cv (type_qual (t)); } qual &= cv_qual; #if LANGUAGE_CPP /* Check for anonymous unions */ if (td == TYPE_DECL_ANON && !(ds & dspec_typedef)) { TYPE s = t; while (IS_type_templ (s)) { s = DEREF_type (type_templ_defn (s)); } if (IS_type_compound (s)) { CLASS_TYPE ct = DEREF_ctype (type_compound_defn (s)); CLASS_INFO ci = DEREF_cinfo (ctype_info (ct)); if (ci & cinfo_union) { /* Anonymous union found */ int def; HASHID nm; IDENTIFIER id; check_anon_union (ct); /* Create the union object */ nm = lookup_anon (); id = DEREF_id (hashid_id (nm)); crt_id_qualifier = qual_none; crt_templ_qualifier = 0; id = make_object_decl (ds, t, id, 0); ds = DEREF_dspec (id_storage (id)); if (ds & dspec_extern) { /* Anonymous unions can't have external linkage */ report (crt_loc, ERR_class_union_anon_static ()); } def = init_object (id, NULL_exp); if (do_dump) dump_declare (id, &crt_loc, def); if (output_diag && !in_function_defn) { compile_variable (id, 1); } /* Bring fields into scope */ if (!redecl_anon_union (ct, ds, id)) { report (crt_loc, ERR_dcl_dcl_empty ()); } return (id); } } } #endif /* Check declaration specifiers */ if (ds != dspec_none) { st = check_storage (ds, CONTEXT_OBJECT, NULL_id); if (st != dspec_none) { /* Can't have a storage class specifier */ report (crt_loc, ERR_dcl_stc_bad (st)); } if (ds & dspec_typedef) { report (crt_loc, ERR_dcl_typedef_dcl ()); } IGNORE check_func_spec (ds, CONTEXT_OBJECT); } /* Check type qualifiers */ if (qual != cv_none && td != TYPE_DECL_NONE) { report (crt_loc, ERR_dcl_type_cv_unused (qual)); } /* Check for type definitions */ switch (td) { case TYPE_DECL_NONE : { report (crt_loc, ERR_dcl_dcl_empty ()); tid = NULL_id; break; } case TYPE_DECL_ANON : { report (crt_loc, ERR_dcl_dcl_anon ()); break; } case TYPE_DECL_OVER_ELAB : { report (crt_loc, ERR_dcl_type_elab_qual (key)); break; } } return (tid); } /* * CHECK AN EMPTY MEMBER DECLARATION * * This routine handles a class member declaration with no declarators, * comprising the declaration specifiers ds, the template type qualifiers * q and the type specifiers t. This is similar to empty_object_decl, * except that provision needs to be made for friend declarations of the * form 'friend class C'. */ static IDENTIFIER empty_member_decl(DECL_SPEC ds, TYPE q, TYPE t) { CV_SPEC qual; IDENTIFIER tid; BASE_TYPE key = btype_class; int td = have_type_declaration; /* Check for type declarations */ if (IS_type_pre (t)) { QUALIFIER it; DESTROY_type_pre (destroy, qual, tid, key, it, t); if (it == qual_none) { /* Unqualified identifier */ DECL_SPEC mode = dspec_defn; if (option (OPT_class_scope)) mode |= dspec_auto; if (ds & dspec_friend) { mode = (dspec_defn | dspec_used | dspec_friend); if (in_template_decl && is_templ_nspace (crt_namespace)) { /* Friend of template class */ mode |= dspec_template; } mode |= dspec_register; } tid = find_elaborate_type (tid, key, q, mode); if (mode & dspec_template) { NAMESPACE ns = DEREF_nspace (id_parent (tid)); if (EQ_nspace (ns, templ_namespace)) { ns = nonclass_namespace; COPY_nspace (id_parent (tid), ns); } } td = TYPE_DECL_ELABORATE; } else { /* Qualified identifier */ DECL_SPEC mode = (dspec_defn | dspec_alias); if (ds & dspec_friend) mode |= dspec_friend; tid = find_elaborate_type (tid, key, q, mode); td = TYPE_DECL_OVER_ELAB; } t = DEREF_type (id_class_name_etc_defn (tid)); t = qualify_type (t, qual, 0); } else { tid = DEREF_id (type_name (t)); qual = DEREF_cv (type_qual (t)); } qual &= cv_qual; #if LANGUAGE_CPP /* Check for anonymous unions */ if (td == TYPE_DECL_ANON && !(ds & dspec_typedef)) { TYPE s = t; while (IS_type_templ (s)) { s = DEREF_type (type_templ_defn (s)); } if (IS_type_compound (s)) { CLASS_TYPE ct = DEREF_ctype (type_compound_defn (s)); CLASS_INFO ci = DEREF_cinfo (ctype_info (ct)); if (ci & cinfo_union) { /* Anonymous union found */ int def; HASHID nm; IDENTIFIER id; check_anon_union (ct); /* Create union member */ nm = lookup_anon (); id = DEREF_id (hashid_id (nm)); crt_id_qualifier = qual_none; crt_templ_qualifier = 0; if (ds & dspec_static) { /* Can't be a static data member */ report (crt_loc, ERR_class_union_anon_mem ()); ds &= ~dspec_static; } id = make_member_decl (ds, t, id, 0); def = init_member (id, NULL_exp); if (do_dump) dump_declare (id, &crt_loc, def); /* Bring fields into scope */ if (!redecl_anon_union (ct, dspec_none, id)) { report (crt_loc, ERR_class_mem_empty ()); } return (id); } } } #endif /* Check declaration specifiers */ if (ds != dspec_none) { CLASS_TYPE cs = crt_class; CLASS_TYPE ct = NULL_ctype; DECL_SPEC st = check_storage (ds, CONTEXT_MEMBER, NULL_id); if (st != dspec_none) { /* Can't have a storage class specifier */ report (crt_loc, ERR_dcl_stc_bad (st)); } if (ds & dspec_typedef) { report (crt_loc, ERR_dcl_typedef_dcl ()); } if (ds & dspec_friend) { /* Allow for friend declarations */ while (IS_type_templ (t)) { t = DEREF_type (type_templ_defn (t)); } if (IS_type_compound (t)) { ct = DEREF_ctype (type_compound_defn (t)); } else if (is_templ_type (t)) { IDENTIFIER cid = DEREF_id (type_token_tok (t)); ct = find_class (cid); } if (!IS_NULL_ctype (ct)) { switch (td) { case TYPE_DECL_ELABORATE : case TYPE_DECL_OVER_ELAB : { /* Have 'friend class A;' */ break; } case TYPE_DECL_NORMAL : { /* Have 'friend class A { ... };' */ report (crt_loc, ERR_class_friend_def ()); break; } case TYPE_DECL_ANON : { /* Have 'friend class { ... };' */ report (crt_loc, ERR_class_mem_anon ()); report (crt_loc, ERR_class_friend_def ()); break; } default : { /* Have 'friend A;' */ report (crt_loc, ERR_class_friend_elab ()); break; } } ds &= ~dspec_friend; } } IGNORE check_func_spec (ds, CONTEXT_MEMBER); if (!IS_NULL_ctype (ct)) { /* Declare a class as a friend */ tid = DEREF_id (ctype_name (ct)); if (qual != cv_none) { report (crt_loc, ERR_dcl_type_cv_unused (qual)); } friend_class (cs, tid, 1); return (tid); } } /* Check type qualifiers */ if (qual != cv_none && td != TYPE_DECL_NONE) { report (crt_loc, ERR_dcl_type_cv_unused (qual)); } /* Check for type definitions */ switch (td) { case TYPE_DECL_NONE : { report (crt_loc, ERR_class_mem_empty ()); tid = NULL_id; break; } case TYPE_DECL_ANON : { report (crt_loc, ERR_class_mem_anon ()); break; } case TYPE_DECL_OVER_ELAB : { report (crt_loc, ERR_dcl_type_elab_qual (key)); break; } } return (tid); } /* * CHECK AN EMPTY DECLARATION * * This routine checks the empty declaration declared with the declaration * specifiers ds, the template type qualifiers q, the pre-type bt and t * and the cv-qualifiers cv (not all of which will be empty). The tok * parameter is used to pass in the number of the last lexical token read, * this is used for a backwards compatibility hack involving types such * as wchar_t which used to be defined by typedefs, but are now keywords. * mem is true for member declarations. */ IDENTIFIER empty_decl(DECL_SPEC ds, TYPE q, BASE_TYPE bt, TYPE t, CV_SPEC cv, int tok, int mem) { /* Check for empty declarations */ IDENTIFIER id; int have_specifier = 1; decl_loc = crt_loc; if (ds == dspec_none && bt == btype_none && cv == cv_none) { if (IS_NULL_type (q)) { if (IS_NULL_type (t)) { /* Only semicolon in declaration */ if (mem) { if (tok != lex_func_Hop) { /* Allowed after function definition */ report (crt_loc, ERR_class_mem_semicolon ()); } } else { report (crt_loc, ERR_dcl_dcl_semicolon ()); } return (NULL_id); } if (have_type_declaration == TYPE_DECL_NONE) { /* No type specifier in declaration */ have_specifier = 0; } } } #if LANGUAGE_C /* Check 'for' statements */ if (in_for_decl) { report (crt_loc, ERR_stmt_for_no_object ()); return (NULL_id); } #endif /* Check for definitions of built-in types */ if ((ds & dspec_typedef) && !mem) { BASE_TYPE bs = key_type (tok); if (bs) { /* Type is now a keyword */ HASHID nm = KEYWORD (tok); id = DEREF_id (hashid_id (nm)); bt &= ~bs; t = complete_pre_type (bt, t, cv, 0); report (crt_loc, ERR_lex_key_word (tok)); crt_id_qualifier = qual_none; crt_templ_qualifier = 0; id = make_object_decl (ds, t, id, 0); return (id); } } /* Check for type access declarations */ if (!have_specifier && mem) { if (!IS_NULL_type (t) && IS_type_pre (t)) { BASE_TYPE key = DEREF_btype (type_pre_rep (t)); if (key == btype_alias) { IDENTIFIER tid = DEREF_id (type_name (t)); QUALIFIER qual = DEREF_qual (type_pre_nqual (t)); if (qual && !IS_NULL_id (tid)) { id = access_decl (tid); return (id); } } } } /* Perform the declaration */ t = empty_complete_pre_type (bt, t, cv, 0); if (mem) { report (crt_loc, ERR_class_mem_declarator ()); id = empty_member_decl (ds, q, t); } else { id = empty_object_decl (ds, q, t); } if (in_weak_param) { /* Shouldn't happen in parameter declaration lists */ report (crt_loc, ERR_dcl_fct_par_none ()); } return (id); } /* * UPDATE EXTERNAL DECLARATION INFORMATION * * This routine is called after each external declaration. d gives * the number of objects declared and e gives the associated expression * for an asm definition. Note that this is the point of instantiation * for any pending templates. */ void external_declaration(EXP e, int d) { if (crt_file_type == 0) { no_declarations += (unsigned long) d; } if (!IS_NULL_exp (e)) { /* Compile any asm definitions */ compile_asm (e); } if (!in_preproc_dir) { if (crt_access_list.pending) { /* Clear any outstanding access checks */ IGNORE report_access (NULL_id); } if (!IS_NULL_list (pending_templates)) { /* Instantiate any pending templates */ clear_templates (0); } } compile_weak_pending (); return; }