/* * 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/function.c,v 1.11 2005/10/11 06:46:37 stefanf Exp $ */ #include "config.h" #include "producer.h" #include "msgcat.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 "tok_ops.h" #include "type_ops.h" #include "error.h" #include "catalog.h" #include "option.h" #include "access.h" #include "basetype.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 "declare.h" #include "derive.h" #include "destroy.h" #include "dump.h" #include "exception.h" #include "expression.h" #include "file.h" #include "function.h" #include "hash.h" #include "identifier.h" #include "initialise.h" #include "instance.h" #include "label.h" #include "member.h" #include "namespace.h" #include "operator.h" #include "option.h" #include "overload.h" #include "parse.h" #include "predict.h" #include "printf.h" #include "redeclare.h" #include "rewrite.h" #include "statement.h" #include "syntax.h" #include "template.h" #include "tokdef.h" #include "token.h" #include "ustring.h" #include "variable.h" /* * CHECK A FUNCTION RETURN TYPE * * This routine checks whether the type t is a suitable function return * type. This can be void (unqualified) or a complete type. def is * true for a function definition or call, but false otherwise. */ TYPE check_ret_type(TYPE t, ERROR *err, int def) { CV_SPEC cv = DEREF_cv (type_qual (t)); cv &= cv_qual; if (IS_type_top_etc (t)) { if (cv != cv_none && !def) { /* Can't return 'cv void' */ add_error (err, ERR_dcl_fct_ret_void (t)); if ((cv & cv_volatile) && IS_type_top (t)) { /* Map 'volatile void' to 'bottom' */ t = type_bottom; cv &= ~cv_volatile; t = qualify_type (t, cv, 0); } } } else { if (def) add_error (err, check_incomplete (t)); } if (cv != cv_none && !def) { /* Check for cv-qualified return types */ add_error (err, ERR_dcl_fct_cv_ret (cv)); } return (t); } /* * APPLY REFERENCE CONVERSIONS TO A LIST OF EXPRESSIONS * * This routine applies reference conversions to each element of the * argument list args. */ LIST (EXP) convert_args(LIST (EXP) args) { LIST (EXP) p = args; while (!IS_NULL_list (p)) { EXP e = DEREF_exp (HEAD_list (p)); if (!IS_NULL_exp (e)) { e = convert_reference (e, REF_ASSIGN); COPY_exp (HEAD_list (p), e); } p = TAIL_list (p); } return (args); } /* * FIND MINIMUM NUMBER OF ARGUMENTS FOR A FUNCTION * * This routine calculates the minimum number of arguments for the function * type fn, taking default arguments and weak prototypes into account. * The extra argument for member functions is included. */ unsigned min_no_args(TYPE fn) { unsigned n = 0; LIST (TYPE) ptypes; LIST (TYPE) mtypes; LIST (IDENTIFIER) p; while (IS_type_templ (fn)) { fn = DEREF_type (type_templ_defn (fn)); } p = DEREF_list (type_func_pids (fn)); ptypes = DEREF_list (type_func_ptypes (fn)); mtypes = DEREF_list (type_func_mtypes (fn)); if (!EQ_list (mtypes, ptypes)) { /* Add one for member functions */ if (!IS_NULL_list (mtypes)) { mtypes = TAIL_list (mtypes); if (EQ_list (mtypes, ptypes)) n = 1; } } while (!IS_NULL_list (p)) { /* Scan for default arguments */ IDENTIFIER id = DEREF_id (HEAD_list (p)); EXP e = DEREF_exp (id_parameter_init (id)); if (!IS_NULL_exp (e)) break; n++; p = TAIL_list (p); } return (n); } /* * CHECK FUNCTION DEFAULT ARGUMENTS * * This routine checks the default arguments for the function type fn, * returning true if there is a default argument. Missing default * arguments are checked if chk is true. */ int check_func_dargs(TYPE fn, int chk, int clr) { int started = 0; unsigned tag = TAG_type (fn); while (tag == type_templ_tag) { fn = DEREF_type (type_templ_defn (fn)); tag = TAG_type (fn); } if (tag == type_func_tag) { LIST (IDENTIFIER) pids = DEREF_list (type_func_pids (fn)); while (!IS_NULL_list (pids)) { IDENTIFIER pid = DEREF_id (HEAD_list (pids)); EXP a = DEREF_exp (id_parameter_init (pid)); if (IS_NULL_exp (a)) { if (started && !clr) { /* Missing default arguments */ TYPE s; LOCATION loc; DEREF_loc (id_loc (pid), loc); report (loc, ERR_dcl_fct_default_missing (pid)); s = DEREF_type (id_parameter_type (pid)); MAKE_exp_value (s, a); COPY_exp (id_parameter_init (pid), a); } } else { started = 1; if (clr) { /* Clear default argument */ COPY_exp (id_parameter_init (pid), NULL_exp); } else { if (!chk) break; } } pids = TAIL_list (pids); } } return (started); } /* * CHECK A WEAK PROTOTYPE ARGUMENT * * This routine checks the expression a passed as an argument to a weak * function parameter of type t. It returns the composite of t and the * type of a, adding any errors to err. */ static TYPE check_weak_arg(TYPE t, EXP a, ERROR *err) { ERROR err2 = NULL_err; TYPE s = DEREF_type (exp_type (a)); if (IS_exp_int_lit (a) && eq_type_offset (s, t)) { /* Allow for integer literals */ NAT n = DEREF_nat (exp_int_lit_nat (a)); if (check_nat_range (t, n) == NAT_FIT) return (t); } t = check_compatible (t, s, 2, &err2, 1); if (!IS_NULL_err (err2)) { err2 = set_severity (err2, OPT_whatever, 0); add_error (err, err2); } return (t); } /* * PERFORM WEAK PROTOTYPE ANALYSIS * * This routine performs weak prototype analysis for a call to the * function id with the arguments args. It is only called when the * number of arguments matches the function type. */ static void check_weak_args(IDENTIFIER id, LIST (EXP) args, unsigned n) { TYPE fn = DEREF_type (id_function_etc_type (id)); if (IS_type_func (fn)) { int changed = 0; int ell = DEREF_int (type_func_ellipsis (fn)); LIST (TYPE) p = DEREF_list (type_func_ptypes (fn)); LIST (TYPE) q = NULL_list (TYPE); LIST (IDENTIFIER) pids = NULL_list (IDENTIFIER); if (ell == FUNC_WEAK_ARGS) changed = 1; while (!IS_NULL_list (p)) { /* Check parameter types */ TYPE s = DEREF_type (HEAD_list (p)); if (!IS_NULL_list (args)) { ERROR err = NULL_err; EXP a = DEREF_exp (HEAD_list (args)); TYPE t = check_weak_arg (s, a, &err); if (!IS_NULL_err (err)) { /* Report incompatible argument types */ PTR (LOCATION) loc = id_loc (id); ERROR err2 = ERR_expr_call_weak_arg (n, loc); err = concat_error (ERR_expr_call_func (id), err); err = concat_error (err, err2); report (crt_loc, err); } if (!EQ_type (t, s)) { if (changed) changed = 1; s = t; } args = TAIL_list (args); n++; } if (changed) CONS_type (s, q, q); p = TAIL_list (p); } if (ell == FUNC_NO_PARAMS) { /* Previous declaration was 'id ()' */ LOCATION loc; int par = CONTEXT_PARAMETER; NAMESPACE ns = DEREF_nspace (type_func_pars (fn)); loc = decl_loc; decl_loc = crt_loc; push_namespace (ns); while (!IS_NULL_list (args)) { HASHID nm = lookup_anon (); EXP a = DEREF_exp (HEAD_list (args)); TYPE t = DEREF_type (exp_type (a)); IDENTIFIER pid = DEREF_id (hashid_id (nm)); pid = make_param_decl (dspec_none, t, pid, par); init_param (pid, NULL_exp); CONS_id (pid, pids, pids); CONS_type (t, q, q); args = TAIL_list (args); } IGNORE pop_namespace (); ell = FUNC_WEAK_ARGS; decl_loc = loc; changed = 2; } if (changed == 2) { q = REVERSE_list (q); fn = copy_typedef (id, fn, cv_none); COPY_list (type_func_ptypes (fn), q); COPY_list (type_func_mtypes (fn), q); if (!IS_NULL_list (pids)) { pids = REVERSE_list (pids); COPY_list (type_func_pids (fn), pids); } COPY_int (type_func_ellipsis (fn), ell); COPY_type (id_function_etc_type (id), fn); COPY_loc (id_loc (id), crt_loc); decl_func_type (id, fn, 0); } else { DESTROY_list (q, SIZE_type); } } return; } /* * CHECK PRINTF AND SCANF ARGUMENTS * * This routine performs weak prototype analysis for a call to the * printf-like or scanf-like function id with the arguments args. p gives * the parameter types deduced from the format string. */ static void check_printf_args(IDENTIFIER id, LIST (TYPE) p, LIST (EXP) args, unsigned n, int pf) { unsigned np = LENGTH_list (p) + (n - 1); unsigned na = LENGTH_list (args) + (n - 1); if (np != na) { /* Check number of parameters */ ERROR err = ERR_expr_call_args_exact (na, na, np); err = set_severity (err, OPT_weak, -1); if (!IS_NULL_id (id)) { err = concat_error (ERR_expr_call_func (id), err); } report (crt_loc, err); } while (!IS_NULL_list (p) && !IS_NULL_list (args)) { /* Check parameter types */ ERROR err = NULL_err; TYPE s = DEREF_type (HEAD_list (p)); EXP a = DEREF_exp (HEAD_list (args)); TYPE t = check_weak_arg (s, a, &err); if (!IS_NULL_err (err)) { /* Report incompatible argument types */ PTR (LOCATION) loc = NULL_ptr (LOCATION); if (!IS_NULL_id (id)) loc = id_loc (id); err = concat_error (err, ERR_expr_call_weak_arg (n, loc)); } else { /* Check that scanf arguments aren't const */ if (!(pf & 1) && IS_type_ptr (t)) { CV_SPEC cv; t = DEREF_type (type_ptr_sub (t)); cv = DEREF_cv (type_qual (t)); if (cv & cv_const) { err = ERR_conv_qual_cast (cv_const); err = set_severity (err, OPT_weak, -1); } } } if (!IS_NULL_err (err)) { if (!IS_NULL_id (id)) { err = concat_error (ERR_expr_call_func (id), err); } report (crt_loc, err); } args = TAIL_list (args); p = TAIL_list (p); n++; } return; } /* * APPLY ARGUMENT CONVERSIONS TO A LIST OF EXPRESSIONS * * This routine applies the argument conversions indicated by the function * type fn to the argument list args. gr gives information on how member * functions are inherited. The function return type is returned via pr. * The identifier id is used in error reporting only, it is the function * being called for named functions and the null identifier otherwise. */ static LIST (EXP) cast_args(IDENTIFIER id, TYPE fn, GRAPH gr, LIST (EXP) args, TYPE *pr, int mem) { int ell; TYPE ret; int extra = 0; unsigned n = 1; LIST (EXP) q; LIST (TYPE) p; LIST (TYPE) ptypes; LIST (TYPE) mtypes; ERROR err = NULL_err; int printf_function = 0; LIST (IDENTIFIER) pids; OPTION weak = OPTION_OFF; LIST (TYPE) ftypes = NULL_list (TYPE); /* Allow for template types */ if (IS_type_templ (fn)) { int d; TOKEN sort = DEREF_tok (type_templ_sort (fn)); pids = DEREF_list (tok_templ_pids (sort)); force_template++; d = save_token_args (pids, NULL_list (TOKEN)); fn = DEREF_type (type_templ_defn (fn)); args = cast_args (id, fn, gr, args, &ret, mem); *pr = expand_type (ret, 2); restore_token_args (pids, d); force_template--; return (args); } /* Check function return type */ ret = DEREF_type (type_func_ret (fn)); ret = check_ret_type (ret, &err, 1); if (!IS_NULL_err (err)) { err = concat_error (err, ERR_expr_call_ret ()); if (!IS_NULL_id (id)) { err = concat_error (ERR_expr_call_func (id), err); } report (crt_loc, err); } ret = convert_qual_type (ret); *pr = ret; /* Check number of arguments */ ell = DEREF_int (type_func_ellipsis (fn)); ptypes = DEREF_list (type_func_ptypes (fn)); mtypes = DEREF_list (type_func_mtypes (fn)); if (!EQ_list (mtypes, ptypes)) { if (mem) { /* Member function */ extra = 1; } else { fn = copy_typedef (NULL_id, fn, cv_none); mtypes = ptypes; COPY_list (type_func_mtypes (fn), mtypes); } } if (match_no_args == 0) { /* Weren't checked in overload resolution */ unsigned na = LENGTH_list (args); unsigned npars = LENGTH_list (mtypes); if (na != npars) { int more = 0; unsigned margs = min_no_args (fn); if (ell & FUNC_VAR_PARAMS) more = 1; if (na < margs || (na > npars && !more)) { /* Illegal number of arguments */ if (extra) { /* Report actual numbers of passed arguments */ na--; npars--; margs--; } if (more) { err = ERR_expr_call_args_min (na, na, margs); } else if (npars == margs) { err = ERR_expr_call_args_exact (na, na, npars); } else { err = ERR_expr_call_args_range (na, na, margs, npars); } if (ell & FUNC_NON_PROTO) { /* Allowed for non-prototype functions */ err = set_severity (err, OPT_weak, -1); } if (!IS_NULL_err (err)) { if (!IS_NULL_id (id)) { ERROR err2 = ERR_expr_call_func (id); err = concat_error (err2, err); } report (crt_loc, err); } } } } /* Check function argument types */ p = mtypes; q = args; pids = DEREF_list (type_func_pids (fn)); /* Extra implicit argument */ if (extra && !IS_NULL_list (p) && !IS_NULL_list (q)) { EXP b = DEREF_exp (HEAD_list (q)); TYPE t = DEREF_type (HEAD_list (p)); if (!IS_NULL_exp (b) && !IS_NULL_type (t)) { /* Non-static member function called with object */ TYPE u = t; int temp = 1; CLASS_TYPE cs, ct; TYPE s = DEREF_type (exp_type (b)); CV_SPEC qs = DEREF_cv (type_qual (s)); CV_SPEC qt = DEREF_cv (type_func_mqual (fn)); /* Check for temporary object */ while (IS_type_array (s)) { s = DEREF_type (type_array_sub (s)); temp = 0; } while (IS_type_ptr_etc (s)) { s = DEREF_type (type_ptr_etc_sub (s)); temp = 0; } if (temp) { TYPE ps; if (!(qs & cv_lvalue)) { ERROR ferr = NULL_err; b = make_temporary (s, b, NULL_exp, 0, &ferr); if (!IS_NULL_err (ferr)) report (crt_loc, ferr); } MAKE_type_ptr (cv_none, s, ps); MAKE_exp_address (ps, b, b); } /* Check types for base class conversion */ while (IS_type_ptr_etc (t)) { t = DEREF_type (type_ptr_etc_sub (t)); } cs = DEREF_ctype (type_compound_defn (s)); ct = DEREF_ctype (type_compound_defn (t)); if (!eq_ctype (cs, ct)) { GRAPH gs = find_base_class (cs, ct, 1); if (IS_NULL_graph (gs)) { err = ERR_expr_ref_func_type (cs); } else { OFFSET off; err = check_ambig_base (gs); if (!IS_NULL_graph (gr)) { CLASS_TYPE cr = DEREF_ctype (graph_head (gr)); if (!eq_ctype (cs, cr) && !eq_ctype (cr, ct)) { /* Inherited via intermediate base */ GRAPH g1 = find_base_class (cs, cr, 1); if (!IS_NULL_graph (g1)) { GRAPH g2 = find_base_class (cr, ct, 1); if (!IS_NULL_graph (g2)) { if (!IS_NULL_err (err)) { ERROR err2; destroy_error (err, 1); err = check_ambig_base (g1); err2 = check_ambig_base (g2); err = concat_error (err, err2); } gs = DEREF_graph (graph_top (g2)); gs = find_subgraph (g1, gs, g2); } } } } if (!IS_NULL_err (err)) { /* Report ambiguous bases */ ERROR err2 = ERR_class_member_lookup_func (); err = concat_error (err, err2); } off = DEREF_off (graph_off (gs)); b = make_base_cast (u, b, off); /* Access should have been checked */ } if (!IS_NULL_err (err)) { if (!IS_NULL_id (id)) { ERROR err2 = ERR_expr_call_func (id); err = concat_error (err2, err); } report (crt_loc, err); } } /* Check type qualifiers */ qs &= cv_qual; qt &= cv_qual; if (qs != qt) MAKE_exp_cast (u, CONV_QUAL, b, b); qs = (qs & ~qt); if (qs != cv_none) { if (IS_NULL_id (id)) { err = ERR_class_this_qual (qs); report (crt_loc, err); } else { HASHID nm = DEREF_hashid (id_name (id)); if (!IS_hashid_destr (nm)) { /* Allowed for destructors */ ERROR err2; err = ERR_class_this_qual (qs); err2 = ERR_expr_call_func (id); err = concat_error (err2, err); report (crt_loc, err); } } } COPY_exp (HEAD_list (q), b); } p = TAIL_list (p); q = TAIL_list (q); } /* Normal arguments */ if (ell & FUNC_NON_PROTO) { weak = option (OPT_weak); goto ellipsis_lab; } while (!IS_NULL_list (p) && !IS_NULL_list (q)) { EXP b = DEREF_exp (HEAD_list (q)); TYPE t = DEREF_type (HEAD_list (p)); OPTION opt = option (OPT_conv_int_int_impl); if (IS_NULL_exp (b)) b = make_error_exp (0); if (IS_exp_paren (b)) { /* Parentheses suppress conversion warnings */ b = DEREF_exp (exp_paren_arg (b)); option (OPT_conv_int_int_impl) = OPTION_ALLOW; } if (IS_exp_string_lit (b)) { if (option (OPT_printf_string)) { /* Check for printf and scanf strings */ int pf = is_printf_type (t); if (pf) { unsigned na = LENGTH_list (q) + 100; STRING fmt = DEREF_str (exp_string_lit_str (b)); ftypes = find_printf_args (fmt, na, pf); printf_function = pf; } } } err = NULL_err; b = init_assign (t, cv_none, b, &err); if (pass_complex_type (t)) { /* Create temporary variable */ b = remove_temporary (b, NULL_exp); b = make_temporary (t, b, NULL_exp, 0, &err); MAKE_type_ptr (cv_none, t, t); MAKE_exp_address (t, b, b); } if (!IS_NULL_err (err)) { err = init_error (err, 0); err = concat_error (err, ERR_expr_call_arg (n)); if (!IS_NULL_id (id)) { err = concat_error (ERR_expr_call_func (id), err); } report (crt_loc, err); } option (OPT_conv_int_int_impl) = opt; n++; COPY_exp (HEAD_list (q), b); pids = TAIL_list (pids); p = TAIL_list (p); q = TAIL_list (q); } /* Default arguments */ if (!IS_NULL_list (p)) { LIST (EXP) dargs = NULL_list (EXP); while (!IS_NULL_list (pids)) { IDENTIFIER pid = DEREF_id (HEAD_list (pids)); EXP e = DEREF_exp (id_parameter_init (pid)); if (!IS_NULL_exp (e)) { TYPE t = DEREF_type (exp_type (e)); if (pass_complex_type (t)) { /* Create temporary variable */ EXP d = DEREF_exp (id_parameter_term (pid)); if (!IS_NULL_exp (d)) { d = copy_exp (d, NULL_type, NULL_type); } err = NULL_err; e = remove_temporary (e, NULL_exp); MAKE_exp_copy (t, e, e); e = make_temporary (t, e, d, 0, &err); if (!IS_NULL_err (err)) { err = concat_error (err, ERR_expr_call_arg (n)); if (!IS_NULL_id (id)) { ERROR err2 = ERR_expr_call_func (id); err = concat_error (err2, err); } report (crt_loc, err); } MAKE_type_ptr (cv_none, t, t); MAKE_exp_address (t, e, e); } else { MAKE_exp_copy (t, e, e); } CONS_exp (e, dargs, dargs); n++; } pids = TAIL_list (pids); } if (!IS_NULL_list (dargs)) { dargs = REVERSE_list (dargs); args = APPEND_list (args, dargs); } } /* Ellipsis arguments */ ellipsis_lab : { unsigned wn = n; LIST (EXP) wq = q; while (!IS_NULL_list (q)) { TYPE t, s; EXP b = DEREF_exp (HEAD_list (q)); if (IS_NULL_exp (b)) b = make_error_exp (0); b = convert_lvalue (b); b = convert_none (b); t = DEREF_type (exp_type (b)); err = NULL_err; s = arg_promote_type (t, &err); if (!EQ_type (s, t)) { b = init_assign (s, cv_none, b, &err); } if (!IS_NULL_err (err)) { err = init_error (err, 0); err = concat_error (err, ERR_expr_call_ellipsis (n)); if (!IS_NULL_id (id)) { err = concat_error (ERR_expr_call_func (id), err); } report (crt_loc, err); } COPY_exp (HEAD_list (q), b); n++; q = TAIL_list (q); } if (weak && !IS_NULL_id (id)) { /* Perform weak prototype analysis */ check_weak_args (id, wq, wn); } if (printf_function) { /* Check printf arguments */ if (option (OPT_weak)) { check_printf_args (id, ftypes, wq, wn, printf_function); } DESTROY_list (ftypes, SIZE_type); } } IGNORE check_value (OPT_VAL_func_args, (unsigned long) (n - 1)); return (args); } /* * APPLY A NAMED FUNCTION TO A LIST OF EXPRESSIONS * * This routine applies the function id to the list of arguments args. * Any qualifiers used to express id are passed in as qual, since these * may suppress the virtual call mechanism. gr gives the base class * from which a member function is inherited. */ EXP apply_func_id(IDENTIFIER id, QUALIFIER qual, GRAPH gr, LIST (EXP) args) { EXP e; TYPE fn; TYPE ret; DECL_SPEC ds; int throws = 1; EXP virt = NULL_exp; IDENTIFIER fid = id; /* Check for non-functions */ if (!IS_id_function_etc (id)) { e = make_error_exp (0); return (e); } /* Check for inherited functions */ ds = DEREF_dspec (id_storage (id)); if (ds & dspec_inherit) { id = DEREF_id (id_alias (id)); ds = DEREF_dspec (id_storage (id)); } /* Check for trivial functions */ if (ds & dspec_trivial) { e = apply_trivial_func (id, args); if (!IS_NULL_exp (e)) { DESTROY_list (args, SIZE_exp); return (e); } } /* Convert the arguments */ fn = DEREF_type (id_function_etc_type (id)); args = cast_args (id, fn, gr, args, &ret, 1); /* Check for virtual function calls */ if (ds & dspec_virtual) { if (!(qual & qual_explicit)) { EXP a = DEREF_exp (HEAD_list (args)); int know = know_type (a); if (know == 0) { if (!IS_NULL_exp (a)) { TYPE ta = DEREF_type (exp_type (a)); MAKE_exp_dummy (ta, a, LINK_NONE, NULL_off, 1, virt); COPY_exp (HEAD_list (args), virt); } } else if (know == 2) { /* Non-obvious case */ report (crt_loc, ERR_class_virtual_not (id)); } } if (IS_NULL_exp (virt)) { /* Explicit call of virtual function */ if (ds & dspec_pure) { /* Call of pure virtual function */ HASHID nm = DEREF_hashid (id_name (id)); if (IS_hashid_destr (nm)) { /* Calling pure destructor is alright */ /* EMPTY */ } else { report (crt_loc, ERR_class_abstract_call (id)); } } if (!(ds & dspec_used)) { /* Mark explicit use */ reuse_id (id, suppress_usage); ds = DEREF_dspec (id_storage (id)); } } } if ((ds & dspec_friend) && IS_NULL_exp (virt)) { /* Call can't throw an exception */ throws = 0; } /* Check for token applications */ if (ds & dspec_token) { if ((qual & qual_mark) && !(ds & dspec_reserve)) { /* Parenthesised - use function proper */ /* EMPTY */ } else { TYPE form = DEREF_type (id_function_etc_form (id)); if (!IS_NULL_type (form) && IS_type_token (form)) { IDENTIFIER ext = DEREF_id (type_token_tok (form)); if (!IS_NULL_id (ext) && IS_id_token (ext)) { id = ext; } } } } /* A function call is a side effect */ no_side_effects++; /* Form the result */ MAKE_exp_func_id (ret, id, args, virt, e); if (pass_complex_type (ret)) { /* Allow for complex return types */ EXP a; MAKE_exp_dummy (ret, NULL_exp, LINK_NONE, NULL_off, 0, a); if (IS_id_stat_mem_func (id)) { /* Insert as second parameter for static member functions */ EXP b = DEREF_exp (HEAD_list (args)); COPY_exp (HEAD_list (args), a); CONS_exp (b, args, args); } else { /* Insert as first parameter for other functions */ CONS_exp (a, args, args); } COPY_list (exp_func_id_args (e), args); COPY_unsigned (exp_func_id_extra (e), 1); COPY_type (exp_type (e), type_void); MAKE_exp_constr (ret, e, a, a, DEFAULT_USR, e); } /* Check for exception violations */ if (throws) { IGNORE check_func_throw (fn, fid); } return (e); } /* * APPLY A FUNCTION TO A LIST OF EXPRESSIONS * * This routine applies the function expression a to the list of arguments * args. */ static EXP apply_func_exp(EXP a, LIST (EXP) args) { /* Find function type */ EXP e; TYPE ret; int mem = 0; TYPE fn = DEREF_type (exp_type (a)); CV_SPEC cv = DEREF_cv (type_qual (fn)); if (cv & cv_lvalue) { a = convert_lvalue (a); fn = DEREF_type (exp_type (a)); } switch (TAG_type (fn)) { case type_ptr_tag : { fn = DEREF_type (type_ptr_sub (fn)); break; } case type_ptr_mem_tag : { fn = DEREF_type (type_ptr_mem_sub (fn)); break; } } /* Convert the arguments */ match_no_args = 0; if (IS_exp_call (a)) mem = 1; args = cast_args (NULL_id, fn, NULL_graph, args, &ret, mem); if (mem) { /* Record pointer to function member argument */ EXP c = DEREF_exp (HEAD_list (args)); TYPE t = DEREF_type (exp_type (c)); MAKE_exp_dummy (t, c, LINK_NONE, NULL_off, 1, c); COPY_exp (exp_call_arg (a), c); COPY_exp (HEAD_list (args), c); } /* A function call is a side effect */ no_side_effects++; /* Form the result */ MAKE_exp_func (ret, a, args, e); if (pass_complex_type (ret)) { /* Allow for complex return types */ EXP b; MAKE_exp_dummy (ret, NULL_exp, LINK_NONE, NULL_off, 0, b); CONS_exp (b, args, args); COPY_list (exp_func_args (e), args); COPY_unsigned (exp_func_extra (e), 1); COPY_type (exp_type (e), type_void); MAKE_exp_constr (ret, e, b, b, DEFAULT_USR, e); } /* Check for exception violations */ IGNORE check_func_throw (fn, NULL_id); return (e); } /* * APPLY A TEMPLATE DEPENDENT FUNCTION * * This routine constructs the template dependent function call * 'a (args)', or '(a) (args)' if is_paren is true. */ static EXP call_func_templ(EXP a, LIST (EXP) args, int is_paren) { EXP e; TYPE ret = type_templ_param; if (is_paren) a = make_paren_exp (a); CONS_exp (a, args, args); MAKE_exp_opn (ret, lex_func_Hop, args, e); return (e); } /* * CONSTRUCT A FUNCTION CALL EXPRESSION * * This routine constructs the function call expression 'a (args)'. */ EXP make_func_exp(EXP a, LIST (EXP) args, int rescan) { EXP e; TYPE fn; unsigned tag; unsigned ftag; int is_ptr = 0; int is_ptr_mem = 0; int is_paren = IS_exp_paren (a); /* Do reference conversions */ a = convert_reference (a, REF_FUNCTION); args = convert_args (args); /* Map '&f' to 'f' */ tag = TAG_exp (a); if (tag == exp_address_tag) { /* Non-member function */ EXP b = DEREF_exp (exp_address_arg (a)); if (IS_exp_identifier_etc (b)) { a = b; tag = TAG_exp (a); is_paren = 1; } } else if (tag == exp_address_mem_tag) { /* Member function (which better eventually be static) */ EXP b = DEREF_exp (exp_address_mem_arg (a)); IDENTIFIER id = DEREF_id (exp_member_id (b)); if (IS_id_function_etc (id)) { while (!IS_NULL_id (id)) { if (IS_id_mem_func (id)) { report (crt_loc, ERR_over_match_call_mem (id)); break; } id = DEREF_id (id_function_etc_over (id)); } a = b; tag = TAG_exp (a); is_paren = 1; is_ptr_mem = 1; } } /* Check function type */ fn = DEREF_type (exp_type (a)); ftag = TAG_type (fn); #if LANGUAGE_CPP if (ftag == type_compound_tag) { /* Allow for overloading using 'operator ()' */ if (overload_depth == 0) { e = function_overload (a, args); return (e); } } #endif if (ftag == type_ptr_tag) { /* Allow for pointers to functions */ fn = DEREF_type (type_ptr_sub (fn)); ftag = TAG_type (fn); is_ptr = 1; } while (ftag == type_templ_tag) { fn = DEREF_type (type_templ_defn (fn)); ftag = TAG_type (fn); } if (ftag != type_func_tag) { if (ftag == type_token_tag && is_templ_type (fn)) { /* Allow for template types */ e = call_func_templ (a, args, is_paren); return (e); } if (ftag != type_error_tag) { /* Type should now be a function type */ ERROR err; if (IS_exp_member (a)) { IDENTIFIER id = DEREF_id (exp_member_id (a)); err = ERR_expr_prim_mem (id); } else { err = ERR_expr_call_op (fn); } if (ftag == type_ptr_mem_tag && in_ptr_mem_selector) { err = concat_error (err, ERR_expr_mptr_oper_paren ()); } report (crt_loc, err); } e = make_error_exp (0); return (e); } /* Deal with named functions */ if (!is_ptr) { switch (tag) { case exp_identifier_tag : case exp_member_tag : case exp_ambiguous_tag : case exp_undeclared_tag : { /* Normal functions, 'f' */ int dep = 1; DECL_SPEC ds; IDENTIFIER id; QUALIFIER qual; EXP extra = NULL_exp; NAMESPACE ns = NULL_nspace; int acc = crt_access_list.inherit; id = DEREF_id (exp_identifier_etc_id (a)); qual = DEREF_qual (exp_identifier_etc_qual (a)); if (rescan) id = rescan_func_id (id, qual); if (dependent_call (id, args)) { /* Call depends on template argument */ e = call_func_templ (a, args, is_paren); return (e); } ds = DEREF_dspec (id_storage (id)); if (ds & dspec_instance) dep = 0; if (qual & qual_explicit) dep = 0; if (is_paren) qual |= qual_mark; switch (TAG_id (id)) { case id_mem_func_tag : case id_stat_mem_func_tag : mem_func_label : { /* Add argument for member functions */ extra = make_this_ref (&ns); CONS_exp (extra, args, args); dep = 0; break; } case id_ambig_tag : { /* Check for ambiguous member functions */ CLASS_TYPE ct = parent_class (id); if (!IS_NULL_ctype (ct)) goto mem_func_label; break; } } id = resolve_call (id, args, qual, dep); switch (TAG_id (id)) { case id_function_tag : { /* Normal function call */ break; } case id_mem_func_tag : { /* Member function call */ if (is_ptr_mem) { fn = DEREF_type (id_mem_func_type (id)); COPY_type (exp_type (a), fn); a = make_ref_exp (a, 1); fn = DEREF_type (exp_type (a)); report (crt_loc, ERR_expr_call_op (fn)); } if (IS_NULL_exp (extra)) { /* No associated object */ report (crt_loc, ERR_expr_call_mem (id)); } else { /* Indicate inherited member function */ crt_access_list.inherit++; } break; } case id_stat_mem_func_tag : { /* Static member function call */ if (!IS_NULL_exp (extra)) { COPY_exp (HEAD_list (args), NULL_exp); } break; } default : { /* Non-function called */ if (in_template_decl) { e = call_func_templ (a, args, is_paren); } else { e = make_id_exp (id); if (eq_exp (e, a, 0)) { e = make_error_exp (0); } else { e = make_func_exp (e, args, 0); } } return (e); } } use_func_id (id, 1, suppress_usage); crt_access_list.inherit = acc; if (resolved_kind == KIND_CONSTR) { e = apply_constr (id, args); } else { e = apply_func_id (id, qual, NULL_graph, args); } return (e); } case exp_call_tag : { /* Member function selectors */ EXP b = DEREF_exp (exp_call_ptr (a)); EXP c = DEREF_exp (exp_call_arg (a)); tag = TAG_exp (b); if (tag == exp_identifier_tag || tag == exp_member_tag) { /* Named function selector, 'c->f' */ IDENTIFIER id; QUALIFIER qual; id = DEREF_id (exp_identifier_etc_id (b)); qual = DEREF_qual (exp_identifier_etc_qual (b)); if (rescan) id = rescan_func_id (id, qual_nested); if (dependent_call (id, args)) { e = call_func_templ (a, args, is_paren); } else { GRAPH gr = DEREF_graph (exp_call_base (a)); if (is_paren) qual |= qual_mark; CONS_exp (c, args, args); id = resolve_call (id, args, qual, 0); use_func_id (id, 1, suppress_usage); if (resolved_kind == KIND_CONSTR) { e = apply_constr (id, args); } else { HASHID nm = DEREF_hashid (id_name (id)); e = apply_func_id (id, qual, gr, args); if (!IS_hashid_name_etc (nm)) { /* Check for extra arguments */ int v = EXTRA_CONSTR; CLASS_TYPE ct = parent_class (id); if (IS_hashid_destr (nm)) { v = EXTRA_DESTR; } e = add_constr_args (e, ct, v); } } } return (e); } if (tag == exp_undeclared_tag) { /* Pseudo-destructor call, 'c->C::~C' */ IDENTIFIER id = DEREF_id (exp_undeclared_id (b)); HASHID nm = DEREF_hashid (id_name (id)); if (!IS_NULL_list (args)) { report (crt_loc, ERR_expr_pseudo_args (nm)); } e = trivial_destr (c); return (e); } /* Pointer to member function selector, 'a.*f' */ CONS_exp (c, args, args); break; } } } /* Form the result for function expressions */ e = apply_func_exp (a, args); return (e); } /* * SHOULD A FUNCTION RETURN VALUE BE IGNORED? * * This routine checks whether a function consisting of 'return e;' * should be inlined. */ static EXP check_inline_return (EXP e, TYPE ret) { if (IS_NULL_exp (e)) { /* No value returned */ MAKE_exp_value (ret, e); return (e); } if (is_const_exp (e, -1)) { /* Constant expression returned */ MAKE_exp_copy (ret, e, e); return (e); } return (NULL_exp); } /* * SHOULD A FUNCTION CALL BE INLINED? * * Function inlining is generally left to the installers which have a * far better idea of whether a function should be inlined than the * producer. This routine checks whether the function call 'id (args)' * should be inlined by the producer. This is generally done on the * basis of code size rather than efficiency. If so it returns the result * expression. Otherwise the null expression is returned. */ EXP check_inline(IDENTIFIER id, LIST (EXP) args, TYPE ret) { while (!IS_NULL_list (args)) { /* Check argument list */ EXP a = DEREF_exp (HEAD_list (args)); if (!IS_NULL_exp (a)) return (NULL_exp); args = TAIL_list (args); } if (IS_id_function_etc (id)) { /* Check function definition */ EXP e = DEREF_exp (id_function_etc_defn (id)); if (!IS_NULL_exp (e) && IS_exp_sequence (e)) { LIST (EXP) p = DEREF_list (exp_sequence_first (e)); p = TAIL_list (p); if (IS_NULL_list (p)) { /* Empty function definition */ e = check_inline_return (NULL_exp, ret); return (e); } e = DEREF_exp (HEAD_list (p)); p = TAIL_list (p); if (IS_NULL_list (p)) { if (!IS_NULL_exp (e) && IS_exp_location (e)) { /* Step over location marker */ e = DEREF_exp (exp_location_arg (e)); } if (!IS_NULL_exp (e) && IS_exp_return_stmt (e)) { /* Single return statement */ e = DEREF_exp (exp_return_stmt_value (e)); e = check_inline_return (e, ret); return (e); } } } } return (NULL_exp); } /* * CHECK FOR COMPLEX FUNCTION RETURN OR ARGUMENT TYPE * * This routine checks whether t is a complex function return or argument * type, that is to say a class type with a non-trivial constructor, * destructor, or assignment operator. The calling convention implemented * is that such values are returned by means of a reference which is * passed to the function as the first argument, and that such values * are passed as arguments as a reference to a copy. */ int pass_complex_type(TYPE t) { if (!IS_NULL_type (t) && IS_type_compound (t)) { CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); CLASS_INFO ci = DEREF_cinfo (ctype_info (ct)); CLASS_INFO cj = (ci & cinfo_trivial); if (cj != cinfo_trivial) return (1); } return (0); } /* * CHECK A FUNCTION RETURN OR PARAMETER TYPE * * This routine checks whether the type just constructed by the parser * contains type definitions and so is not suitable for use as a function * return or parameter type (as indicated by par). The necessary * information is stored in the global variable have_type_declaration. */ void func_type_defn(int par) { int td = have_type_declaration; if (td == TYPE_DECL_NORMAL || td == TYPE_DECL_ANON) { if (par) { report (crt_loc, ERR_dcl_fct_typedef_par ()); } else { report (crt_loc, ERR_dcl_fct_typedef_ret ()); } } return; } /* * CREATE A PARAMETER TYPE * * This routine creates the parameter type for a function or template * parameter (as indicated by loc) declared with type t. Thus functions * and, for function parameters, arrays are converted to pointers. */ TYPE make_param_type(TYPE t, int loc) { switch (TAG_type (t)) { case type_func_tag : { /* Function parameters are adjusted to pointers */ member_func_type (NULL_ctype, id_parameter_tag, t); check_weak_func (t, 0); MAKE_type_ptr (cv_none, t, t); break; } case type_array_tag : { /* Array parameters are adjusted to pointers */ if (loc == CONTEXT_PARAMETER || loc == CONTEXT_WEAK_PARAM) { t = DEREF_type (type_array_sub (t)); MAKE_type_ptr (cv_none, t, t); } break; } } return (t); } /* * CHECK A PARAMETER TYPE * * A parameter cannot include a type of the form pointer to unbound array * or reference to unbound array. This routine returns an error if the type * t includes a type of this form. Strictly the parameters of any function * components should also be checked, but these will have already been * handled by a previous check. */ ERROR check_param_type(IDENTIFIER id, TYPE t) { TYPE s = t; int state = 0; while (!IS_NULL_type (s)) { switch (TAG_type (s)) { case type_top_tag : case type_bottom_tag : { /* Void types */ if (state) return (NULL_err); return (ERR_dcl_fct_par_void (id, t)); } case type_ptr_tag : case type_ref_tag : { /* Pointer and reference types */ s = DEREF_type (type_ptr_etc_sub (s)); state = 1; break; } case type_array_tag : { /* Array types */ if (state) { NAT n = DEREF_nat (type_array_size (s)); if (IS_NULL_nat (n)) { return (ERR_dcl_fct_par_array (id, t)); } } s = DEREF_type (type_array_sub (s)); state = 0; break; } default : { /* Other types */ return (NULL_err); } } } return (NULL_err); } /* * ADJUST A FUNCTION LINKAGE * * This routine adjusts the function linkage specifier cv to include * the current linkage specifier. */ CV_SPEC func_linkage(CV_SPEC cv) { DECL_SPEC ln = crt_linkage; if (ln) { if (ln & dspec_c) cv |= cv_c; if (ln & dspec_cpp) cv |= cv_cpp; } return (cv); } /* * CREATE A LIST OF FUNCTION PARAMETER TYPES * * This routine constructs the function type with parameter declarations * given by the current namespace and const-volatile qualifiers cv. The * kind of function is given by ell, which is a combination of the * FUNC_* values defined in function.h. The function return type is * usually filled in later (by inject_pre_type) but may be specified * by r. Note that function and array parameters have already been * adjusted to pointers by make_param_decl. */ TYPE make_func_type(TYPE r, int ell, CV_SPEC cv, LIST (TYPE) ex) { int no_param = 0; TYPE t = NULL_type; LIST (IDENTIFIER) p1; IDENTIFIER id = NULL_id; LIST (TYPE) q = NULL_list (TYPE); LIST (IDENTIFIER) p = NULL_list (IDENTIFIER); /* Get parameter declarations */ NAMESPACE ns = crt_namespace; MEMBER mem = DEREF_member (nspace_last (ns)); /* Build up parameter type list (deleting cv-qualifiers) */ while (!IS_NULL_member (mem)) { id = DEREF_id (member_id (mem)); if (!IS_NULL_id (id) && IS_id_parameter (id)) { t = DEREF_type (id_parameter_type (id)); if ((ell & FUNC_WEAK) && !is_arg_promote (t)) { DECL_SPEC ds; t = arg_promote_type (t, KILL_err); ds = DEREF_dspec (id_storage (id)); ds |= dspec_virtual; COPY_dspec (id_storage (id), ds); } t = qualify_type (t, cv_none, 0); CONS_type (t, q, q); CONS_id (id, p, p); no_param++; } mem = DEREF_member (member_next (mem)); } /* Check for non-prototype functions */ if (IS_NULL_type (r)) { if (ell & FUNC_NON_PROTO) { report (crt_loc, ERR_dcl_fct_nonproto ()); if (ell == FUNC_WEAK && no_param == 0) { /* Can't have 't weak ()' */ report (crt_loc, ERR_dcl_fct_par_weak ()); } #if LANGUAGE_CPP ell &= FUNC_ELLIPSIS; #endif } else { report (crt_loc, ERR_dcl_fct_proto ()); } } /* Check for '(...)' */ if (no_param == 0 && (ell & FUNC_ELLIPSIS)) { report (crt_loc, ERR_dcl_fct_par_ellipsis ()); } /* Check for '(void)' */ if (no_param == 1 && !(ell & FUNC_ELLIPSIS)) { /* Precisely one parameter (in t and id) */ if (IS_type_top (t)) { HASHID nm = DEREF_hashid (id_name (id)); if (!IS_hashid_anon (nm)) { report (crt_loc, ERR_dcl_fct_par_empty ()); } DESTROY_list (q, SIZE_type); DESTROY_list (p, SIZE_id); q = NULL_list (TYPE); p = NULL_list (IDENTIFIER); } } /* Check for other void parameters */ p1 = p; while (!IS_NULL_list (p1)) { ERROR err; id = DEREF_id (HEAD_list (p1)); t = DEREF_type (id_parameter_type (id)); err = check_param_type (id, t); if (!IS_NULL_err (err)) { /* Void or other illegal parameter type */ report (crt_loc, err); } p1 = TAIL_list (p1); } /* Construct the function type */ MAKE_type_func (cv_none, r, q, ell, cv, q, ns, p, ex, t); return (t); } /* * ADJUST MEMBER FUNCTION TYPES * * Each function type has two lists of parameter types, ptypes, which * gives the actual declared parameters, and mtypes, which has an extra * reference to class parameter for non-static member functions, or an * extra null parameter for static member functions. This routine sets * the mtypes field of t from the ptypes field according to whether or not * ct is the null class and the tag of an associated declaration, itag. * Note that member function types always have C++ linkage. */ void member_func_type(CLASS_TYPE ct, unsigned itag, TYPE t) { unsigned tag = TAG_type (t); while (tag == type_templ_tag) { t = DEREF_type (type_templ_defn (t)); tag = TAG_type (t); } if (tag == type_func_tag) { CV_SPEC cv = DEREF_cv (type_func_mqual (t)); CV_SPEC qual = (cv & cv_qual); LIST (TYPE) ptypes = DEREF_list (type_func_ptypes (t)); LIST (TYPE) mtypes = DEREF_list (type_func_mtypes (t)); if (IS_NULL_ctype (ct)) { /* Non-member functions */ if (qual && itag != id_type_alias_tag) { /* Can't have cv-qualifiers */ report (crt_loc, ERR_dcl_fct_cv (qual)); cv &= ~cv_qual; COPY_cv (type_func_mqual (t), cv); } if (!EQ_list (ptypes, mtypes)) { /* Set mtypes equal to ptypes */ COPY_list (type_func_mtypes (t), ptypes); } } else { /* Member functions */ if (EQ_list (ptypes, mtypes)) { /* Add extra argument to mtypes */ TYPE r; if (itag == id_mem_func_tag) { IDENTIFIER cid = DEREF_id (ctype_name (ct)); cv = (qual | cv_cpp); qual |= cv_lvalue; MAKE_type_compound (qual, ct, r); COPY_id (type_name (r), cid); MAKE_type_ref (cv_none, r, r); } else { if (qual) { /* Can't have cv-qualifiers */ report (crt_loc, ERR_dcl_fct_cv (qual)); } r = NULL_type; cv = cv_cpp; } CONS_type (r, ptypes, mtypes); COPY_list (type_func_mtypes (t), mtypes); COPY_cv (type_func_mqual (t), cv); } else { /* Don't check existing extra argument */ /* EMPTY */ } } } return; } /* * CHECK A NON-PROTOTYPE FUNCTION TYPE * * A parameter list can only be used in a function definition. This * routine checks the function type t with def being true for a function * definition. */ void check_weak_func(TYPE t, int def) { int ell = DEREF_int (type_func_ellipsis (t)); if (ell == FUNC_PARAMS) { /* Have parameter list '(a1, a2, ..., an)' */ if (def) { LOCATION loc; LIST (TYPE) q = NULL_list (TYPE); LIST (IDENTIFIER) p = DEREF_list (type_func_pids (t)); NAMESPACE ns = DEREF_nspace (type_func_pars (t)); MEMBER mem = DEREF_member (nspace_last (ns)); loc = decl_loc; bad_crt_loc++; while (!IS_NULL_member (mem)) { IDENTIFIER id = DEREF_id (member_id (mem)); if (!IS_NULL_id (id)) { if (IS_id_weak_param (id)) { /* Implicitly declare parameter */ ERROR err; TYPE s = type_sint; int par = CONTEXT_WEAK_PARAM; DEREF_loc (id_loc (id), decl_loc); id = make_param_decl (dspec_none, s, id, par); init_param (id, NULL_exp); err = ERR_dcl_fct_par_impl (id); if (!IS_NULL_err (err)) { ERROR err2 = ERR_dcl_type_infer (s); err = concat_error (err, err2); report (decl_loc, err); } CONS_id (id, p, p); CONS_type (s, q, q); } else if (IS_id_parameter (id)) { /* Add parameter to list */ TYPE s = DEREF_type (id_parameter_type (id)); if (!is_arg_promote (s)) { DECL_SPEC ds; s = arg_promote_type (s, KILL_err); ds = DEREF_dspec (id_storage (id)); ds |= dspec_virtual; COPY_dspec (id_storage (id), ds); } s = qualify_type (s, cv_none, 0); CONS_id (id, p, p); CONS_type (s, q, q); } } mem = DEREF_member (member_next (mem)); } COPY_list (type_func_ptypes (t), q); COPY_list (type_func_mtypes (t), q); COPY_list (type_func_pids (t), p); bad_crt_loc--; decl_loc = loc; ell = FUNC_WEAK_PARAMS; } else { report (crt_loc, ERR_dcl_fct_weak ()); ell = FUNC_NO_PARAMS; } } else if (ell == FUNC_NO_PARAMS) { /* Have empty parameter list '()' */ if (def) ell = FUNC_WEAK_PARAMS; } COPY_int (type_func_ellipsis (t), ell); return; } /* * CHECK THE FUNCTION COMPONENTS OF AN OBJECT TYPE * * This routine checks the function components of an object with the * given identifier tag and type t. */ void object_type(TYPE t, unsigned tag) { int depth = 0; if (tag == id_type_alias_tag || tag == null_tag) { /* Force errors in these cases */ depth = 2; } while (!IS_NULL_type (t)) { ASSERT (ORDER_type == 18); switch (TAG_type (t)) { case type_func_tag : { /* Function types */ LIST (TYPE) ex; CV_SPEC cv = DEREF_cv (type_func_mqual (t)); /* Check function qualifiers */ CV_SPEC mq = (cv & cv_qual); CV_SPEC lq = (cv & cv_language); if (depth == 0) { if (tag == id_mem_func_tag) { /* Member functions have C++ linkage */ lq = cv_cpp; } else { if (mq) { /* Can't have cv-qualifiers */ report (crt_loc, ERR_dcl_fct_cv_decl (mq)); mq = cv_none; } if (tag == id_stat_mem_func_tag) { /* Member functions have C++ linkage */ lq = cv_cpp; } } } if (lq == cv_none) lq = cv_lang; COPY_cv (type_func_mqual (t), (mq | lq)); /* Check default arguments */ if (depth && check_func_dargs (t, 0, 0)) { report (crt_loc, ERR_dcl_fct_default_bad ()); } /* Check exception specifiers */ ex = DEREF_list (type_func_except (t)); if (!EQ_list (ex, empty_type_set)) { if (!EQ_list (ex, univ_type_set)) { ulong n = (ulong) LENGTH_list (ex); IGNORE check_value (OPT_VAL_exception_specs, n); } if (depth > 1) { report (crt_loc, ERR_except_spec_bad ()); } } /* Recheck parameter types */ if (depth > 1) { LIST (TYPE) p; p = DEREF_list (type_func_ptypes (t)); while (!IS_NULL_list (p)) { TYPE s = DEREF_type (HEAD_list (p)); s = find_func_type (s); if (!IS_NULL_type (s)) { ex = DEREF_list (type_func_except (s)); if (!EQ_list (ex, empty_type_set)) { report (crt_loc, ERR_except_spec_bad ()); } } p = TAIL_list (p); } } return; } case type_ptr_tag : { t = DEREF_type (type_ptr_sub (t)); depth++; break; } case type_ref_tag : { t = DEREF_type (type_ref_sub (t)); break; } case type_ptr_mem_tag : { t = DEREF_type (type_ptr_mem_sub (t)); depth++; break; } case type_array_tag : { t = DEREF_type (type_array_sub (t)); depth++; break; } case type_templ_tag : { t = DEREF_type (type_templ_defn (t)); break; } default : { /* Other types */ return; } } } return; } /* * DECLARE A FUNCTION TYPE * * This routine checks the function or function typedef id of type t, * including checking that if a default argument is given for a * particular parameter one is also given for all subsequent parameters. * The redeclaration case, where default arguments can be inherited * from the previous declaration is dealt with by redecl_func_type. */ void decl_func_type(IDENTIFIER id, TYPE t, int def) { NAMESPACE pns; int is_templ = 0; unsigned tag = TAG_id (id); /* Step over template components */ if (IS_type_templ (t)) { t = check_templ_params (t, id); is_templ = 1; } pns = DEREF_nspace (type_func_pars (t)); COPY_id (nspace_name (pns), id); /* Check default arguments */ IGNORE check_func_dargs (t, 1, 0); /* Check cv-qualifiers */ switch (tag) { case id_function_tag : case id_mem_func_tag : case id_stat_mem_func_tag : { /* Allow for member functions */ CLASS_TYPE ct = parent_class (id); member_func_type (ct, tag, t); /* Allow for overloading of template functions */ if (is_templ) { templ_func_decl (id); } else { IDENTIFIER over = DEREF_id (id_function_etc_over (id)); if (!IS_NULL_id (over)) { /* Overloads a template function */ DECL_SPEC ds = DEREF_dspec (id_storage (over)); if (ds & dspec_template) templ_func_decl (id); } } break; } default : { /* Allow for function typedefs */ member_func_type (NULL_ctype, tag, t); break; } } UNUSED (def); return; } /* * REDECLARE DEFAULT ARGUMENTS * * This routine checks and unifies the default arguments for the equal * function types s and t. It returns the number of default arguments * added by this unification. */ static unsigned redecl_func_dargs(TYPE s, TYPE t) { unsigned nargs = 0; if (IS_type_func (s) && IS_type_func (t)) { int started = 0; LIST (IDENTIFIER) ps = DEREF_list (type_func_pids (s)); LIST (IDENTIFIER) pt = DEREF_list (type_func_pids (t)); while (!IS_NULL_list (ps) && !IS_NULL_list (pt)) { ERROR err = NULL_err; IDENTIFIER as = DEREF_id (HEAD_list (ps)); IDENTIFIER at = DEREF_id (HEAD_list (pt)); EXP ds = DEREF_exp (id_parameter_init (as)); EXP dt = DEREF_exp (id_parameter_init (at)); if (IS_NULL_exp (ds)) { /* No existing default argument */ if (IS_NULL_exp (dt)) { if (started) { /* Missing default arguments */ TYPE r = DEREF_type (id_parameter_type (at)); err = ERR_dcl_fct_default_missing (at); MAKE_exp_value (r, dt); COPY_exp (id_parameter_init (at), dt); COPY_exp (id_parameter_init (as), dt); } } else { /* New default argument */ COPY_exp (id_parameter_init (as), dt); dt = DEREF_exp (id_parameter_term (at)); COPY_exp (id_parameter_term (as), dt); nargs++; started = 1; } } else { /* Existing default argument */ if (IS_NULL_exp (dt)) { /* Inherited default argument */ COPY_exp (id_parameter_init (at), ds); ds = DEREF_exp (id_parameter_term (as)); COPY_exp (id_parameter_term (at), ds); } else { /* Redefined default argument */ PTR (LOCATION) sloc = id_loc (as); if (eq_exp (ds, dt, 0)) { err = ERR_dcl_fct_default_dup (at, sloc); } else { /* NOT YET IMPLEMENTED: dt uncompiled */ err = ERR_dcl_fct_default_redef (at, sloc); } COPY_exp (id_parameter_init (as), dt); dt = DEREF_exp (id_parameter_term (at)); COPY_exp (id_parameter_term (as), dt); } started = 1; } if (!IS_NULL_err (err)) { /* Report any errors */ LOCATION loc; DEREF_loc (id_loc (at), loc); report (loc, err); } ps = TAIL_list (ps); pt = TAIL_list (pt); } } return (nargs); } /* * REDECLARE A FUNCTION TYPE * * This routine deals with the compatible redeclaration of the function * id of type s to have type t. It unifies the parameter types, checking * default arguments etc. It also checks any exception specifications * for the two declarations. The parameter names in the returned type * are those from t if def is true, and those from s otherwise. */ TYPE redecl_func_type(IDENTIFIER id, TYPE s, TYPE t, int def, int dargs) { TYPE fs = s; TYPE ft = t; CV_SPEC qs, qt; NAMESPACE ns, nt; unsigned tag = TAG_id (id); /* Check template components */ redecl_template (&fs, &ft, id); ns = DEREF_nspace (type_func_pars (fs)); nt = DEREF_nspace (type_func_pars (ft)); COPY_id (nspace_name (ns), id); COPY_id (nspace_name (nt), id); #if LANGUAGE_C /* Copy composite type information */ if (def) { TYPE ret = DEREF_type (type_func_ret (fs)); int ell = DEREF_int (type_func_ellipsis (fs)); LIST (TYPE) ptypes = DEREF_list (type_func_ptypes (fs)); COPY_list (type_func_ptypes (ft), ptypes); COPY_int (type_func_ellipsis (ft), ell); COPY_type (type_func_ret (ft), ret); } #endif /* Check default arguments */ if (dargs && redecl_func_dargs (fs, ft)) { if (IS_type_templ (t)) { report (decl_loc, ERR_dcl_fct_default_templ ()); } } /* Check exception specifications */ if (eq_except (s, t) != 2) { PTR (LOCATION) loc = id_loc (id); report (decl_loc, ERR_except_spec_wrong (id, loc)); } /* Check cv-qualifiers */ switch (tag) { case id_mem_func_tag : case id_stat_mem_func_tag : { /* Allow for member functions */ CLASS_TYPE ct = parent_class (id); member_func_type (ct, tag, ft); break; } default : { /* Allow for function typedefs */ member_func_type (NULL_ctype, tag, ft); break; } } /* Check function qualifiers */ qs = DEREF_cv (type_func_mqual (fs)); qt = DEREF_cv (type_func_mqual (ft)); if (qs != qt) { qs &= cv_language; qt &= cv_language; if (qs != qt) { /* Language specifiers don't match */ string ln = linkage_string (dspec_none, qs); report (decl_loc, ERR_dcl_link_func (ln)); } } /* Select type to continue with */ if (def) { LIST (IDENTIFIER) sids = DEREF_list (type_func_pids (fs)); LIST (IDENTIFIER) tids = DEREF_list (type_func_pids (ft)); if (!EQ_list (sids, tids)) { while (!IS_NULL_list (sids) && !IS_NULL_list (tids)) { /* Identify parameters */ IDENTIFIER sid = DEREF_id (HEAD_list (sids)); IDENTIFIER tid = DEREF_id (HEAD_list (tids)); tid = chase_alias (tid); sid = chase_alias (sid); COPY_id (id_alias (sid), tid); tids = TAIL_list (tids); sids = TAIL_list (sids); } } if (IS_type_templ (t)) { /* Reset primary function template */ reset_primary_templ (s, t); } s = t; } return (s); } /* * FIND THE FUNCTION COMPONENT OF A TYPE * * This routine returns the function component of a function, pointer to * function, or pointer to member function type. */ TYPE find_func_type(TYPE t) { if (!IS_NULL_type (t)) { unsigned tag = TAG_type (t); if (tag == type_ref_tag) { t = DEREF_type (type_ref_sub (t)); tag = TAG_type (t); } if (tag == type_ptr_tag) { t = DEREF_type (type_ptr_sub (t)); tag = TAG_type (t); } else if (tag == type_ptr_mem_tag) { t = DEREF_type (type_ptr_mem_sub (t)); tag = TAG_type (t); } if (tag == type_func_tag) return (t); } return (NULL_type); } /* * STACK OF DECLARATOR LOCATIONS * * The location decl_loc refers to the current declarator. This value * needs to be stored during parameter declarations and this stack is * used for this purpose. */ static STACK (LOCATION) decl_locs = NULL_stack (LOCATION); /* * BEGIN FUNCTION PARAMETER NAMESPACE * * This routine is called at the start of a list of function parameters to * initialise the parameter namespace. id gives the associated function * name (or the null identifier). */ void begin_param(IDENTIFIER id) { NAMESPACE ns = make_namespace (id, nspace_param_tag, 0); push_namespace (ns); PUSH_loc (decl_loc, decl_locs); return; } /* * END FUNCTION PARAMETER NAMESPACE * * This routine is called at the end of a list of function parameters. */ void end_param(void) { IGNORE pop_namespace (); POP_loc (decl_loc, decl_locs); return; } /* * ADJUST A FUNCTION PARAMETER NAMESPACE * * This routine adjusts the parameter namespace of the dfunction type * t used in a function definition. */ void adjust_param(TYPE t) { NAMESPACE ns; while (IS_type_templ (t)) { t = DEREF_type (type_templ_defn (t)); } ns = DEREF_nspace (type_func_pars (t)); MODIFY_nspace_block_etc (nspace_block_tag, ns); report (crt_loc, ERR_dcl_fct_typedef ()); return; } /* * READ A LIST OF NON-PROTOTYPE FUNCTION PARAMETERS * * This routine reads a list of function parameters, returning true for * a function definition. */ int function_params(TYPE t) { int def = 0; if (IS_type_func (t)) { int func = have_func_declarator; int ell = DEREF_int (type_func_ellipsis (t)); NAMESPACE ns = DEREF_nspace (type_func_pars (t)); in_weak_param++; push_namespace (ns); while (predict_dspec (0)) { if (!func) { adjust_param (t); func = 1; } if (ell != FUNC_NO_PARAMS && ell != FUNC_PARAMS) { /* Can't have parameters with prototype */ report (crt_loc, ERR_dcl_fct_par_proto ()); ell = FUNC_PARAMS; } parse_decl (NULL_type, dspec_none); def = 1; } if (predict_func_defn ()) { if (!func) adjust_param (t); def = 1; } check_weak_func (t, def); IGNORE pop_namespace (); in_weak_param--; } return (def); } /* * MAIN FUNCTION * * This variable is used to hold the main function. */ IDENTIFIER main_function = NULL_id; /* * CHECK THE TYPE OF THE MAIN FUNCTION * * This routine checks the type t of the main function nm. The return * type must always be 'int', but the parameter types are implementation * dependent. Basically, anything other than: * * int main (void); * int main (int, char **, [extra parameters]); * * is deemed to be unorthodox. */ TYPE check_main(TYPE t, HASHID nm) { int ok = 0; if (IS_type_func (t)) { TYPE r = DEREF_type (type_func_ret (t)); LIST (TYPE) p = DEREF_list (type_func_ptypes (t)); int ell = DEREF_int (type_func_ellipsis (t)); if (!eq_type_unqual (r, type_sint)) { /* Return type is wrong */ ERROR err = ERR_basic_start_main_ret (r, nm); report (crt_loc, err); } if (IS_NULL_list (p)) { /* Check for no parameter case */ if (!(ell & FUNC_ELLIPSIS)) ok = 2; } else { /* Check for two parameter case */ TYPE s = DEREF_type (HEAD_list (p)); if (eq_type_unqual (s, type_sint)) { p = TAIL_list (p); if (!IS_NULL_list (p)) { s = DEREF_type (HEAD_list (p)); if (IS_type_ptr (s)) { s = DEREF_type (type_ptr_sub (s)); if (IS_type_ptr (s)) { s = DEREF_type (type_ptr_sub (s)); if (eq_type_unqual (s, type_char)) { p = TAIL_list (p); if (IS_NULL_list (p)) { if (!(ell & FUNC_ELLIPSIS)) { ok = 2; } else { ok = 1; } } else { ok = 1; } } } } } } } } if (!ok) { /* Warn about unorthodox parameter types */ ERROR err = ERR_basic_start_main_proto (t, nm); report (crt_loc, err); } return (t); } /* * RECHECK THE MAIN FUNCTION * * This routine rechecks the main function id. In particular 'main' can't * be overloaded. */ void recheck_main(IDENTIFIER id) { TYPE fn = DEREF_type (id_function_etc_type (id)); IDENTIFIER over = DEREF_id (id_function_etc_over (id)); if (!IS_NULL_id (over) || IS_type_templ (fn)) { /* Can't overload 'main' */ report (decl_loc, ERR_basic_start_main_over (id)); } main_function = id; return; } /* * CURRENT FUNCTION INFORMATION * * These variables are used to hold information concerning the current * function, including its name, return type and exception specification. */ IDENTIFIER crt_func_id = NULL_id; TYPE crt_func_return = NULL_type; int crt_func_complex = 0; /* * NESTED FUNCTION STACK * * Note that it is indirectly possible to have nested function definitions * (a function definition can include a class definition which can include * a member function definition). These stacks are used to preserve * information across nested functions. */ static struct { STACK (IDENTIFIER) id; STACK (TYPE) ret; STACK (int) unreached; STACK (int) declaration; STACK (int) destructor; STACK (int) handler; STACK (STACK (EXP)) loops; STACK (NAMESPACE) labels; STACK (LIST (EXP)) solves; STACK (LIST (EXP)) tries; STACK (unsigned long) opts; } func_stack = { NULL_stack (IDENTIFIER), NULL_stack (TYPE), NULL_stack (int), NULL_stack (int), NULL_stack (int), NULL_stack (int), NULL_stack (STACK (EXP)), NULL_stack (NAMESPACE), NULL_stack (LIST (EXP)), NULL_stack (LIST (EXP)), NULL_stack (unsigned long) }; /* * BEGIN A FUNCTION DEFINITION * * This routine is called at the start of a function definition. t gives * the function type. */ void begin_function(IDENTIFIER id) { TYPE t; int ell; TYPE ret; NAMESPACE ns; NAMESPACE bns; unsigned long n; LIST (TYPE) ex; ERROR err = NULL_err; LIST (IDENTIFIER) p; unsigned long npars = 0; /* Check for previous definition */ if (IS_id_function_etc (id)) { EXP e = DEREF_exp (id_function_etc_defn (id)); DECL_SPEC ds = DEREF_dspec (id_storage (id)); t = DEREF_type (id_function_etc_type (id)); if (IS_NULL_exp (e)) { /* Mark with dummy definition */ MAKE_exp_value (t, e); COPY_exp (id_function_etc_defn (id), e); } else { /* Already defined */ PTR (LOCATION) loc = id_loc (id); report (decl_loc, ERR_basic_odr_def_func (id, loc)); } if ((ds & dspec_inline) && (ds & dspec_called)) { report (decl_loc, ERR_dcl_fct_spec_inline_call (id)); } } else { t = type_func_void; } COPY_loc (id_loc (id), decl_loc); stmt_loc = crt_loc; /* Decompose function type */ while (IS_type_templ (t)) { t = DEREF_type (type_templ_defn (t)); } ell = DEREF_int (type_func_ellipsis (t)); p = DEREF_list (type_func_pids (t)); ex = DEREF_list (type_func_except (t)); ns = DEREF_nspace (type_func_pars (t)); if (IS_NULL_nspace (ns)) { ns = make_namespace (id, nspace_param_tag, 0); } bns = ns; /* Check return type */ ret = DEREF_type (type_func_ret (t)); ret = check_ret_type (ret, &err, 1); if (!IS_NULL_err (err)) { err = concat_error (err, ERR_dcl_fct_ret ()); report (decl_loc, err); } /* Save old function data */ PUSH_id (crt_func_id, func_stack.id); PUSH_type (crt_func_return, func_stack.ret); PUSH_int (unreached_code, func_stack.unreached); PUSH_int (in_declaration, func_stack.declaration); PUSH_int (have_destructor, func_stack.destructor); PUSH_int (in_func_handler, func_stack.handler); PUSH_stack (crt_loop_stack, func_stack.loops); PUSH_nspace (label_namespace, func_stack.labels); PUSH_list (all_solve_stmts, func_stack.solves); PUSH_list (all_try_blocks, func_stack.tries); n = crt_option_value (OPT_VAL_statement_depth); PUSH_ulong (n, func_stack.opts); n = crt_option_value (OPT_VAL_nested_class); PUSH_ulong (n, func_stack.opts); n = number_errors; PUSH_ulong (n, func_stack.opts); /* Set up new function data */ commentary (id); crt_func_id = id; crt_func_return = ret; crt_func_complex = pass_complex_type (ret); unreached_code = 0; unreached_last = 0; unreached_fall = 1; in_declaration = 0; have_destructor = 0; in_func_handler = 0; crt_loop_stack = NULL_stack (EXP); all_solve_stmts = NULL_list (EXP); all_try_blocks = NULL_list (EXP); crt_option_value (OPT_VAL_statement_depth) = 0; crt_option_value (OPT_VAL_nested_class) = 0; if (option (OPT_variable)) record_location++; label_namespace = make_namespace (id, nspace_label_tag, 0); if (do_dump) dump_declare (id, &decl_loc, 1); /* Modify function parameter namespace */ if (IS_nspace_block (bns)) bns = NULL_nspace; MODIFY_nspace_block_etc (nspace_block_tag, ns); COPY_id (nspace_name (ns), id); /* Check function parameters */ crt_id_qualifier = qual_none; while (!IS_NULL_list (p)) { IDENTIFIER par = DEREF_id (HEAD_list (p)); IDENTIFIER par2 = DEREF_id (id_alias (par)); HASHID pnm = DEREF_hashid (id_name (par)); TYPE pt = DEREF_type (id_parameter_type (par)); unsigned ptag = TAG_type (pt); if (!EQ_id (par2, par)) { /* Rename parameter if necessary */ par2 = chase_alias (par2); pnm = DEREF_hashid (id_name (par2)); COPY_hashid (id_name (par), pnm); COPY_id (id_alias (par), par2); } if (do_local) { LOCATION loc; DEREF_loc (id_loc (par), loc); dump_declare (par, &loc, 1); } if (IS_hashid_anon (pnm)) { /* Report anonymous parameters */ LOCATION loc; DEREF_loc (id_loc (par), loc); report (loc, ERR_dcl_fct_par_anon ()); } switch (ptag) { case type_top_tag : case type_bottom_tag : { /* Void parameters have already been reported */ break; } case type_ref_tag : { /* References don't need checking */ break; } default : { /* Check for incomplete types */ err = check_complete (pt); if (!IS_NULL_err (err)) { LOCATION loc; ERROR err2 = ERR_basic_types_par_incompl (par); err = concat_error (err, err2); DEREF_loc (id_loc (par), loc); report (loc, err); } break; } } if (option (OPT_decl_hide)) check_hiding (par); npars++; p = TAIL_list (p); } /* Declare parameters */ push_namespace (ns); block_namespace = bns; IGNORE check_value (OPT_VAL_func_pars, npars); /* Deal with the this pointer */ if (IS_id_mem_func (id)) { IGNORE make_this_decl (id); } /* Deal with the ellipsis parameter */ if (ell & FUNC_ELLIPSIS) make_ellipsis_decl (); /* Create dummy try block */ start_try_check (ex); return; } /* * DECLARE THE IDENTIFIER __func__ * * According to ISO/IEC 9899:1999, the declaration * * static const char __func__[] = "function-name"; * * implicitly follows the opening brace of a function body. This * function simply inserts the tokens for this declaration into the token * stream. The function name is obtained through the global variable * crt_func_id. */ void declare_func_id(void) { int toks[] = { lex_static, lex_const, lex_char, lex_identifier, lex_open_Hsquare_H1, lex_close_Hsquare_H1, lex_assign, lex_string_Hlit, lex_semicolon }; int i; PPTOKEN *p = patch_tokens (ARRAY_SIZE (toks)); for (i = 0; i < ARRAY_SIZE (toks); i++) { p->tok = toks[i]; if (p->tok == lex_identifier) { p->pp_data.id.hash = KEYWORD (lex_func_Hid); } else if (p->tok == lex_string_Hlit) { HASHID h = DEREF_hashid (id_name (crt_func_id)); string s = DEREF_string (hashid_name_text (h)); p->pp_data.str.start = s; p->pp_data.str.end = s + ustrlen (s); } p = p->next; } } /* * END A FUNCTION DEFINITION * * This routine is called at the end of a function definition. The * expression body gives the compound statement comprising the definition. * Note that the parameters are in the outermost scope of body and so * have already been taken out of scope. */ EXP end_function(IDENTIFIER id, EXP body) { /* Check for errors in function */ TYPE ret; int flow = 0; unsigned long n; POP_ulong (n, func_stack.opts); if (option (OPT_variable)) { if (n == number_errors) flow = 1; record_location--; } /* Check function body */ if (!IS_NULL_exp (body)) { if (!unreached_code) { /* Check for falling out of function */ EXP e = fall_return_stmt (); body = add_compound_stmt (body, e); } unreached_code = 0; set_parent_stmt (body, NULL_exp); if (IS_exp_solve_stmt (body)) { /* Analyse enclosing solve statement */ body = solve_labels (body); } else if (check_labels ()) { /* Construct enclosing solve statement */ EXP a; MAKE_exp_solve_stmt (type_void, body, a); CONS_exp (a, all_solve_stmts, all_solve_stmts); set_parent_stmt (body, a); body = solve_labels (a); } end_solve_stmts (); #if LANGUAGE_CPP if (!IS_NULL_list (all_try_blocks)) { /* Check all try blocks */ end_try_blocks (id); } #endif body = end_try_check (id, body); if (flow || (have_destructor && do_usage)) { /* Variable flow analysis */ check_flow (id, body, flow); } } /* Define the function */ if (IS_id_function_etc (id)) { COPY_exp (id_function_etc_defn (id), body); define_id (id); if (!in_template_decl) { compile_function (id, 0); free_nspace (label_namespace); } if (do_dump) dump_undefine (id, &crt_loc, 0); } /* Restore old function data */ POP_id (crt_func_id, func_stack.id); POP_type (ret, func_stack.ret); POP_int (unreached_code, func_stack.unreached); POP_int (in_declaration, func_stack.declaration); POP_int (have_destructor, func_stack.destructor); POP_int (in_func_handler, func_stack.handler); POP_stack (crt_loop_stack, func_stack.loops); POP_nspace (label_namespace, func_stack.labels); POP_list (all_solve_stmts, func_stack.solves); POP_list (all_try_blocks, func_stack.tries); POP_ulong (n, func_stack.opts); crt_option_value (OPT_VAL_nested_class) = n; POP_ulong (n, func_stack.opts); crt_option_value (OPT_VAL_statement_depth) = n; crt_func_complex = pass_complex_type (ret); crt_func_return = ret; block_namespace = NULL_nspace; suppress_variable = 0; unreached_last = 0; return (body); }