#include "config.h"
#include "system.h"
#include "tree.h"
#include "cp-tree.h"
#include "rtl.h"
#include "expr.h"
#include "output.h"
#include "flags.h"
#include "toplev.h"
#include "tm_p.h"
#include "target.h"
enum mangling_flags
{
mf_none = 0,
mf_maybe_uninstantiated = 1,
mf_use_underscores_around_value = 2,
};
typedef enum mangling_flags mangling_flags;
static void do_build_assign_ref PARAMS ((tree));
static void do_build_copy_constructor PARAMS ((tree));
static tree synthesize_exception_spec PARAMS ((tree, tree (*) (tree, void *), void *));
static tree locate_dtor PARAMS ((tree, void *));
static tree locate_ctor PARAMS ((tree, void *));
static tree locate_copy PARAMS ((tree, void *));
void
init_method ()
{
init_mangle ();
}
void
set_mangled_name_for_decl (decl)
tree decl;
{
if (processing_template_decl)
return;
mangle_decl (decl);
}
tree
build_opfncall (code, flags, xarg1, xarg2, arg3)
enum tree_code code;
int flags;
tree xarg1, xarg2, arg3;
{
return build_new_op (code, flags, xarg1, xarg2, arg3);
}
tree
hack_identifier (value, name)
tree value, name;
{
tree type;
if (value == error_mark_node)
return error_mark_node;
type = TREE_TYPE (value);
if (TREE_CODE (value) == FIELD_DECL)
{
if (current_class_ptr == NULL_TREE)
{
if (current_function_decl
&& DECL_STATIC_FUNCTION_P (current_function_decl))
error ("invalid use of member `%D' in static member function",
value);
else
error ("invalid use of member `%D'", value);
return error_mark_node;
}
TREE_USED (current_class_ptr) = 1;
if (processing_template_decl)
value = build_min_nt (COMPONENT_REF, current_class_ref, name);
else
{
tree access_type = current_class_type;
while (!DERIVED_FROM_P (context_for_name_lookup (value),
access_type))
{
access_type = TYPE_CONTEXT (access_type);
while (DECL_P (access_type))
access_type = DECL_CONTEXT (access_type);
}
enforce_access (access_type, value);
value
= build_class_member_access_expr (current_class_ref, value,
NULL_TREE,
false);
}
}
else if ((TREE_CODE (value) == FUNCTION_DECL
&& DECL_FUNCTION_MEMBER_P (value))
|| (TREE_CODE (value) == OVERLOAD
&& DECL_FUNCTION_MEMBER_P (OVL_CURRENT (value))))
{
tree decl;
if (TREE_CODE (value) == OVERLOAD)
value = OVL_CURRENT (value);
decl = maybe_dummy_object (DECL_CONTEXT (value), 0);
value = finish_class_member_access_expr (decl, name);
}
else if (really_overloaded_fn (value))
;
else if (TREE_CODE (value) == OVERLOAD)
mark_used (OVL_FUNCTION (value));
else if (TREE_CODE (value) == TREE_LIST)
{
tree t = value;
while (t && TREE_CODE (t) == TREE_LIST)
{
mark_used (TREE_VALUE (t));
t = TREE_CHAIN (t);
}
}
else if (TREE_CODE (value) == NAMESPACE_DECL)
{
error ("use of namespace `%D' as expression", value);
return error_mark_node;
}
else if (DECL_CLASS_TEMPLATE_P (value))
{
error ("use of class template `%T' as expression", value);
return error_mark_node;
}
else
mark_used (value);
if (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == PARM_DECL
|| TREE_CODE (value) == RESULT_DECL)
{
tree context = decl_function_context (value);
if (context != NULL_TREE && context != current_function_decl
&& ! TREE_STATIC (value))
{
error ("use of %s from containing function",
(TREE_CODE (value) == VAR_DECL
? "`auto' variable" : "parameter"));
cp_error_at (" `%#D' declared here", value);
value = error_mark_node;
}
}
if (DECL_P (value) && DECL_NONLOCAL (value))
{
if (DECL_CLASS_SCOPE_P (value)
&& DECL_CONTEXT (value) != current_class_type)
{
tree path;
path = currently_open_derived_class (DECL_CONTEXT (value));
enforce_access (path, value);
}
}
else if (TREE_CODE (value) == TREE_LIST
&& TREE_TYPE (value) == error_mark_node)
{
error ("\
request for member `%D' is ambiguous in multiple inheritance lattice",
name);
print_candidates (value);
return error_mark_node;
}
if (! processing_template_decl)
value = convert_from_reference (value);
return value;
}
tree
make_thunk (function, delta, vcall_index)
tree function;
tree delta;
tree vcall_index;
{
tree thunk_id;
tree thunk;
tree vcall_offset;
HOST_WIDE_INT d;
my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 20021025);
if (vcall_index)
vcall_offset
= size_binop (MULT_EXPR,
vcall_index,
convert (ssizetype,
TYPE_SIZE_UNIT (vtable_entry_type)));
else
vcall_offset = NULL_TREE;
d = tree_low_cst (delta, 0);
for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
if (THUNK_DELTA (thunk) == d
&& ((THUNK_VCALL_OFFSET (thunk) != NULL_TREE)
== (vcall_offset != NULL_TREE))
&& (THUNK_VCALL_OFFSET (thunk)
? tree_int_cst_equal (THUNK_VCALL_OFFSET (thunk),
vcall_offset)
: true))
return thunk;
my_friendly_assert (!TREE_ASM_WRITTEN (function), 20021025);
thunk_id = mangle_thunk (function, delta, vcall_offset);
thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (function));
DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function);
cxx_dup_lang_specific_decl (function);
SET_DECL_ASSEMBLER_NAME (thunk, thunk_id);
DECL_CONTEXT (thunk) = DECL_CONTEXT (function);
TREE_READONLY (thunk) = TREE_READONLY (function);
TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function);
TREE_PUBLIC (thunk) = TREE_PUBLIC (function);
if (flag_weak)
comdat_linkage (thunk);
SET_DECL_THUNK_P (thunk);
DECL_INITIAL (thunk) = build1 (ADDR_EXPR, vfunc_ptr_type_node, function);
THUNK_DELTA (thunk) = d;
THUNK_VCALL_OFFSET (thunk) = vcall_offset;
DECL_INTERFACE_KNOWN (thunk) = 1;
DECL_NOT_REALLY_EXTERN (thunk) = 1;
DECL_SAVED_FUNCTION_DATA (thunk) = NULL;
DECL_DESTRUCTOR_P (thunk) = 0;
DECL_CONSTRUCTOR_P (thunk) = 0;
DECL_CLONED_FUNCTION (thunk) = NULL_TREE;
DECL_EXTERNAL (thunk) = 1;
DECL_ARTIFICIAL (thunk) = 1;
DECL_NO_STATIC_CHAIN (thunk) = 1;
DECL_PENDING_INLINE_P (thunk) = 0;
DECL_INLINE (thunk) = 0;
DECL_DECLARED_INLINE_P (thunk) = 0;
DECL_DEFERRED_FN (thunk) = 0;
TREE_CHAIN (thunk) = DECL_THUNKS (function);
DECL_THUNKS (function) = thunk;
return thunk;
}
void
use_thunk (thunk_fndecl, emit_p)
tree thunk_fndecl;
int emit_p;
{
tree fnaddr;
tree function;
tree vcall_offset;
HOST_WIDE_INT delta, vcall_value;
if (TREE_ASM_WRITTEN (thunk_fndecl))
return;
fnaddr = DECL_INITIAL (thunk_fndecl);
if (TREE_CODE (DECL_INITIAL (thunk_fndecl)) != ADDR_EXPR)
return;
TREE_ADDRESSABLE (thunk_fndecl) = 1;
function = TREE_OPERAND (fnaddr, 0);
TREE_ADDRESSABLE (function) = 1;
mark_used (function);
TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (function)) = 1;
if (!emit_p)
return;
delta = THUNK_DELTA (thunk_fndecl);
vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl);
if (vcall_offset)
{
vcall_value = tree_low_cst (vcall_offset, 0);
if (!vcall_value)
abort ();
}
else
vcall_value = 0;
mark_used (thunk_fndecl);
DECL_EXTERNAL (thunk_fndecl) = 0;
TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function);
if (flag_syntax_only)
{
TREE_ASM_WRITTEN (thunk_fndecl) = 1;
return;
}
#if defined(DECL_PRIVATE_EXTERN) && defined(COALESCE_STATIC_THUNK)
DECL_PRIVATE_EXTERN (thunk_fndecl) = DECL_PRIVATE_EXTERN (function);
if (DECL_PRIVATE_EXTERN (function) || !TREE_PUBLIC (function) || DECL_INLINE (function))
COALESCE_STATIC_THUNK (thunk_fndecl, 0);
#endif
push_to_top_level ();
DECL_INITIAL (thunk_fndecl) = make_node (BLOCK);
BLOCK_VARS (DECL_INITIAL (thunk_fndecl))
= DECL_ARGUMENTS (thunk_fndecl);
if (targetm.asm_out.can_output_mi_thunk (thunk_fndecl, delta,
vcall_value, function))
{
const char *fnname;
current_function_decl = thunk_fndecl;
DECL_RESULT (thunk_fndecl)
= build_decl (RESULT_DECL, 0, integer_type_node);
fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
init_function_start (thunk_fndecl, input_filename, lineno);
current_function_is_thunk = 1;
assemble_start_function (thunk_fndecl, fnname);
targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl, delta,
vcall_value, function);
assemble_end_function (thunk_fndecl, fnname);
current_function_decl = 0;
cfun = 0;
TREE_ASM_WRITTEN (thunk_fndecl) = 1;
}
else
{
tree a, t;
if (varargs_function_p (function))
error ("generic thunk code fails for method `%#D' which uses `...'",
function);
t = NULL_TREE;
for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
{
tree x = copy_node (a);
TREE_CHAIN (x) = t;
DECL_CONTEXT (x) = thunk_fndecl;
t = x;
}
a = nreverse (t);
DECL_ARGUMENTS (thunk_fndecl) = a;
DECL_RESULT (thunk_fndecl) = NULL_TREE;
start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
t = ssize_int (delta);
t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
if (vcall_offset && !integer_zerop (vcall_offset))
{
tree orig_this;
t = save_expr (t);
orig_this = t;
t = build1 (NOP_EXPR,
build_pointer_type (build_pointer_type
(vtable_entry_type)),
t);
t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
t = build (PLUS_EXPR, TREE_TYPE (t), t, vcall_offset);
t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
t = fold (build (PLUS_EXPR,
TREE_TYPE (orig_this),
orig_this,
t));
}
t = tree_cons (NULL_TREE, t, NULL_TREE);
for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
t = tree_cons (NULL_TREE, a, t);
t = nreverse (t);
t = build_call (function, t);
if (VOID_TYPE_P (TREE_TYPE (t)))
finish_expr_stmt (t);
else
finish_return_stmt (t);
TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (thunk_fndecl)) = 1;
DECL_IGNORED_P (thunk_fndecl) = 1;
expand_body (finish_function (0));
}
pop_from_top_level ();
}
static void
do_build_copy_constructor (fndecl)
tree fndecl;
{
tree parm = FUNCTION_FIRST_USER_PARM (fndecl);
tree t;
parm = convert_from_reference (parm);
if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)
&& is_empty_class (current_class_type))
;
else if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type))
{
t = build (INIT_EXPR, void_type_node, current_class_ref, parm);
finish_expr_stmt (t);
}
else
{
tree fields = TYPE_FIELDS (current_class_type);
int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type);
tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
tree member_init_list = NULL_TREE;
int cvquals = cp_type_quals (TREE_TYPE (parm));
int i;
for (t = CLASSTYPE_VBASECLASSES (current_class_type); t;
t = TREE_CHAIN (t))
{
tree binfo = TREE_VALUE (t);
member_init_list
= tree_cons (binfo,
build_tree_list (NULL_TREE,
build_base_path (PLUS_EXPR, parm,
binfo, 1)),
member_init_list);
}
for (i = 0; i < n_bases; ++i)
{
tree binfo = TREE_VEC_ELT (binfos, i);
if (TREE_VIA_VIRTUAL (binfo))
continue;
member_init_list
= tree_cons (binfo,
build_tree_list (NULL_TREE,
build_base_path (PLUS_EXPR, parm,
binfo, 1)),
member_init_list);
}
for (; fields; fields = TREE_CHAIN (fields))
{
tree init;
tree field = fields;
tree expr_type;
if (TREE_CODE (field) != FIELD_DECL)
continue;
init = parm;
if (DECL_NAME (field))
{
if (VFIELD_NAME_P (DECL_NAME (field)))
continue;
if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field)
continue;
}
else if ((t = TREE_TYPE (field)) != NULL_TREE
&& ANON_AGGR_TYPE_P (t)
&& TYPE_FIELDS (t) != NULL_TREE)
;
else
continue;
expr_type = TREE_TYPE (field);
if (TREE_CODE (expr_type) != REFERENCE_TYPE)
expr_type = cp_build_qualified_type (expr_type, cvquals);
init = build (COMPONENT_REF, expr_type, init, field);
init = build_tree_list (NULL_TREE, init);
member_init_list
= tree_cons (field, init, member_init_list);
}
finish_mem_initializers (member_init_list);
}
}
static void
do_build_assign_ref (fndecl)
tree fndecl;
{
tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
tree compound_stmt;
compound_stmt = begin_compound_stmt (0);
parm = convert_from_reference (parm);
if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)
&& is_empty_class (current_class_type))
;
else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type))
{
tree t = build (MODIFY_EXPR, void_type_node, current_class_ref, parm);
finish_expr_stmt (t);
}
else
{
tree fields;
int cvquals = cp_type_quals (TREE_TYPE (parm));
int i;
for (i = 0; i < CLASSTYPE_N_BASECLASSES (current_class_type); ++i)
{
tree binfo;
tree converted_parm;
binfo = BINFO_BASETYPE (TYPE_BINFO (current_class_type), i);
converted_parm = build_base_path (PLUS_EXPR, parm, binfo, 1);
finish_expr_stmt
(build_special_member_call (current_class_ref,
ansi_assopname (NOP_EXPR),
build_tree_list (NULL_TREE,
converted_parm),
binfo,
LOOKUP_NORMAL | LOOKUP_NONVIRTUAL));
}
for (fields = TYPE_FIELDS (current_class_type);
fields;
fields = TREE_CHAIN (fields))
{
tree comp, init, t;
tree field = fields;
if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
continue;
if (CP_TYPE_CONST_P (TREE_TYPE (field)))
{
error ("non-static const member `%#D', can't use default assignment operator", field);
continue;
}
else if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE)
{
error ("non-static reference member `%#D', can't use default assignment operator", field);
continue;
}
comp = current_class_ref;
init = parm;
if (DECL_NAME (field))
{
if (VFIELD_NAME_P (DECL_NAME (field)))
continue;
if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field)
continue;
}
else if ((t = TREE_TYPE (field)) != NULL_TREE
&& ANON_AGGR_TYPE_P (t)
&& TYPE_FIELDS (t) != NULL_TREE)
;
else
continue;
comp = build (COMPONENT_REF, TREE_TYPE (field), comp, field);
init = build (COMPONENT_REF,
cp_build_qualified_type (TREE_TYPE (field), cvquals),
init, field);
if (DECL_NAME (field))
finish_expr_stmt (build_modify_expr (comp, NOP_EXPR, init));
else
finish_expr_stmt (build (MODIFY_EXPR, TREE_TYPE (comp), comp,
init));
}
}
finish_return_stmt (current_class_ref);
finish_compound_stmt (0, compound_stmt);
}
void
synthesize_method (fndecl)
tree fndecl;
{
int nested = (current_function_decl != NULL_TREE);
tree context = decl_function_context (fndecl);
int need_body = 1;
tree stmt;
if (at_eof)
import_export_decl (fndecl);
if (DECL_CLONED_FUNCTION_P (fndecl))
{
synthesize_method (DECL_CLONED_FUNCTION (fndecl));
return;
}
if (! context)
push_to_top_level ();
else if (nested)
push_function_context_to (context);
DECL_SOURCE_LINE (fndecl) = lineno;
DECL_SOURCE_FILE (fndecl) = input_filename;
interface_unknown = 1;
start_function (NULL_TREE, fndecl, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED);
clear_last_expr ();
stmt = begin_function_body ();
if (DECL_OVERLOADED_OPERATOR_P (fndecl) == NOP_EXPR)
{
do_build_assign_ref (fndecl);
need_body = 0;
}
else if (DECL_CONSTRUCTOR_P (fndecl))
{
tree arg_chain = FUNCTION_FIRST_USER_PARMTYPE (fndecl);
if (arg_chain != void_list_node)
do_build_copy_constructor (fndecl);
else if (TYPE_NEEDS_CONSTRUCTING (current_class_type))
finish_mem_initializers (NULL_TREE);
}
if (need_body)
{
tree compound_stmt;
compound_stmt = begin_compound_stmt (0);
finish_compound_stmt (0, compound_stmt);
}
finish_function_body (stmt);
expand_body (finish_function (0));
extract_interface_info ();
if (! context)
pop_from_top_level ();
else if (nested)
pop_function_context_from (context);
}
static tree
synthesize_exception_spec (type, extractor, client)
tree type;
tree (*extractor) (tree, void *);
void *client;
{
tree raises = empty_except_spec;
tree fields = TYPE_FIELDS (type);
int i, n_bases = CLASSTYPE_N_BASECLASSES (type);
tree binfos = TYPE_BINFO_BASETYPES (type);
for (i = 0; i != n_bases; i++)
{
tree base = BINFO_TYPE (TREE_VEC_ELT (binfos, i));
tree fn = (*extractor) (base, client);
if (fn)
{
tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
raises = merge_exception_specifiers (raises, fn_raises);
}
}
for (; fields; fields = TREE_CHAIN (fields))
{
tree type = TREE_TYPE (fields);
tree fn;
if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields))
continue;
while (TREE_CODE (type) == ARRAY_TYPE)
type = TREE_TYPE (type);
if (TREE_CODE (type) != RECORD_TYPE)
continue;
fn = (*extractor) (type, client);
if (fn)
{
tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
raises = merge_exception_specifiers (raises, fn_raises);
}
}
return raises;
}
static tree
locate_dtor (type, client)
tree type;
void *client ATTRIBUTE_UNUSED;
{
tree fns;
if (!TYPE_HAS_DESTRUCTOR (type))
return NULL_TREE;
fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type),
CLASSTYPE_DESTRUCTOR_SLOT);
return fns;
}
static tree
locate_ctor (type, client)
tree type;
void *client ATTRIBUTE_UNUSED;
{
tree fns;
if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
return NULL_TREE;
fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type),
CLASSTYPE_CONSTRUCTOR_SLOT);
for (; fns; fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
if (sufficient_parms_p (TREE_CHAIN (parms)))
return fn;
}
return NULL_TREE;
}
struct copy_data
{
tree name;
int quals;
};
static tree
locate_copy (type, client_)
tree type;
void *client_;
{
struct copy_data *client = (struct copy_data *)client_;
tree fns;
int ix = -1;
tree best = NULL_TREE;
int excess_p = 0;
if (client->name)
{
if (TYPE_HAS_ASSIGN_REF (type))
ix = lookup_fnfields_1 (type, client->name);
}
else if (TYPE_HAS_INIT_REF (type))
ix = CLASSTYPE_CONSTRUCTOR_SLOT;
if (ix < 0)
return NULL_TREE;
fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), ix);
for (; fns; fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
tree src_type;
int excess;
int quals;
parms = TREE_CHAIN (parms);
if (!parms)
continue;
src_type = TREE_VALUE (parms);
if (TREE_CODE (src_type) == REFERENCE_TYPE)
src_type = TREE_TYPE (src_type);
if (!same_type_ignoring_top_level_qualifiers_p (src_type, type))
continue;
if (!sufficient_parms_p (TREE_CHAIN (parms)))
continue;
quals = cp_type_quals (src_type);
if (client->quals & ~quals)
continue;
excess = quals & ~client->quals;
if (!best || (excess_p && !excess))
{
best = fn;
excess_p = excess;
}
else
return NULL_TREE;
}
return best;
}
tree
implicitly_declare_fn (kind, type, const_p)
special_function_kind kind;
tree type;
int const_p;
{
tree declspecs = NULL_TREE;
tree fn, args = NULL_TREE;
tree raises = empty_except_spec;
int retref = 0;
int has_parm = 0;
tree name = constructor_name (TYPE_IDENTIFIER (type));
switch (kind)
{
case sfk_destructor:
name = build_nt (BIT_NOT_EXPR, name);
args = void_list_node;
raises = synthesize_exception_spec (type, &locate_dtor, 0);
break;
case sfk_constructor:
args = void_list_node;
raises = synthesize_exception_spec (type, &locate_ctor, 0);
break;
case sfk_copy_constructor:
case sfk_assignment_operator:
{
struct copy_data data;
tree argtype = type;
has_parm = 1;
data.name = NULL;
data.quals = 0;
if (kind == sfk_assignment_operator)
{
retref = 1;
declspecs = build_tree_list (NULL_TREE, type);
name = ansi_assopname (NOP_EXPR);
data.name = name;
}
if (const_p)
{
data.quals = TYPE_QUAL_CONST;
argtype = build_qualified_type (argtype, TYPE_QUAL_CONST);
}
argtype = build_reference_type (argtype);
args = build_tree_list (hash_tree_chain (argtype, NULL_TREE),
get_identifier ("_ctor_arg"));
args = tree_cons (NULL_TREE, args, void_list_node);
raises = synthesize_exception_spec (type, &locate_copy, &data);
break;
}
default:
abort ();
}
TREE_PARMLIST (args) = 1;
{
tree declarator = make_call_declarator (name, args, NULL_TREE, raises);
if (retref)
declarator = build_nt (ADDR_EXPR, declarator);
fn = grokfield (declarator, declspecs, NULL_TREE, NULL_TREE, NULL_TREE);
if (has_parm)
TREE_USED (FUNCTION_FIRST_USER_PARM (fn)) = 1;
}
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 20000408);
DECL_ARTIFICIAL (fn) = 1;
DECL_NOT_REALLY_EXTERN (fn) = 1;
DECL_DECLARED_INLINE_P (fn) = 1;
DECL_INLINE (fn) = 1;
defer_fn (fn);
return fn;
}
tree
skip_artificial_parms_for (fn, list)
tree fn, list;
{
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
list = TREE_CHAIN (list);
else
return list;
if (DECL_HAS_IN_CHARGE_PARM_P (fn))
list = TREE_CHAIN (list);
if (DECL_HAS_VTT_PARM_P (fn))
list = TREE_CHAIN (list);
return list;
}