static int check_btype PARAMS ((tree));
static void build_mangled_name_for_type PARAMS ((tree));
static void build_mangled_name_for_type_with_Gcode PARAMS ((tree, int));
+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 *));
# define OB_INIT() (scratch_firstobj ? (obstack_free (&scratch_obstack, scratch_firstobj), 0) : 0)
# define OB_PUTC(C) (obstack_1grow (&scratch_obstack, (C)))
pop_function_context_from (context);
}
+/* Use EXTRACTOR to locate the relevant function called for each base &
+ class field of TYPE. CLIENT allows additional information to be passed
+ to EXTRACTOR. Generates the union of all exceptions generated by
+ those functions. */
+
+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)
+ 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;
+}
+
+/* Locate the dtor of TYPE. */
+
+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;
+}
+
+/* Locate the default ctor of TYPE. */
+
+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;
+};
+
+/* Locate the copy ctor or copy assignment of TYPE. CLIENT_
+ points to a COPY_DATA holding the name (NULL for the ctor)
+ and desired qualifiers of the source operand. */
+
+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
+ /* Ambiguous */
+ return NULL_TREE;
+ }
+ return best;
+}
+
/* Implicitly declare the special function indicated by KIND, as a
member of TYPE. For copy constructors and assignment operators,
CONST_P indicates whether these functions should take a const
{
tree declspecs = NULL_TREE;
tree fn, args = NULL_TREE;
+ tree raises = empty_except_spec;
tree argtype;
int retref = 0;
tree name = constructor_name (TYPE_IDENTIFIER (type));
switch (kind)
{
- /* Destructors. */
case sfk_destructor:
+ /* Destructor. */
name = build_parse_node (BIT_NOT_EXPR, name);
args = void_list_node;
+ raises = synthesize_exception_spec (type, &locate_dtor, 0);
break;
case sfk_constructor:
/* Default constructor. */
args = void_list_node;
+ raises = synthesize_exception_spec (type, &locate_ctor, 0);
break;
case sfk_copy_constructor:
+ {
+ struct copy_data data;
+
if (const_p)
type = build_qualified_type (type, TYPE_QUAL_CONST);
argtype = build_reference_type (type);
build_tree_list (hash_tree_chain (argtype, NULL_TREE),
get_identifier ("_ctor_arg")),
void_list_node);
+ data.name = NULL;
+ data.quals = const_p ? TYPE_QUAL_CONST : 0;
+ raises = synthesize_exception_spec (type, &locate_copy, &data);
break;
-
+ }
case sfk_assignment_operator:
+ {
+ struct copy_data data;
+
retref = 1;
declspecs = build_tree_list (NULL_TREE, type);
build_tree_list (hash_tree_chain (argtype, NULL_TREE),
get_identifier ("_ctor_arg")),
void_list_node);
+ data.name = name;
+ data.quals = const_p ? TYPE_QUAL_CONST : 0;
+ raises = synthesize_exception_spec (type, &locate_copy, &data);
break;
-
+ }
default:
my_friendly_abort (59);
}
TREE_PARMLIST (args) = 1;
{
- tree declarator = make_call_declarator (name, args, NULL_TREE, NULL_TREE);
+ tree declarator = make_call_declarator (name, args, NULL_TREE, raises);
if (retref)
declarator = build_parse_node (ADDR_EXPR, declarator);