/* * 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/construct.c,v 1.7 2004/08/14 15:15:35 bp Exp $ */ #include "config.h" #include "producer.h" #include "c_types.h" #include "ctype_ops.h" #include "exp_ops.h" #include "graph_ops.h" #include "hashid_ops.h" #include "id_ops.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 "assign.h" #include "basetype.h" #include "capsule.h" #include "cast.h" #include "check.h" #include "chktype.h" #include "class.h" #include "compile.h" #include "constant.h" #include "construct.h" #include "convert.h" #include "copy.h" #include "chktype.h" #include "declare.h" #include "derive.h" #include "destroy.h" #include "dump.h" #include "exception.h" #include "expression.h" #include "function.h" #include "hash.h" #include "identifier.h" #include "initialise.h" #include "instance.h" #include "label.h" #include "namespace.h" #include "operator.h" #include "overload.h" #include "predict.h" #include "statement.h" #include "syntax.h" #include "template.h" #include "token.h" /* * SET AN INFERRED FUNCTION RETURN TYPE * * If t is a function type with an inferred return type then the actual * return type is set according to id. The routine returns the original * inferred return type. */ TYPE inferred_return (TYPE t, IDENTIFIER id) { if (IS_type_func (t)) { TYPE r = DEREF_type (type_func_ret (t)); if (is_type_inferred (r) == INFERRED_EMPTY) { HASHID nm = DEREF_hashid (id_name (id)); switch (TAG_hashid (nm)) { case hashid_constr_tag : case hashid_destr_tag : { /* Constructors and destructors */ COPY_type (type_func_ret (t), type_void); break; } case hashid_conv_tag : { /* Conversion functions */ TYPE s = DEREF_type (hashid_conv_type (nm)); COPY_type (type_func_ret (t), s); break; } } return (r); } } return (NULL_type); } /* * CHECK A COPY CONSTRUCTOR OR ASSIGNMENT OPERATOR TYPE * * This routine checks whether the function type fn has first parameter * of type '[volatile] ct &', 'const [volatile] ct &' or '[const] * [volatile] ct' with any subsequent parameters being optional. It * returns 1, 2 and 3 respectively in these cases, or 0 if fn does not * match this description. */ static int check_copy_constr(TYPE fn, CLASS_TYPE ct) { int c = 0; if (IS_type_templ (fn)) { /* Allow for template constructors */ in_template_decl++; fn = DEREF_type (type_templ_defn (fn)); c = check_copy_constr (fn, ct); in_template_decl--; } else { LIST (IDENTIFIER) pids = DEREF_list (type_func_pids (fn)); if (!IS_NULL_list (pids)) { /* Have at least one parameter */ IDENTIFIER pid = DEREF_id (HEAD_list (pids)); TYPE t = DEREF_type (id_parameter_type (pid)); /* Check for second parameter */ pids = TAIL_list (pids); if (!IS_NULL_list (pids)) { /* Second parameter must have a default argument */ EXP e; pid = DEREF_id (HEAD_list (pids)); e = DEREF_exp (id_parameter_init (pid)); if (IS_NULL_exp (e)) return (0); } /* Check parameter type */ if (IS_type_ref (t)) { TYPE s = DEREF_type (type_ref_sub (t)); if (IS_type_compound (s)) { CLASS_TYPE cs = DEREF_ctype (type_compound_defn (s)); if (eq_ctype (cs, ct)) { /* Reference to same class */ CV_SPEC qual = DEREF_cv (type_qual (s)); c = ((qual & cv_const) ? 2 : 1); } } else if (is_templ_type (s)) { /* Reference to template parameter */ CV_SPEC qual = DEREF_cv (type_qual (s)); c = ((qual & cv_const) ? 2 : 1); } } else if (IS_type_compound (t)) { CLASS_TYPE cs = DEREF_ctype (type_compound_defn (t)); if (eq_ctype (cs, ct)) c = 3; } else if (is_templ_type (t)) { /* Template parameter */ c = 1; } } } return (c); } /* * CHECK A CONSTRUCTOR FUNCTION TYPE * * This routine checks the function type t for the constructor id declared * in namespace ns. The check that the constructor is a non-static member * function is carried out elsewhere. Note that no return type can be given * for id - it is implicitly void. Remedial action is taken to transform * illegal copy constructors such as 'X::X (X)' into valid constructors * such as 'X::X (X &)'. This is to avoid having to check for infinite * loops later. */ TYPE check_constr(TYPE t, IDENTIFIER id, NAMESPACE ns) { if (IS_type_templ (t)) { /* Allow for template types */ TYPE s = DEREF_type (type_templ_defn (t)); s = check_constr (s, id, ns); COPY_type (type_templ_defn (t), s); } else { /* Decompose function type */ TYPE r = DEREF_type (type_func_ret (t)); CV_SPEC cv = DEREF_cv (type_func_mqual (t)); /* Find underlying class */ CLASS_TYPE ct = namespace_class (ns); /* No return type can be given for a constructor */ if (is_type_inferred (r) != INFERRED_EMPTY) { HASHID nm = DEREF_hashid (id_name (id)); report (crt_loc, ERR_class_ctor_ret (nm)); } COPY_type (type_func_ret (t), type_void); /* Check for invalid copy constructors */ if (check_copy_constr (t, ct) == 3) { HASHID nm = DEREF_hashid (id_name (id)); report (crt_loc, ERR_class_copy_bad (nm)); } /* A constructor cannot be cv-qualified */ if (cv & cv_qual) { HASHID nm = DEREF_hashid (id_name (id)); report (crt_loc, ERR_class_ctor_qual (nm, cv)); } } return (t); } /* * CHECK A DESTRUCTOR FUNCTION TYPE * * This routine checks the function type t for the destructor id. The * check that the destructor is a non-static member function is carried * out elsewhere. Note that no return type can be given for id - it is * implicitly void. */ TYPE check_destr(TYPE t, IDENTIFIER id, NAMESPACE ns) { if (IS_type_templ (t)) { /* Allow for template types */ TYPE s = DEREF_type (type_templ_defn (t)); s = check_destr (s, id, ns); COPY_type (type_templ_defn (t), s); } else { /* Decompose function type */ TYPE r = DEREF_type (type_func_ret (t)); CV_SPEC cv = DEREF_cv (type_func_mqual (t)); int ell = DEREF_int (type_func_ellipsis (t)); LIST (TYPE) p = DEREF_list (type_func_ptypes (t)); /* Check namespace */ HASHID nm = DEREF_hashid (id_name (id)); TYPE dt = DEREF_type (hashid_destr_type (nm)); if (IS_type_compound (dt)) { /* Check inheritance */ CLASS_TYPE dct = DEREF_ctype (type_compound_defn (dt)); NAMESPACE dns = DEREF_nspace (ctype_member (dct)); if (!EQ_nspace (dns, ns)) { report (crt_loc, ERR_class_dtor_inherit (nm, ns)); } } /* No return type can be given for a destructor */ if (is_type_inferred (r) != INFERRED_EMPTY) { report (crt_loc, ERR_class_dtor_ret (nm)); } COPY_type (type_func_ret (t), type_void); /* No parameter types can be given for a destructor */ if (!IS_NULL_list (p) || ell) { report (crt_loc, ERR_class_dtor_pars (nm)); } /* A destructor cannot be cv-qualified */ if (cv & cv_qual) { report (crt_loc, ERR_class_dtor_qual (nm, cv)); } } return (t); } /* * CHECK A CONVERSION FUNCTION TYPE * * This routine checks the function type t for the conversion function id. * The check that the converter is a non-static member function is carried * out elsewhere. Note that no return type can be given for id - it is * inferred from the type used in id. This may not be a legal return type, * so inject_pre_type is used to check it. */ TYPE check_conv(TYPE t, IDENTIFIER id) { if (IS_type_templ (t)) { /* Allow for template types */ TYPE s = DEREF_type (type_templ_defn (t)); s = check_conv (s, id); COPY_type (type_templ_defn (t), s); } else { /* Find the conversion type */ HASHID nm = DEREF_hashid (id_name (id)); TYPE s = DEREF_type (hashid_conv_type (nm)); /* Decompose function type */ TYPE r = DEREF_type (type_func_ret (t)); int ell = DEREF_int (type_func_ellipsis (t)); LIST (TYPE) p = DEREF_list (type_func_ptypes (t)); /* No return type can be given for a conversion function */ if (is_type_inferred (r) != INFERRED_EMPTY) { /* If a return type is given it might as well be right */ if (eq_type (r, s)) { report (crt_loc, ERR_class_conv_fct_ret (nm)); } else { report (crt_loc, ERR_class_conv_fct_ret_bad (nm, r)); } } COPY_type (type_func_ret (t), NULL_type); t = inject_pre_type (t, s, 0); /* No parameter types can be given for a conversion function */ if (!IS_NULL_list (p) || ell) { report (crt_loc, ERR_class_conv_fct_pars (nm)); } /* Can't have conversion to cv-qualified void */ if (IS_type_top_etc (s)) { report (crt_loc, ERR_class_conv_fct_void (nm)); } } return (t); } /* * LOOK UP AN OVERLOADED OPERATOR FUNCTION * * This routine looks up the overloaded operator function 'operator op' * in the class ct. */ IDENTIFIER find_operator(CLASS_TYPE ct, int op) { HASHID nm = lookup_op (op); NAMESPACE cns = DEREF_nspace (ctype_member (ct)); IDENTIFIER id = search_field (cns, nm, 0, 0); return (id); } /* * FIND A DEFAULT CONSTRUCTOR OR DESTRUCTOR * * This routine finds either a default constructor, a copy constructor, * a default destructor or a copy assignment operator of the class ct, * depending on the value of n. The null identifier is returned and * an error is added to err if such a function does not exist (including * for incomplete types). */ static IDENTIFIER find_constr(CLASS_TYPE ct, int n, ERROR *err) { CLASS_INFO ci; int match = 0; int nargs = 0; int kind = KIND_FUNC; IDENTIFIER id = NULL_id; IDENTIFIER qid = NULL_id; /* Check for complete types */ complete_class (ct, 1); ci = DEREF_cinfo (ctype_info (ct)); if (!(ci & cinfo_complete)) return (NULL_id); /* Find the basic identifier */ switch (n) { case DEFAULT_CONSTR : case DEFAULT_COPY : case DEFAULT_USR : { /* Find constructors */ id = DEREF_id (ctype_constr (ct)); if (n == DEFAULT_COPY) nargs = 1; kind = KIND_CONSTR; break; } case DEFAULT_DESTR : case DEFAULT_DELETE : { /* Find destructors */ id = DEREF_id (ctype_destr (ct)); nargs = 1; break; } case DEFAULT_ASSIGN : { /* Find 'operator =' */ id = find_operator (ct, lex_assign); nargs = 2; break; } } /* Find appropriate function */ if (!IS_NULL_id (id) && IS_id_mem_func (id)) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (ds & dspec_template) { /* Allow for template constructors */ match = 2; } else { switch (n) { case DEFAULT_CONSTR : case DEFAULT_DESTR : case DEFAULT_DELETE : case DEFAULT_USR : { /* Should take no arguments */ IDENTIFIER pid = id; while (!IS_NULL_id (pid)) { TYPE t = DEREF_type (id_mem_func_type (pid)); if (min_no_args (t) == 1) { qid = pid; match++; } pid = DEREF_id (id_mem_func_over (pid)); } break; } case DEFAULT_COPY : case DEFAULT_ASSIGN : { /* Should be a copy constructor */ IDENTIFIER pid = id; while (!IS_NULL_id (pid)) { TYPE t = DEREF_type (id_mem_func_type (pid)); if (check_copy_constr (t, ct)) { qid = pid; match++; } pid = DEREF_id (id_mem_func_over (pid)); } break; } } } } else { /* This can only happen for dummy classes */ return (NULL_id); } /* Deal with ambiguous cases */ if (match > 1) { CANDIDATE_LIST *p = &candidates; p->size = 0; add_candidates (p, id, 1, KIND_CONSTR); if (p->size) { CANDIDATE *q; unsigned rank; TYPE t = make_class_type (ct); LIST (EXP) args = NULL_list (EXP); while (nargs) { /* Create dummy arguments */ EXP a; MAKE_exp_value (t, a); CONS_exp (a, args, args); nargs--; } if (kind == KIND_CONSTR) { swap_candidates (p, (unsigned) 0); } q = resolve_overload (p, args, t, 0); if (kind == KIND_CONSTR) { swap_candidates (p, (unsigned) 0); } rank = q->rank; if (rank >= RANK_VIABLE) { qid = q->func; if (rank == RANK_BEST) { /* Best match */ if (match_no_viable > 1) { ERROR err2; if (kind == KIND_CONSTR) { err2 = ERR_over_match_ctor_ok (qid); } else { err2 = ERR_over_match_call_ok (qid); } add_error (err, err2); } match = 1; } else { /* Ambiguous call */ ERROR err2; if (kind == KIND_CONSTR) { err2 = ERR_over_match_ctor_ambig (qid); } else { err2 = ERR_over_match_call_ambig (qid); } err2 = list_candidates (err2, p, RANK_VIABLE); add_error (err, err2); } } else { /* No viable call */ qid = NULL_id; match = 0; } if (!IS_NULL_list (args)) free_exp_list (args, 1); } else { /* No viable call */ qid = NULL_id; match = 0; } } /* Report error */ if (match == 0) { switch (n) { case DEFAULT_CONSTR : case DEFAULT_USR : { add_error (err, ERR_class_ctor_default (ct)); break; } case DEFAULT_COPY : { add_error (err, ERR_class_copy_constr (ct)); break; } case DEFAULT_DESTR : case DEFAULT_DELETE : { add_error (err, ERR_class_dtor_default (ct)); break; } case DEFAULT_ASSIGN : { add_error (err, ERR_class_copy_assign (ct)); break; } } } return (qid); } /* * FIND NUMBER OF EXTRA CONSTRUCTOR ARGUMENTS * * This routine finds the number of extra constructor arguments required * by the member function id of the class ct. For constructors and * assignment operators for classes with a virtual base the extra * argument is true to indicate that the virtual components should be * initialised. For non-trivial destructors bit 1 of the extra argument * is used to indicate that any virtual components should be destroyed, * while bit 0 is used to indicate that 'operator delete' should be * called on the argument. The macros EXTRA_* are used to represent * these values. */ unsigned extra_constr_args(IDENTIFIER id, CLASS_TYPE ct) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (!(ds & dspec_trivial)) { HASHID nm = DEREF_hashid (id_name (id)); unsigned tag = TAG_hashid (nm); if (tag == hashid_constr_tag) { /* Constructors */ CLASS_INFO ci = DEREF_cinfo (ctype_info (ct)); if (ci & cinfo_virtual_base) return (1); } else if (tag == hashid_destr_tag) { /* Destructors */ return (1); } } return (0); } /* * CONSTRUCTOR BASE CLASS INITIALISER FLAG * * This flag is set to true in a constructor base class initialiser. * This overrides the value of any extra arguments passed to the * constructor. */ static int in_ctor_base_init = 0; /* * ADD EXTRA CONSTRUCTOR ARGUMENTS * * This routine adds any necessary extra constructor arguments to the * member function call expression e. ct gives the associate class * type and v is the value to be passed to such arguments. */ EXP add_constr_args(EXP e, CLASS_TYPE ct, int v) { if (IS_exp_func_id (e)) { IDENTIFIER id = DEREF_id (exp_func_id_id (e)); unsigned n = extra_constr_args (id, ct); if (n) { LIST (EXP) args = DEREF_list (exp_func_id_args (e)); LIST (EXP) extra = NULL_list (EXP); if (in_ctor_base_init) v = 0; while (n) { EXP a; NAT c = small_nat [v]; MAKE_exp_int_lit (type_sint, c, exp_int_lit_tag, a); CONS_exp (a, extra, extra); n--; } args = APPEND_list (args, extra); COPY_list (exp_func_id_args (e), args); } } return (e); } /* * CALL A CONSTRUCTOR OR DESTRUCTOR * * This routine constructs a default call of the constructor or destructor * id of type n. ct gives the corresponding class type and pb gives the * second argument for copy constructors and assignment operators. */ static EXP call_constr(IDENTIFIER id, EXP *pb, int n, int v, CLASS_TYPE ct) { /* Create argument list */ TYPE t; EXP e, a, b; LIST (EXP) args = NULL_list (EXP); IDENTIFIER cid = DEREF_id (ctype_name (ct)); MAKE_type_compound (cv_lvalue, ct, t); COPY_id (type_name (t), cid); MAKE_exp_dummy (t, NULL_exp, LINK_NONE, NULL_off, 0, a); if (n == DEFAULT_ASSIGN || n == DEFAULT_DELETE) { /* Don't know object type */ COPY_int (exp_dummy_virt (a), 1); } if (n == DEFAULT_COPY || n == DEFAULT_ASSIGN) { /* These have two arguments */ TYPE s = t; int virt = 1; b = *pb; if (!IS_NULL_exp (b)) { s = DEREF_type (exp_type (b)); while (IS_type_array (s)) { s = DEREF_type (type_array_sub (s)); } s = lvalue_type (s); if (know_type (b)) virt = 0; } MAKE_exp_dummy (s, b, LINK_NONE, NULL_off, DUMMY_copy, b); COPY_int (exp_dummy_virt (b), virt); CONS_exp (b, args, args); *pb = b; } else { /* These have one argument */ b = a; } CONS_exp (a, args, args); /* Call the function */ use_func_id (id, 0, suppress_usage); e = apply_func_id (id, qual_none, NULL_graph, args); e = add_constr_args (e, ct, v); if (n == DEFAULT_DESTR || n == DEFAULT_DELETE) { MAKE_exp_destr (type_void, e, a, e); } else { t = make_class_type (ct); MAKE_exp_constr (t, e, a, b, n, e); } return (e); } /* * CREATE A DEFAULT INITIALISER * * This routine creates a default initialiser for an object of type t * in a constructor, destructor or assignment operator (as indicated * by n). Any resultant errors are added to err. */ EXP init_default(TYPE t, EXP *pa, int n, int v, ERROR *err) { CV_SPEC cv; EXP e = NULL_exp; unsigned tag = TAG_type (t); /* Deal with classes */ if (tag == type_compound_tag) { CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); IDENTIFIER id = find_constr (ct, n, err); if (!IS_NULL_id (id)) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (!(ds & dspec_trivial)) { /* Non-trivial constructor */ e = call_constr (id, pa, n, v, ct); } else if (ds & dspec_implicit) { if (!(ds & dspec_defn)) { /* Trivial constructor */ implicit_defn (id, n); } } } return (e); } /* Deal with arrays */ if (tag == type_array_tag) { NAT m = DEREF_nat (type_array_size (t)); TYPE s = DEREF_type (type_array_sub (t)); e = init_default (s, pa, n, v, err); if (!IS_NULL_exp (e)) { /* Apply to each array element */ MAKE_exp_nof (t, NULL_exp, m, e, NULL_exp, e); } return (e); } /* Everything else is alright in these cases */ if (n == DEFAULT_COPY || n == DEFAULT_DESTR || n == DEFAULT_DELETE) { return (NULL_exp); } /* Deal with references */ if (tag == type_ref_tag) { add_error (err, ERR_dcl_init_ref_none ()); if (n == DEFAULT_ASSIGN) return (NULL_exp); MAKE_exp_null (t, e); return (e); } /* Deal with const objects */ cv = DEREF_cv (type_qual (t)); if (cv & cv_const) add_error (err, ERR_dcl_init_const ()); return (NULL_exp); } /* * REPORT AN INITIALISATION ERROR * * This routine reports the error err which occurred in the initialisation * of id in constructor or destructor fn of type n. */ static void constr_error(ERROR err, IDENTIFIER id, IDENTIFIER fn, int n) { ERROR err1; ERROR err2 = ERR_dcl_init_decl (id, NULL_string); if (n == DEFAULT_USR) { err1 = ERR_class_base_init_err (fn); } else { err1 = ERR_class_base_init_impl (fn); } err = concat_error (err2, err); err = concat_error (err1, err); report (crt_loc, err); return; } /* * CREATE A BASE CLASS INITIALISER * * This routine creates a default initialiser for the base class gr * for the constructor or destructor fn of type n. For copy constructors * and assignment operators a dummy expression is used to indicate that * the base should be initialised from the corresponding base of the * second argument (see enc_ctor_exp). */ static EXP init_empty_base(GRAPH gr, IDENTIFIER fn, int n, int m) { EXP e = NULL_exp; ERROR err = NULL_err; CLASS_TYPE ct = DEREF_ctype (graph_head (gr)); TYPE t = make_class_type (ct); e = init_default (t, &e, m, EXTRA_NONE, &err); if (IS_NULL_exp (e)) { if (n == DEFAULT_USR && m != DEFAULT_DESTR) { /* Warn about uninitialised bases */ if (!is_empty_class (t)) { IDENTIFIER id = DEREF_id (ctype_name (ct)); err = concat_error (err, ERR_class_base_init_none (id)); } } if (m == DEFAULT_COPY || m == DEFAULT_ASSIGN) { /* Dummy value for copy constructor */ MAKE_exp_value (t, e); } } if (!IS_NULL_err (err)) { IDENTIFIER id = DEREF_id (ctype_name (ct)); constr_error (err, id, fn, n); } return (e); } /* * CREATE A CLASS MEMBER INITIALISER * * This routine creates a default initialiser for a class member id * for the constructor or destructor fn of type n. Again a dummy value * is used in copy constructors and assignment operators. */ static EXP init_empty_mem(IDENTIFIER id, IDENTIFIER fn, int n, int m) { EXP e = NULL_exp; ERROR err = NULL_err; TYPE t = DEREF_type (id_member_type (id)); int v = (m == DEFAULT_DESTR ? EXTRA_DESTR : EXTRA_CONSTR); e = init_default (t, &e, m, v, &err); if (IS_NULL_exp (e)) { if (m == DEFAULT_COPY || m == DEFAULT_ASSIGN) { /* Dummy value for copy constructor */ if (IS_type_ptr (t)) { DECL_SPEC ds = DEREF_dspec (id_storage (fn)); if (!(ds & dspec_trivial)) { /* Warn about shallow copies */ err = concat_error (err, ERR_class_copy_ptr ()); } } MAKE_exp_value (t, e); } } if (!IS_NULL_err (err)) { constr_error (err, id, fn, n); } return (e); } /* * LISTS OF CONSTRUCTOR INITIALISERS * * These lists are built up by the constructor initialisers. */ static LIST (GRAPH) init_bases = NULL_list (GRAPH); static LIST (EXP) val_bases = NULL_list (EXP); static LIST (IDENTIFIER) init_mems = NULL_list (IDENTIFIER); static LIST (EXP) val_mems = NULL_list (EXP); static unsigned long no_ctor_init = 0; static int init_base_last = 1; /* * CLEAR THE LISTS OF CONSTRUCTOR INITIALISERS * * This routine clears the lists of constructor initialisers above. */ static void destroy_ctor_lists() { IGNORE check_value (OPT_VAL_ctor_initializers, no_ctor_init); DESTROY_list (init_bases, SIZE_graph); DESTROY_list (val_bases, SIZE_exp); DESTROY_list (init_mems, SIZE_id); DESTROY_list (val_mems, SIZE_exp); init_bases = NULL_list (GRAPH); val_bases = NULL_list (EXP); init_mems = NULL_list (IDENTIFIER); val_mems = NULL_list (EXP); init_base_last = 1; no_ctor_init = 0; return; } /* * FIND A BASE CLASS INITIALISER * * This routine finds the base class initialiser for gr in the lists * given above. If gr is a member of init_bases then the corresponding * element of val_bases is returned, otherwise the null expression is * returned. */ static EXP find_base_init(GRAPH gr) { LIST (GRAPH) p = init_bases; LIST (EXP) q = val_bases; while (!IS_NULL_list (p)) { GRAPH gs = DEREF_graph (HEAD_list (p)); if (eq_graph (gs, gr)) { /* Found graph - return corresponding expression */ EXP e = DEREF_exp (HEAD_list (q)); return (e); } q = TAIL_list (q); p = TAIL_list (p); } return (NULL_exp); } /* * FIND A CLASS MEMBER INITIALISER * * This routine finds the class member initialiser for id in the lists * given above. If id is a member of init_mems then the corresponding * element of val_mems is returned, otherwise the null expression is * returned. */ static EXP find_mem_init(IDENTIFIER id) { LIST (IDENTIFIER) p = init_mems; LIST (EXP) q = val_mems; while (!IS_NULL_list (p)) { IDENTIFIER mid = DEREF_id (HEAD_list (p)); if (EQ_id (mid, id)) { /* Found identifier - return corresponding expression */ EXP e = DEREF_exp (HEAD_list (q)); return (e); } q = TAIL_list (q); p = TAIL_list (p); } return (NULL_exp); } /* * MARK A DESTRUCTOR * * This routine marks the initialiser expression e for an object of type t * if t has a non-trivial destructor by enclosing it in parentheses. */ static EXP destr_init(TYPE t, EXP e) { TYPE s = t; while (IS_type_array (s)) { s = DEREF_type (type_array_sub (s)); } if (IS_type_compound (s)) { CLASS_TYPE cs = DEREF_ctype (type_compound_defn (s)); IDENTIFIER id = DEREF_id (ctype_destr (cs)); if (IS_id_mem_func (id)) { DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (!(ds & dspec_trivial)) { if (ds & dspec_implicit) { if (!(ds & dspec_defn)) { /* Trivial constructor */ implicit_defn (id, DEFAULT_DESTR); } } MAKE_exp_paren (t, e, e); } } } return (e); } /* * CREATE A CONSTRUCTOR OR DESTRUCTOR * * This routine creates a constructor or destructor initialiser list. * cns gives the corresponding class namespace and fn is the function * name. n and m indicate the constructor or destructor type. This can * be an implicitly declared constructor, destructor or assignment * function, or an explicitly declared constructor. In the latter * case the ctor-initialiser lists above are used to indicate the * initialiser values. */ static EXP make_constr(NAMESPACE cns, IDENTIFIER fn, int n, int m) { EXP r; int usr = 0; int str = 1; unsigned nv = 0; unsigned nb = 0; unsigned long no = 0; int templ = in_template_decl; LIST (EXP) p = NULL_list (EXP); LIST (OFFSET) q = NULL_list (OFFSET); /* Deconstruct class type */ CLASS_TYPE ct = namespace_class (cns); CLASS_INFO ci = DEREF_cinfo (ctype_info (ct)); GRAPH gr = DEREF_graph (ctype_base (ct)); LIST (GRAPH) br = DEREF_list (graph_tails (gr)); LIST (GRAPH) bv = DEREF_list (ctype_vbase (ct)); MEMBER mem = DEREF_member (nspace_ctype_first (cns)); /* Mark 'this' parameter as used */ crt_access_list.inherit++; IGNORE this_param (fn, 1); /* Check for user-defined constructors */ if (n == DEFAULT_USR && m == DEFAULT_CONSTR) usr = 1; /* Initialise virtual bases */ if (m != DEFAULT_ASSIGN) { while (!IS_NULL_list (bv)) { EXP e = NULL_exp; GRAPH gs = DEREF_graph (HEAD_list (bv)); DECL_SPEC acc = DEREF_dspec (graph_access (gs)); if (usr) e = find_base_init (gs); if (IS_NULL_exp (e) && !(acc & dspec_template)) { e = init_empty_base (gs, fn, n, m); if (templ) { /* Only testing for template classes */ free_exp (e, 1); e = NULL_exp; } } if (m == DEFAULT_CONSTR && !templ) { CLASS_TYPE cs = DEREF_ctype (graph_head (gs)); TYPE s = make_class_type (cs); e = destr_init (s, e); } if (!IS_NULL_exp (e)) { OFFSET off = DEREF_off (graph_off (gs)); CONS_off (off, q, q); CONS_exp (e, p, p); nv++; } bv = TAIL_list (bv); } } /* Initialise direct bases */ while (!IS_NULL_list (br)) { EXP e = NULL_exp; GRAPH gs = DEREF_graph (HEAD_list (br)); DECL_SPEC acc = DEREF_dspec (graph_access (gs)); if (!(acc & dspec_virtual) || m == DEFAULT_ASSIGN) { if (usr) e = find_base_init (gs); if (IS_NULL_exp (e) && !(acc & dspec_template)) { e = init_empty_base (gs, fn, n, m); if (templ) { /* Only testing for template classes */ free_exp (e, 1); e = NULL_exp; } } if (m == DEFAULT_CONSTR && !templ) { CLASS_TYPE cs = DEREF_ctype (graph_head (gs)); TYPE s = make_class_type (cs); e = destr_init (s, e); } if (!IS_NULL_exp (e)) { OFFSET off = DEREF_off (graph_off (gs)); CONS_off (off, q, q); CONS_exp (e, p, p); nb++; } } br = TAIL_list (br); } /* Initialise data members */ member_no = no; mem = next_data_member (mem, 2); if (usr && (ci & cinfo_union)) { /* Check union initialisers */ unsigned ni = LENGTH_list (init_mems); if (ni) { if (ni > 1) { /* More than one initialiser for union */ report (crt_loc, ERR_class_base_init_union (ct)); } str = 0; } } while (!IS_NULL_member (mem)) { EXP e = NULL_exp; IDENTIFIER id = DEREF_id (member_id (mem)); if (usr) { e = find_mem_init (id); if (!IS_NULL_exp (e)) { if (no == member_no) { /* More than one initialiser for anonymous union */ report (crt_loc, ERR_class_base_init_anon (id)); } no = member_no; } } if (IS_NULL_exp (e) && str) { e = init_empty_mem (id, fn, n, m); if (templ) { /* Only testing for template classes */ free_exp (e, 1); e = NULL_exp; } } if (m == DEFAULT_CONSTR && !templ) { TYPE s = DEREF_type (id_member_type (id)); e = destr_init (s, e); } if (!IS_NULL_exp (e)) { OFFSET off = DEREF_off (id_member_off (id)); e = check_init (e); CONS_off (off, q, q); CONS_exp (e, p, p); } if (ci & cinfo_union) { if (!usr) break; str = 0; } mem = DEREF_member (member_next (mem)); mem = next_data_member (mem, 2); } /* Construct the result */ crt_access_list.inherit--; if (IS_NULL_list (p)) { DECL_SPEC ds = DEREF_dspec (id_storage (fn)); if (ds & dspec_trivial) return (NULL_exp); if (m != DEFAULT_DESTR && !templ) { if (ci & (cinfo_virtual_base | cinfo_polymorphic)) { /* These require an initialiser */ /* EMPTY */ } else { return (NULL_exp); } } } if (m != DEFAULT_DESTR) { /* Initialisers are built in reverse order */ p = REVERSE_list (p); q = REVERSE_list (q); } MAKE_exp_initialiser (type_void, p, q, m, nv, nb, r); return (r); } /* * CREATE A DESTRUCTOR PRELUDE EXPRESSION * * The destruction of the base classes and members of a class takes * place at the end of the destructor, and it is this which is handled * by make_constr. However for polymorphic classes some action is * also required at the start of the destructor, namely the resetting * of the virtual function tables. This routine creates a dummy * initialiser expression which performs this action. */ static EXP make_destr_prelude(NAMESPACE cns) { EXP r = NULL_exp; CLASS_TYPE ct = namespace_class (cns); CLASS_INFO ci = DEREF_cinfo (ctype_info (ct)); if (ci & cinfo_polymorphic) { /* Create dummy initialiser */ MAKE_exp_initialiser (type_void, NULL_list (EXP), NULL_list (OFFSET), DEFAULT_PRELUDE, 0, 0, r); } return (r); } /* * COPY A CONSTRUCTOR INITIALISER LIST * * This routine copies the constructor initialiser list of type m. */ EXP copy_ctor(EXP e, int m) { IDENTIFIER fn = crt_func_id; NAMESPACE cns = DEREF_nspace (id_parent (fn)); LIST (EXP) p = DEREF_list (exp_initialiser_args (e)); LIST (OFFSET) q = DEREF_list (exp_initialiser_offs (e)); if (!IS_NULL_list (p)) { /* Copy initialisers */ while (!IS_NULL_list (p) && !IS_NULL_list (q)) { int redo = 0; IDENTIFIER id = NULL_id; EXP a = DEREF_exp (HEAD_list (p)); OFFSET off = DEREF_off (HEAD_list (q)); EXP b = implicit_cast_exp (a); if (!IS_NULL_exp (b) && !EQ_exp (b, a)) { redo = 1; a = b; } a = copy_exp (a, NULL_type, NULL_type); if (redo && !IS_exp_initialiser (a)) { /* Turn expression into ctor-initialiser list */ LIST (EXP) r = NULL_list (EXP); LIST (OFFSET) s = NULL_list (OFFSET); CONS_exp (a, r, r); MAKE_exp_initialiser (type_void, r, s, 0, 0, 0, a); } off = copy_offset (off, lex_plus); switch (TAG_off (off)) { case off_member_tag : { /* Member initialiser */ id = DEREF_id (off_member_id (off)); break; } case off_base_tag : { /* Direct base class initialiser */ GRAPH gr = DEREF_graph (off_base_graph (off)); CLASS_TYPE ct = DEREF_ctype (graph_head (gr)); id = DEREF_id (ctype_name (ct)); break; } case off_deriv_tag : { /* Indirect base class initialiser */ GRAPH gr = DEREF_graph (off_deriv_graph (off)); CLASS_TYPE ct = DEREF_ctype (graph_head (gr)); id = DEREF_id (ctype_name (ct)); break; } } if (!IS_NULL_id (id)) { /* Add initialiser to list */ ctor_initialise (cns, id, a); } q = TAIL_list (q); p = TAIL_list (p); } } e = make_constr (cns, fn, DEFAULT_USR, m); destroy_ctor_lists (); return (e); } /* * BEGIN A CONSTRUCTOR INITIALISER LIST * * This routine is called at the start of a ctor-initialiser list to * check that the current function is a constructor. If so it returns * the corresponding class namespace. Otherwise the null namespace * is returned. */ NAMESPACE ctor_begin() { IDENTIFIER id = crt_func_id; HASHID nm = DEREF_hashid (id_name (id)); if (IS_hashid_constr (nm)) { TYPE t = DEREF_type (hashid_constr_type (nm)); if (IS_type_compound (t)) { CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); NAMESPACE cns = DEREF_nspace (ctype_member (ct)); return (cns); } } report (crt_loc, ERR_class_base_init_bad (id)); return (NULL_nspace); } /* * END A CONSTRUCTOR INITIALISER LIST * * This routine is called at the end of a ctor-initialiser list. cns * gives the class namespace, e is the compound statement to which * the initialisers are to be added and elem is true if the list was * not empty. The routine returns the resultant compound statement. */ EXP ctor_end(NAMESPACE cns, EXP e, int elem) { if (!IS_NULL_nspace (cns)) { /* Construct the constructor */ IDENTIFIER id = crt_func_id; if (!elem) report (crt_loc, ERR_class_base_init_empty (id)); if (IS_id_mem_func (id)) { EXP c = make_constr (cns, id, DEFAULT_USR, DEFAULT_CONSTR); if (!IS_NULL_exp (c)) { e = add_compound_stmt (e, c); } } destroy_ctor_lists (); } return (e); } /* * HANDLE AN ABSENT CONSTRUCTOR INITIALISER LIST * * This routine is called for a function definition which contains no * ctor-initialiser. e gives the compound statement giving the function * body. The routine returns the value of e after any initialisers * required for constructors have been added. Any destructors which need * to be called at the end of the function are returned via p. */ EXP ctor_none(EXP e, EXP *p) { IDENTIFIER id = crt_func_id; if (IS_id_mem_func (id)) { HASHID nm = DEREF_hashid (id_name (id)); switch (TAG_hashid (nm)) { case hashid_constr_tag : { /* Constructor declarations */ NAMESPACE cns = DEREF_nspace (id_parent (id)); EXP c = make_constr (cns, id, DEFAULT_USR, DEFAULT_CONSTR); if (!IS_NULL_exp (c)) { /* Add initialiser to function body */ e = add_compound_stmt (e, c); } break; } case hashid_destr_tag : { /* Destructor declarations */ NAMESPACE cns = DEREF_nspace (id_parent (id)); EXP c = make_destr_prelude (cns); EXP d = make_constr (cns, id, DEFAULT_USR, DEFAULT_DESTR); if (!IS_NULL_exp (c)) { /* Add destructor prelude to function body */ e = add_compound_stmt (e, c); } if (!IS_NULL_exp (d)) { /* Set up destructor postlude */ IDENTIFIER lab = postlude_label (); EXP a = begin_label_stmt (lab, lex_return); *p = end_label_stmt (a, d); } break; } } } return (e); } /* * ADD A POSTLUDE TO A FUNCTION BODY * * This routine adds the postlude expression d to the end of the * function body e. This is used in user declared destructors where the * default destructors need to be called after the main function body. * For convenience the code for falling out of a normal function body * is also handled by this routine. */ EXP ctor_postlude(EXP e, EXP d) { if (!IS_NULL_exp (d)) { /* Add postlude expression */ EXP r; unreached_code = 0; e = add_compound_stmt (e, d); unreached_code = 0; MAKE_exp_return_stmt (type_bottom, NULL_exp, r); e = add_compound_stmt (e, r); unreached_code = 1; unreached_last = 0; } else { /* Fall out of function */ if (!unreached_code) { EXP r = fall_return_stmt (); e = add_compound_stmt (e, r); } } return (e); } /* * CREATE AN EXCEPTION POSTLUDE EXPRESSION * * This routine creates an expression which will be called in the exception * specifier for the function id. This is used in constructors to destroy * the partially complete object. */ EXP except_postlude(IDENTIFIER id) { EXP e = NULL_exp; HASHID nm = DEREF_hashid (id_name (id)); if (IS_hashid_constr (nm)) { /* Have a constructor */ TYPE t = DEREF_type (hashid_constr_type (nm)); if (IS_type_compound (t)) { CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); NAMESPACE cns = DEREF_nspace (ctype_member (ct)); DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (!(ds & (dspec_friend | dspec_trivial))) { /* Constructor may throw an exception */ int ac = do_access_checks; EXP a = DEREF_exp (id_function_etc_defn (id)); if (!IS_NULL_exp (a) && IS_exp_initialiser (a)) { LIST (EXP) p; p = DEREF_list (exp_initialiser_args (a)); if (LENGTH_list (p) == 1) { /* Single initialiser in constructor */ a = DEREF_exp (HEAD_list (p)); if (!IS_NULL_exp (a)) { TYPE s = DEREF_type (exp_type (a)); if (!IS_type_array (s)) return (e); } } } do_access_checks = 0; COPY_dspec (id_storage (id), (ds | dspec_trivial)); start_try_check (univ_type_set); e = make_constr (cns, id, DEFAULT_DESTR, DEFAULT_DESTR); if (!IS_NULL_exp (e)) { /* Add destructor prelude */ EXP d = make_destr_prelude (cns); e = join_exp (d, e); } e = end_try_check (id, e); COPY_dspec (id_storage (id), ds); do_access_checks = ac; } } } return (e); } /* * FIND INITIALISATION ORDER OF TWO BASE GRAPHS * * This routine compares the order of initialisation of the base graphs * gr and gs. It returns 1 if gr is initialised before gs, -1 if gr is * initialised before gr and 0 if they are equal. Note that virtual * bases are initialised before direct bases. */ static int compare_base(GRAPH gr, GRAPH gs) { DECL_SPEC ar, as; LIST (GRAPH) br; if (eq_graph (gr, gs)) return (0); ar = DEREF_dspec (graph_access (gr)); as = DEREF_dspec (graph_access (gs)); if (ar & dspec_virtual) { if (as & dspec_virtual) { GRAPH gt = DEREF_graph (graph_top (gr)); CLASS_TYPE ct = DEREF_ctype (graph_head (gt)); br = DEREF_list (ctype_vbase (ct)); } else { return (1); } } else { if (as & dspec_virtual) { return (-1); } else { GRAPH gt = DEREF_graph (graph_top (gr)); br = DEREF_list (graph_tails (gt)); } } while (!IS_NULL_list (br)) { GRAPH gt = DEREF_graph (HEAD_list (br)); if (eq_graph (gt, gr)) return (1); if (eq_graph (gt, gs)) return (-1); br = TAIL_list (br); } return (0); } /* * FIND INITIALISATION ORDER OF TWO MEMBERS * * This routine compares the order of initialisation of the members pid * and mid of the class namespace ns. It returns 1 if mid is initialised * before pid, -1 if pid is initialised before mid and 0 if they are equal. */ static int compare_mem(NAMESPACE ns, IDENTIFIER mid, IDENTIFIER pid) { MEMBER mem; if (EQ_id (mid, pid)) return (0); mem = DEREF_member (nspace_ctype_first (ns)); while (!IS_NULL_member (mem)) { IDENTIFIER id = DEREF_id (member_id (mem)); if (EQ_id (id, mid)) return (1); if (EQ_id (id, pid)) return (-1); mem = DEREF_member (member_next (mem)); } return (0); } /* * NAME LOOK-UP FOR CONSTRUCTOR INITIALISER * * This routine looks up the name id as a ctor-initialiser for the class * cns. If it denotes a base class then the corresponding graph is * returned via pgr. If id is the null identifier then this is an * anachronistic way of initialising the unique direct base class of * cns, if this exists. The null identifier is returned for illegal * initialisers. */ static IDENTIFIER ctor_field(NAMESPACE cns, IDENTIFIER id, GRAPH *pgr) { if (!IS_NULL_nspace (cns)) { if (IS_NULL_id (id)) { /* Search for unique base class */ ERROR err = ERR_class_base_init_old (crt_func_id); CLASS_TYPE ct = namespace_class (cns); GRAPH gr = uniq_base_class (ct, &err); if (!IS_NULL_graph (gr)) { ct = DEREF_ctype (graph_head (gr)); id = DEREF_id (ctype_name (ct)); *pgr = gr; } else { id = NULL_id; } report (crt_loc, err); } else { /* Look up name as class member */ GRAPH gr; int check_base = 1; IDENTIFIER fid = id; NAMESPACE fns = DEREF_nspace (id_parent (fid)); if (EQ_nspace (fns, crt_namespace)) { /* Rescan constructor parameters in enclosing scope */ HASHID nm = DEREF_hashid (id_name (fid)); int c = cache_lookup; cache_lookup = 0; remove_namespace (); fid = find_id (nm); add_namespace (fns); cache_lookup = c; id = fid; } /* Check for class members */ gr = is_subfield (cns, fid); if (!IS_NULL_graph (gr)) { check_base = 0; fid = search_subfield (cns, gr, fid); switch (TAG_id (fid)) { case id_member_tag : { /* Non-static data members */ DECL_SPEC ds = DEREF_dspec (id_storage (fid)); if (ds & dspec_inherit) { /* Can't denote an inherited member */ ERROR err; err = ERR_class_base_init_inherit (fid); report (crt_loc, err); id = NULL_id; } else { id = fid; } break; } case id_class_name_tag : case id_class_alias_tag : { /* Check for base classes */ check_base = 1; break; } case id_undef_tag : { /* Undeclared members */ HASHID nm = DEREF_hashid (id_name (fid)); ERROR err = ERR_lookup_qual_undef (nm, fns); report (crt_loc, err); id = NULL_id; break; } case id_ambig_tag : { /* Ambiguous members */ id = report_ambiguous (fid, 0, 1, 1); break; } default : { /* Other members */ ERROR err = ERR_class_base_init_static (fid); report (crt_loc, err); id = NULL_id; break; } } } /* Check for base classes */ if (check_base) { CLASS_TYPE cs = find_class (fid); if (IS_NULL_ctype (cs) && IS_id_undef (fid)) { TYPE s = check_typename (fns, fid, btype_class); if (!IS_NULL_type (s) && IS_type_compound (s)) { cs = DEREF_ctype (type_compound_defn (s)); } } if (!IS_NULL_ctype (cs)) { /* Class name found */ ERROR err = NULL_err; CLASS_TYPE ct = namespace_class (cns); gr = direct_base_class (ct, cs, &err); if (!IS_NULL_err (err)) { /* Report invalid bases */ report (crt_loc, err); } if (!IS_NULL_graph (gr)) { id = DEREF_id (ctype_name (cs)); *pgr = gr; } else { id = NULL_id; } } else { /* Invalid ctor-initialiser */ ERROR err = ERR_lookup_qual_bad (id, cns); report (crt_loc, err); id = NULL_id; } } } } else { /* Invalid class namespace */ id = NULL_id; } return (id); } /* * PROCESS A CONSTRUCTOR INITIALISER * * This routine processes a ctor-initialiser which sets the id component * of the current constructor function to the initialiser expression init. * cns gives the value returned by ctor_check. id may be the null * identifier indicating the anachronistic single inheritance base class * initialisation. */ void ctor_initialise(NAMESPACE cns, IDENTIFIER id, EXP init) { TYPE t; int n = 0; int ok = 1; GRAPH gr = NULL_graph; /* Check member identifier */ IDENTIFIER mid = ctor_field (cns, id, &gr); if (!IS_NULL_id (mid)) { EXP e; if (IS_id_member (mid)) { /* Member initialiser */ e = find_mem_init (mid); t = DEREF_type (id_member_type (mid)); n = 1; } else { /* Base class initialiser */ e = find_base_init (gr); t = DEREF_type (id_class_name_etc_defn (mid)); if (in_template_decl) { /* Allow for template parameters */ DECL_SPEC acc = DEREF_dspec (graph_access (gr)); if (acc & dspec_template) { CLASS_TYPE ct = DEREF_ctype (graph_head (gr)); t = DEREF_type (ctype_form (ct)); } } n = 2; } if (!IS_NULL_exp (e)) { /* Initialiser already given */ report (crt_loc, ERR_class_base_init_dup (mid)); } } else { /* Invalid initialiser */ HASHID nm = KEYWORD (lex_zzzz); mid = DEREF_id (hashid_id (nm)); t = type_error; } /* Check for order of initialisers */ if (init_base_last) { /* Previous initialiser was a base */ if (n == 2) { if (!IS_NULL_list (init_bases)) { GRAPH gp = DEREF_graph (HEAD_list (init_bases)); int cmp = compare_base (gr, gp); if (cmp > 0) ok = 0; } } } else { /* Previous initialiser was a member */ if (n == 1) { if (!IS_NULL_list (init_mems)) { IDENTIFIER pid = DEREF_id (HEAD_list (init_mems)); int cmp = compare_mem (cns, mid, pid); if (cmp > 0) ok = 0; } } else if (n == 2) { ok = 0; } } if (!ok) { /* Initialisers out of sequence */ report (crt_loc, ERR_class_base_init_order (mid)); } /* Perform initialisation */ if (IS_exp_initialiser (init)) { crt_access_list.inherit++; decl_loc = crt_loc; if (n == 2) in_ctor_base_init = 1; init = init_general (t, init, mid, 0); in_ctor_base_init = 0; crt_access_list.inherit--; } if (n == 1) { CONS_id (mid, init_mems, init_mems); CONS_exp (init, val_mems, val_mems); init_base_last = 0; } else if (n == 2) { CONS_graph (gr, init_bases, init_bases); CONS_exp (init, val_bases, val_bases); init_base_last = 1; } no_ctor_init++; return; } /* * CONSTRUCT A PSEUDO-DESTRUCTOR * * This routine creates a pseudo-destructor with class name given by * id1 and b1 and destructor name given by id2 and b2. */ IDENTIFIER make_pseudo_destr(IDENTIFIER id1, BASE_TYPE b1, IDENTIFIER id2, BASE_TYPE b2) { HASHID nm; int create = 0; int rescan = 0; TYPE t1 = NULL_type; TYPE t2 = NULL_type; NAMESPACE ns = NULL_nspace; /* Check class name */ if (b1 == btype_none) { if (!IS_NULL_id (id1)) { ns = find_namespace (id1); if (IS_id_class_name_etc (id1)) { t1 = DEREF_type (id_class_name_etc_defn (id1)); t1 = copy_typedef (id1, t1, cv_none); COPY_id (type_name (t1), id1); if (IS_NULL_nspace (ns)) { ns = DEREF_nspace (id_parent (id1)); } else { /* Have class name */ rescan = 1; } use_id (id1, 0); } else { if (!IS_NULL_nspace (ns) && !IS_NULL_id (id2)) { /* Namespace qualifier allowed */ create = 1; } else { report (crt_loc, ERR_dcl_type_simple_undef (id1)); } } } } else { t1 = make_base_type (b1); } /* Check destructor name */ if (b2 == btype_none) { if (!EQ_id (id2, id1)) { nm = DEREF_hashid (id_name (id2)); if (!IS_NULL_nspace (ns)) { /* Rescan id2 in the context of id1 */ IDENTIFIER id3 = find_qual_id (ns, nm, create, 1); if (!IS_NULL_id (id3)) id2 = id3; } if (IS_id_class_name_etc (id2)) { t2 = DEREF_type (id_class_name_etc_defn (id2)); t2 = copy_typedef (id2, t2, cv_none); COPY_id (type_name (t2), id2); use_id (id2, 0); } else { report (crt_loc, ERR_dcl_type_simple_undef (id2)); } } } else { if (b2 != b1) t2 = make_base_type (b2); } /* Form pseudo-destructor name */ if (IS_NULL_type (t2)) { t2 = t1; if (IS_NULL_type (t2)) t2 = type_error; } else { if (rescan) { /* Error will be caught in search_field */ /* EMPTY */ } else { if (!IS_NULL_type (t1) && !eq_type (t1, t2)) { /* If both specified, types should match */ report (crt_loc, ERR_expr_pseudo_type (t1, t2)); } } } nm = lookup_destr (t2, id2); id2 = DEREF_id (hashid_id (nm)); return (id2); } /* * DECLARATION SPECIFIERS FOR IMPLICIT CONSTRUCTORS * * This value gives the declaration specifiers used for implicitly declared * constructors and destructors. */ #define dspec_constr (dspec_implicit | dspec_ignore | dspec_inline) /* * ADD THE EXCEPTIONS THROWN BY A CONSTRUCTOR TO A LIST * * This routine adds the list of exceptions thrown by the implicit * constructor or destructor (given by n) of the class ct to the list p. */ static LIST (TYPE) add_constr_except(LIST (TYPE) p, CLASS_TYPE ct, int n) { IDENTIFIER id = find_constr (ct, n, KILL_err); if (!IS_NULL_id (id) && IS_id_mem_func (id)) { TYPE fn = DEREF_type (id_mem_func_type (id)); if (IS_type_func (fn)) { LIST (TYPE) q = DEREF_list (type_func_except (fn)); p = union_type_set (p, q); } } return (p); } /* * FIND EXCEPTIONS THROWN BY AN IMPLICIT CONSTRUCTOR * * This routine finds the list of exceptions thrown by the implicit * constructor or destructor (given by n) of the class ct. */ static LIST (TYPE) constr_except(CLASS_TYPE ct, int n) { LIST (TYPE) res = NULL_list (TYPE); GRAPH gr = DEREF_graph (ctype_base (ct)); LIST (GRAPH) br = DEREF_list (graph_tails (gr)); NAMESPACE cns = DEREF_nspace (ctype_member (ct)); MEMBER mem = DEREF_member (nspace_ctype_first (cns)); /* Scan through virtual bases */ if (n != DEFAULT_ASSIGN) { LIST (GRAPH) bv = DEREF_list (ctype_vbase (ct)); while (!IS_NULL_list (bv)) { GRAPH gs = DEREF_graph (HEAD_list (bv)); CLASS_TYPE cs = DEREF_ctype (graph_head (gs)); res = add_constr_except (res, cs, n); if (EQ_list (res, univ_type_set)) return (res); bv = TAIL_list (bv); } } /* Scan through direct bases */ while (!IS_NULL_list (br)) { GRAPH gs = DEREF_graph (HEAD_list (br)); DECL_SPEC acc = DEREF_dspec (graph_access (gs)); if (!(acc & dspec_virtual) || n == DEFAULT_ASSIGN) { CLASS_TYPE cs = DEREF_ctype (graph_head (gs)); res = add_constr_except (res, cs, n); if (EQ_list (res, univ_type_set)) return (res); } br = TAIL_list (br); } /* Scan through data members */ 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)); while (IS_type_array (s)) { s = DEREF_type (type_array_sub (s)); } if (IS_type_compound (s)) { CLASS_TYPE cs = DEREF_ctype (type_compound_defn (s)); res = add_constr_except (res, cs, n); if (EQ_list (res, univ_type_set)) return (res); } mem = DEREF_member (member_next (mem)); mem = next_data_member (mem, 2); } return (res); } /* * DECLARE IMPLICIT CONSTRUCTORS AND DESTRUCTORS * * This routine is called at the end of a class definition to implicitly * declare any necessary default constructors, copy constructors, assignment * operators or destructors. Note that these are only actually defined * if they are used, and errors are only detected at this definition stage. * The routine returns information on the class being defined. */ CLASS_INFO implicit_decl(CLASS_TYPE ct, CLASS_INFO ci, DECL_SPEC cds) { TYPE t; HASHID nm; IDENTIFIER id; TYPE pars [2]; CLASS_INFO cj; LIST (TYPE) ex; IDENTIFIER cid = DEREF_id (ctype_name (ct)); NAMESPACE ns = DEREF_nspace (ctype_member (ct)); LIST (IDENTIFIER) pals = DEREF_list (ctype_pals (ct)); /* Options being checked */ int need_copy_constr = 1; int need_default_constr = 1; int need_assignment_op = 1; int need_destructor = 1; int noncopy_constr = 0; int access_constr = 0; int access_destr = 0; int three_rule = 0; /* Find accumulated information */ cj = (ci & cinfo_implicit); if (ci & (cinfo_virtual_base | cinfo_polymorphic)) { cj &= ~cinfo_trivial_make; } ci &= ~cinfo_implicit; /* Check constructors */ id = DEREF_id (ctype_constr (ct)); if (IS_id_mem_func (id)) { IDENTIFIER fid = id; while (!IS_NULL_id (fid)) { TYPE fn = DEREF_type (id_mem_func_type (fid)); int c = check_copy_constr (fn, ct); if (c) { /* Copy constructor */ if (c == 2) ci |= cinfo_const_copy; need_copy_constr = 0; three_rule++; } else { /* Check access for other constructors */ DECL_SPEC acc = DEREF_dspec (id_storage (fid)); if ((acc & dspec_access) != dspec_private) { access_constr = 1; } noncopy_constr = 1; } fid = DEREF_id (id_mem_func_over (fid)); } ci |= cinfo_usr_constr; need_default_constr = 0; } else { /* Delete non-function meanings */ nm = DEREF_hashid (id_name (id)); clear_member (ns, nm); } /* Implicit declaration of default constructor */ if (need_default_constr) { DECL_SPEC ds = (dspec_constr | cds); if (cj & cinfo_trivial_constr) { ci |= cinfo_trivial_constr; ds |= dspec_trivial; } pars [0] = NULL_type; ex = constr_except (ct, DEFAULT_CONSTR); IGNORE declare_func (ds, id, NULL_type, pars, FUNC_NONE, ex); noncopy_constr = 1; access_constr = 1; } /* Implicit declaration of copy constructor */ if (need_copy_constr) { CV_SPEC cv = cv_lvalue; DECL_SPEC ds = (dspec_constr | cds); if (cj & cinfo_trivial_copy) { ci |= cinfo_trivial_copy; ds |= dspec_trivial; } if (cj & cinfo_const_copy) { ci |= cinfo_const_copy; cv |= cv_const; } MAKE_type_compound (cv, ct, t); COPY_id (type_name (t), cid); MAKE_type_ref (cv_none, t, t); pars [0] = t; pars [1] = NULL_type; ex = constr_except (ct, DEFAULT_COPY); IGNORE declare_func (ds, id, NULL_type, pars, FUNC_NONE, ex); } /* Check assignment operators (ignore inheritance) */ nm = lookup_op (lex_assign); id = search_id (ns, nm, 0, 0); if (!IS_NULL_id (id)) { if (IS_id_mem_func (id)) { IDENTIFIER fid = id; while (!IS_NULL_id (fid)) { TYPE fn = DEREF_type (id_mem_func_type (fid)); int c = check_copy_constr (fn, ct); if (c) { if (c == 2 || c == 3) ci |= cinfo_const_assign; need_assignment_op = 0; three_rule++; } fid = DEREF_id (id_mem_func_over (fid)); } } else { /* Delete non-function meanings */ clear_member (ns, nm); } } else { /* Create a dummy identifier */ id = DEREF_id (hashid_id (nm)); } /* Implicit declaration of copy assignment operator */ if (need_assignment_op) { CV_SPEC cv = cv_lvalue; DECL_SPEC ds = (dspec_constr | cds); if (cj & cinfo_trivial_assign) { ci |= cinfo_trivial_assign; ds |= dspec_trivial; } if (cj & cinfo_const_assign) { ci |= cinfo_const_assign; cv |= cv_const; } MAKE_type_compound (cv, ct, t); COPY_id (type_name (t), cid); MAKE_type_ref (cv_none, t, t); pars [0] = t; pars [1] = NULL_type; MAKE_type_compound (cv_lvalue, ct, t); COPY_id (type_name (t), cid); MAKE_type_ref (cv_none, t, t); ex = constr_except (ct, DEFAULT_ASSIGN); IGNORE declare_func (ds, id, t, pars, FUNC_NONE, ex); } /* Check destructors */ id = DEREF_id (ctype_destr (ct)); if (IS_id_mem_func (id)) { DECL_SPEC acc = DEREF_dspec (id_storage (id)); if ((acc & dspec_access) != dspec_private) { access_destr = 1; } need_destructor = 0; three_rule++; } else { /* Delete non-function meanings */ nm = DEREF_hashid (id_name (id)); clear_member (ns, nm); } /* Implicit declaration of default destructor */ if (need_destructor) { /* Check for trivial destructors */ DECL_SPEC ds = (dspec_constr | cds); if (cj & cinfo_trivial_destr) { ci |= cinfo_trivial_destr; ds |= dspec_trivial; } pars [0] = NULL_type; ex = constr_except (ct, DEFAULT_DESTR); IGNORE declare_func (ds, id, NULL_type, pars, FUNC_NONE, ex); access_destr = 1; } /* Report inaccessible constructors or destructors */ if (three_rule != 0 && three_rule != 3) { report (crt_loc, ERR_class_dtor_three (ct)); } if (!noncopy_constr) { report (crt_loc, ERR_class_ctor_make (ct)); access_constr = 1; } if (IS_NULL_list (pals)) { if (!access_constr) { report (crt_loc, ERR_class_ctor_private (ct)); } if (!access_destr) { report (crt_loc, ERR_class_dtor_private (ct)); } } return (ci); } /* * FIND A CONSTRUCTOR KIND * * This routine finds the kind of constructor for the function id of * type t. */ int constr_kind(IDENTIFIER id, TYPE t) { int n = DEFAULT_USR; HASHID nm = DEREF_hashid (id_name (id)); switch (TAG_hashid (nm)) { case hashid_constr_tag : { if (min_no_args (t) == 1) { n = DEFAULT_CONSTR; } else { n = DEFAULT_COPY; } break; } case hashid_destr_tag : { /* Implicit default destructor */ n = DEFAULT_DESTR; break; } case hashid_op_tag : { /* Implicit assignment operator */ n = DEFAULT_ASSIGN; break; } } return (n); } /* * DEFINE AN IMPLICIT CONSTRUCTOR OR DESTRUCTOR * * This routine defines the function id, which will be one of the * implicitly declared constructors or destructors declared in * implicit_decl. n gives the constructor type or DEFAULT_USR if this * is not known. */ void implicit_defn(IDENTIFIER id, int n) { TYPE t; EXP e, r; DECL_SPEC ds; IDENTIFIER fn; NAMESPACE cns; int in_func, in_decl; /* Check for previous definition */ if (!IS_id_mem_func (id)) return; ds = DEREF_dspec (id_storage (id)); if (ds & dspec_inherit) { /* Inherited functions */ id = DEREF_id (id_alias (id)); ds = DEREF_dspec (id_storage (id)); } if (!(ds & dspec_implicit)) return; if (ds & dspec_defn) return; ds |= dspec_defn; COPY_dspec (id_storage (id), ds); /* Find constructor type */ t = DEREF_type (id_mem_func_type (id)); if (!IS_type_func (t)) return; if (n == DEFAULT_USR) n = constr_kind (id, t); /* Force immediate access checks */ in_func = in_function_defn; in_decl = in_declaration; fn = crt_func_id; in_function_defn = 1; in_declaration = 0; crt_func_id = id; /* Make initialiser list */ start_try_check (univ_type_set); cns = DEREF_nspace (type_func_pars (t)); push_namespace (cns); r = make_this_decl (id); cns = DEREF_nspace (id_parent (id)); e = make_constr (cns, id, n, n); if (n == DEFAULT_DESTR) { /* Allow for destructor prelude */ if (!(ds & dspec_trivial)) { EXP d = make_destr_prelude (cns); e = join_exp (d, e); } } else if (n == DEFAULT_ASSIGN) { /* Allow for return value */ r = make_indir_exp (r); MAKE_exp_return_stmt (type_bottom, r, r); e = join_exp (e, r); } IGNORE pop_namespace (); e = end_try_check (id, e); COPY_exp (id_mem_func_defn (id), e); define_id (id); /* Compile the function definition */ if (!(ds & dspec_trivial)) { if (do_dump) { dump_implicit = 1; dump_declare (id, &crt_loc, 1); } compile_function (id, 0); } /* Restore old values */ in_function_defn = in_func; in_declaration = in_decl; crt_func_id = fn; return; } /* * EXPLICIT CONSTRUCTOR FLAGS * * These flags are used to indicate that an explicit constructor or * conversion function has been declared. */ int have_conv_expl = 0; int have_constr_expl = 0; /* * REMOVE EXPLICIT CONSTRUCTORS * * This routine removes all explicit constructors from the candidate list * p beginning with the mth element. */ static void remove_explicit(CANDIDATE_LIST *p, unsigned m) { unsigned i, n = p->size; CANDIDATE *q = p->elem + m; for (i = m ; i < n ; i++) { DECL_SPEC ds = DEREF_dspec (id_storage (q->base)); if (ds & dspec_explicit) q->rank = RANK_IGNORE; q++; } return; } /* * CONSTRUCT CONSTRUCTOR CANDIDATES LIST * * This routine constructs the candidate list consisting of the constructors * for the class type t (including the explicit constructors only if cast * indicates an explicit conversion). The candidates are added to the * list p. The routine returns the first constructor for t. */ static IDENTIFIER constr_candidates(CANDIDATE_LIST *p, TYPE t, unsigned cast) { /* Search for constructor candidates */ IDENTIFIER cid; CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); complete_class (ct, 1); cid = DEREF_id (ctype_constr (ct)); if (IS_id_mem_func (cid)) { unsigned i = p->size; add_candidates (p, cid, 1, KIND_CONSTR); swap_candidates (p, i); if (cast == CAST_IMPLICIT && have_constr_expl) { remove_explicit (p, i); } } else { /* Can happen for incomplete types and in C */ cid = NULL_id; } return (cid); } /* * CONSTRUCT CONVERSION CANDIDATES LIST * * This routine constructs the candidate list for the conversion functions * for the type s which can be implicitly converted to type t, plus the * constructors of t if t is a class type. The candidates are added to * the end of p. The routine returns the first constructor for t if t is * a class type, and the null identifier otherwise. */ IDENTIFIER conv_candidates(CANDIDATE_LIST *p, TYPE t, TYPE s, unsigned cast) { /* Add constructors */ IDENTIFIER cid = NULL_id; if (IS_type_compound (t)) { cid = constr_candidates (p, t, cast); } /* Add conversion functions */ if (IS_type_compound (s)) { LIST (IDENTIFIER) conv; CLASS_TYPE cs = DEREF_ctype (type_compound_defn (s)); complete_class (cs, 1); conv = DEREF_list (ctype_conv (cs)); while (!IS_NULL_list (conv)) { IDENTIFIER id = DEREF_id (HEAD_list (conv)); TYPE fn = DEREF_type (id_function_etc_type (id)); if (IS_type_templ (fn)) { /* Allow for template functions */ fn = deduce_conv (fn, t); if (!IS_NULL_type (fn)) { int eq = 0; id = deduce_func (id, fn, &eq); } else { id = NULL_id; } } if (!IS_NULL_id (id)) { unsigned r; CONVERSION c; HASHID nm = DEREF_hashid (id_name (id)); c.from = DEREF_type (hashid_conv_type (nm)); c.to = t; r = std_convert_seq (&c, NULL_exp, 0, 0); if (r != CONV_NONE) { unsigned i = p->size; add_candidates (p, id, 1, KIND_CONV); if (cast == CAST_IMPLICIT && have_conv_expl) { remove_explicit (p, i); } } } conv = TAIL_list (conv); } } return (cid); } /* * CONSTRUCT GENERIC CONVERSION CANDIDATES LIST * * This routine adds all the conversion functions from the type t to * types matching the type category mask kind to the candidate list p. * Note that template conversion functions are excluded - they cannot * give a non-ambiguous resolution and are beaten by any non-template * conversion function. */ static void gen_candidates(CANDIDATE_LIST *p, TYPE t, unsigned kind) { if (IS_type_compound (t)) { LIST (IDENTIFIER) conv; CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); complete_class (ct, 1); conv = DEREF_list (ctype_conv (ct)); while (!IS_NULL_list (conv)) { IDENTIFIER id = DEREF_id (HEAD_list (conv)); TYPE fn = DEREF_type (id_function_etc_type (id)); if (IS_type_func (fn)) { TYPE r = DEREF_type (type_func_ret (fn)); unsigned c = type_category (&r); if (c & kind) { unsigned i = p->size; add_candidates (p, id, 1, KIND_CONV); if (have_conv_expl) remove_explicit (p, i); } } conv = TAIL_list (conv); } } return; } /* * APPLY A TRIVIAL DESTRUCTOR * * This routine applies a trivial destructor to the expression a. It * is used in explicit destructor and pseudo-destructor calls. */ EXP trivial_destr(EXP a) { EXP e = make_discard_exp (a); MAKE_exp_cast (type_void, CONV_ELLIPSIS, e, e); return (e); } /* * APPLY A TRIVIAL FUNCTION * * This routine applies the trivial constructor or destructor id to * the arguments args. The null expression is returned for invalid * arguments. */ EXP apply_trivial_func(IDENTIFIER id, LIST (EXP) args) { EXP e = NULL_exp; TYPE t = DEREF_type (id_function_etc_type (id)); int n = constr_kind (id, t); switch (n) { case DEFAULT_CONSTR : { if (LENGTH_list (args) == 1) { /* Trivial constructor */ CLASS_TYPE ct = parent_class (id); t = make_class_type (ct); e = make_null_exp (t); } break; } case DEFAULT_COPY : { if (LENGTH_list (args) == 2) { /* Trivial copy constructor */ ERROR err = NULL_err; LIST (TYPE) p = DEREF_list (type_func_mtypes (t)); TYPE ta = DEREF_type (HEAD_list (p)); ta = DEREF_type (type_ref_sub (ta)); e = DEREF_exp (HEAD_list (TAIL_list (args))); e = convert_reference (e, REF_NORMAL); e = convert_class (ta, e, &err); if (!IS_NULL_err (err)) { err = concat_warning (err, ERR_expr_ass_conv ()); report (crt_loc, err); } } break; } case DEFAULT_DESTR : { if (LENGTH_list (args) == 1) { /* Trivial destructor */ EXP a = DEREF_exp (HEAD_list (args)); e = trivial_destr (a); } break; } case DEFAULT_ASSIGN : { if (LENGTH_list (args) == 2) { /* Trivial assignment */ EXP a = DEREF_exp (HEAD_list (args)); EXP b = DEREF_exp (HEAD_list (TAIL_list (args))); e = make_assign_exp (a, b, 1); } break; } } return (e); } /* * APPLY A CONSTRUCTOR * * This routine applies the constructor id to the arguments args, using a * dummy expression for the object the constructor is applied to. The * definition of this object, whether an existing object or a temporary, * is filled in later. */ EXP apply_constr(IDENTIFIER id, LIST (EXP) args) { TYPE t; EXP e, a; DECL_SPEC ds; CLASS_TYPE ct; IDENTIFIER cid; CONS_exp (NULL_exp, args, args); /* Check for trivial constructors */ ds = DEREF_dspec (id_storage (id)); if (ds & dspec_trivial) { e = apply_trivial_func (id, args); if (!IS_NULL_exp (e)) { DESTROY_list (args, SIZE_exp); return (e); } } /* Create dummy argument */ ct = parent_class (id); cid = DEREF_id (ctype_name (ct)); MAKE_type_compound (cv_lvalue, ct, t); COPY_id (type_name (t), cid); MAKE_exp_dummy (t, NULL_exp, LINK_NONE, NULL_off, 0, a); COPY_exp (HEAD_list (args), a); /* Apply the constructor */ e = apply_func_id (id, qual_none, NULL_graph, args); if (IS_exp_func_id (e)) { int n = DEFAULT_USR; TYPE fn = DEREF_type (id_function_etc_type (id)); if (check_copy_constr (fn, ct)) { /* Mark copy constructor calls */ n = DEFAULT_COPY; } e = add_constr_args (e, ct, EXTRA_CONSTR); t = make_class_type (ct); MAKE_exp_constr (t, e, a, a, n, e); } return (e); } /* * INITIALISATION BY CONSTRUCTOR * * This routine converts the argument list args to the class type t by * constructor. The cast parameter indicates if this is an explicit * conversion. The routine is used, for example, in initialisations of * the form 't id (args)'. */ EXP convert_constr(TYPE t, LIST (EXP) args, ERROR *err, unsigned cast) { EXP e; IDENTIFIER cid; CANDIDATE_LIST *p; /* Check for template parameters */ if (dependent_conv (t, args)) { MAKE_exp_opn (t, lex_static_Hcast, args, e); return (e); } /* Construct list of candidates */ p = &candidates; p->size = 0; cid = constr_candidates (p, t, cast); /* Perform overload resolution */ if (p->size) { CANDIDATE *q = resolve_overload (p, args, NULL_type, 0); IDENTIFIER qid = q->func; unsigned rank = q->rank; int kind = q->kind; if (rank == RANK_BEST) { /* Unambiguous resolution */ if (!IS_NULL_id (cid)) { swap_candidates (p, (unsigned) 0); } if (match_no_viable > 1 && overload_warn) { add_error (err, ERR_over_match_ctor_ok (qid)); } } else if (rank == RANK_VIABLE) { /* Ambiguous resolution */ q = resolve_ambiguous (p, args, NULL_type, 0); qid = q->func; rank = q->rank; if (!IS_NULL_id (cid)) { swap_candidates (p, (unsigned) 0); } if (rank == RANK_TARGET) { ERROR err2 = ERR_over_match_ctor_target (qid); qid = make_ambig_func (p, qid, args, qual_none, &err2); kind = KIND_FUNC; add_error (err, err2); } else if (rank == RANK_VIABLE) { ERROR err2 = ERR_over_match_ctor_ambig (qid); err2 = list_candidates (err2, p, RANK_VIABLE); add_error (err, err2); } } else { /* No resolution */ if (!IS_NULL_id (cid)) { swap_candidates (p, (unsigned) 0); } goto error_lab; } use_func_id (qid, 0, suppress_usage); if (kind == KIND_CONSTR) { e = apply_constr (qid, args); } else { /* Can only happen for target dependent resolutions */ e = apply_func_id (qid, qual_none, NULL_graph, args); if (IS_exp_constr (e)) { /* Introduce temporary variable if necessary */ TYPE s = DEREF_type (exp_type (e)); e = make_temporary (s, e, NULL_exp, 0, err); e = convert_lvalue (e); } } return (e); } /* Deal with incomplete structures */ if (IS_NULL_id (cid)) { ERROR err2 = check_incomplete (t); if (!IS_NULL_err (err2)) { add_error (err, err2); add_error (err, ERR_expr_type_conv_incompl ()); e = make_null_exp (t); return (e); } #if LANGUAGE_C if (IS_NULL_list (args)) { /* C default initialisation */ e = make_null_exp (t); return (e); } if (IS_NULL_list (TAIL_list (args))) { /* C copy initialisation */ EXP a = DEREF_exp (HEAD_list (args)); a = convert_none (a); a = convert_class (t, a, err); a = remove_temporary (a, NULL_exp); return (a); } #endif } /* No candidates */ error_lab : { CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); cid = DEREF_id (ctype_constr (ct)); add_error (err, ERR_over_match_ctor_none (cid)); e = make_null_exp (t); } return (e); } /* * CHECK FOR INITIALISATION BY USER-DEFINED CONVERSION * * This routine checks for user-defined conversions of a to type t. * It is identical to convert_conv except that it returns the null * expression is there are no viable conversion functions. */ EXP convert_conv_aux(TYPE t, EXP a, ERROR *err, unsigned cast) { IDENTIFIER cid; CANDIDATE_LIST *p; LIST (EXP) args; TYPE s = DEREF_type (exp_type (a)); if (IS_type_error (s)) { EXP e = make_error_exp (0); return (e); } /* Check for template parameters */ CONS_exp (a, NULL_list (EXP), args); if (dependent_conv (t, args)) { EXP e = cast_templ_type (t, a, cast); DESTROY_list (args, SIZE_exp); return (e); } /* Construct list of candidates */ p = &candidates; p->size = 0; cid = conv_candidates (p, t, s, cast); /* Perform overload resolution */ if (p->size) { EXP e; int kind; DECL_SPEC ds; CANDIDATE *q; unsigned rank; IDENTIFIER qid; match_this++; q = resolve_overload (p, args, t, 0); match_this--; qid = q->func; rank = q->rank; kind = q->kind; if (rank == RANK_BEST) { /* Unambiguous resolution */ if (!IS_NULL_id (cid)) { swap_candidates (p, (unsigned) 0); } if (match_no_viable > 1 && overload_warn) { add_error (err, ERR_over_match_conv_ok (qid)); } } else if (rank == RANK_VIABLE) { /* Ambiguous resolution */ q = resolve_ambiguous (p, args, t, 0); qid = q->func; rank = q->rank; if (!IS_NULL_id (cid)) { swap_candidates (p, (unsigned) 0); } if (rank == RANK_TARGET) { ERROR err2 = ERR_over_match_conv_target (s, t); qid = make_ambig_func (p, qid, args, qual_none, &err2); kind = KIND_FUNC; add_error (err, err2); } else if (rank == RANK_VIABLE) { ERROR err2 = ERR_over_match_conv_ambig (s, t); err2 = list_candidates (err2, p, RANK_VIABLE); add_error (err, err2); } } else { /* No resolution */ if (!IS_NULL_id (cid)) { swap_candidates (p, (unsigned) 0); } DESTROY_list (args, SIZE_exp); return (NULL_exp); } /* Check conversion function */ ds = DEREF_dspec (id_storage (qid)); if (ds & dspec_trivial) { /* Trivial copy constructor */ if (!(ds & dspec_defn)) { implicit_defn (qid, DEFAULT_COPY); } CONS_exp (NULL_exp, args, args); a = apply_trivial_func (qid, args); DESTROY_list (args, SIZE_exp); return (a); } /* Apply conversion function */ use_func_id (qid, 0, suppress_usage); if (kind == KIND_CONSTR) { if (eq_type_unqual (t, s)) { /* Force initialisation in copy constructor */ int depth = init_ref_force; if (depth > 2 && IS_type_compound (t)) { TYPE fn = DEREF_type (id_function_etc_type (qid)); CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); int c = check_copy_constr (fn, ct); if (c == 3) { /* Bad copy constructor */ HASHID nm = DEREF_hashid (id_name (qid)); add_error (err, ERR_class_copy_bad (nm)); DESTROY_list (args, SIZE_exp); return (a); } } init_ref_force = depth + 1; e = apply_constr (qid, args); init_ref_force = depth; } else { e = apply_constr (qid, args); } } else { e = apply_func_id (qid, qual_none, NULL_graph, args); if (IS_exp_constr (e)) { /* Introduce temporary variable if necessary */ s = DEREF_type (exp_type (e)); e = make_temporary (s, e, NULL_exp, 0, err); } } return (e); } /* No candidates */ DESTROY_list (args, SIZE_exp); return (NULL_exp); } /* * INITIALISATION BY USER-DEFINED CONVERSION * * This routine converts the expression a to the type t by user-defined * conversions. It is used, for example, in initialisations of the form * 't id = a'. */ EXP convert_conv(TYPE t, EXP a, ERROR *err, unsigned cast) { EXP e = convert_conv_aux (t, a, err, cast); if (IS_NULL_exp (e)) { /* No viable conversion functions */ TYPE s; a = convert_lvalue (a); s = DEREF_type (exp_type (a)); if (!IS_type_error (s) && !IS_type_error (t)) { add_error (err, check_incomplete (t)); if (check_int_type (t, btype_bool)) { e = convert_boolean (a, exp_paren_tag, err); return (e); } add_error (err, ERR_expr_cast_invalid (s, t)); } e = make_null_exp (t); } else { /* Deal with further implicit conversions */ TYPE s = DEREF_type (exp_type (e)); if (IS_type_ref (s)) { /* Reference conversion */ s = DEREF_type (type_ref_sub (s)); MAKE_exp_indir (s, e, e); } if (!IS_type_ref (t)) { CV_SPEC cv = DEREF_cv (type_qual (s)); if (cv & cv_lvalue) { /* lvalue conversion */ s = rvalue_type (s); MAKE_exp_contents (s, e, e); } } if (!eq_type (t, s)) { cast = (CAST_STANDARD | CAST_IMPLICIT); e = cast_exp (t, e, err, cast); } } return (e); } /* * GENERIC INITIALISATION BY USER-DEFINED CONVERSION * * This routine selects a user-defined conversion from the expression a * to a type with category matching kind. It returns the null expression * if no such conversion exists. */ EXP convert_gen(unsigned kind, EXP a, ERROR *err) { EXP e = NULL_exp; TYPE t = DEREF_type (exp_type (a)); /* Construct list of candidates */ CANDIDATE_LIST *p = &candidates; p->size = 0; gen_candidates (p, t, kind); /* Perform overload resolution */ if (p->size) { CANDIDATE *q; unsigned rank; IDENTIFIER qid; LIST (EXP) args; CONS_exp (a, NULL_list (EXP), args); match_this++; q = resolve_overload (p, args, NULL_type, 0); match_this--; qid = q->func; rank = q->rank; if (rank == RANK_BEST) { /* Unambiguous resolution */ if (match_no_viable > 1 && overload_warn) { add_error (err, ERR_over_match_conv_ok (qid)); } } else if (rank == RANK_VIABLE) { /* Ambiguous resolution */ q = resolve_ambiguous (p, args, NULL_type, 0); qid = q->func; rank = q->rank; if (rank != RANK_BEST) { /* Can't be target dependent */ ERROR err2 = ERR_over_match_conv_dup (t); err2 = list_candidates (err2, p, RANK_VIABLE); add_error (err, err2); } } else { /* No viable candidates */ return (e); } use_func_id (qid, 0, suppress_usage); e = apply_func_id (qid, qual_none, NULL_graph, args); e = convert_reference (e, REF_NORMAL); e = convert_lvalue (e); } /* No candidates */ return (e); }