From: Nathan Sidwell Date: Wed, 3 Jan 2001 14:39:10 +0000 (+0000) Subject: Implement exceptions specifiers for implicit member functions. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=03378143aca4cb4276e6fb1d2f790ea58bdcaa86;p=platform%2Fupstream%2Fgcc.git Implement exceptions specifiers for implicit member functions. cp: Implement exceptions specifiers for implicit member functions. * cp-tree.h (merge_exceptions_specifiers): Declare new function. * method.c (synthesize_exception_spec): New function. (locate_dtor, locate_ctor, locate_copy): New functions. (implicitly_declare_fn): Generate the exception spec too. * search.c (check_final_overrider): Check artificial functions too. * typeck2.c (merge_exception_specifiers): New function. testsuite: * g++.old-deja/g++.eh/spec6.C: Remove remaining XFAIL. From-SVN: r38659 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4b81b72..bee60d6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2001-01-03 Nathan Sidwell + + Implement exceptions specifiers for implicit member functions. + * cp-tree.h (merge_exceptions_specifiers): Declare new function. + * method.c (synthesize_exception_spec): New function. + (locate_dtor, locate_ctor, locate_copy): New functions. + (implicitly_declare_fn): Generate the exception spec too. + * search.c (check_final_overrider): Check artificial functions + too. + * typeck2.c (merge_exception_specifiers): New function. + 2001-01-03 Jason Merrill * init.c (build_default_init): New fn. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8d5c512..0531865 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4532,6 +4532,7 @@ extern tree build_m_component_ref PARAMS ((tree, tree)); extern tree build_functional_cast PARAMS ((tree, tree)); extern void check_for_new_type PARAMS ((const char *, flagged_type_tree)); extern tree add_exception_specifier PARAMS ((tree, tree, int)); +extern tree merge_exception_specifiers PARAMS ((tree, tree)); /* in xref.c */ extern void GNU_xref_begin PARAMS ((const char *)); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 4c59822..574d6ec 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -98,6 +98,10 @@ static int is_back_referenceable_type PARAMS ((tree)); 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))) @@ -2585,6 +2589,163 @@ synthesize_method (fndecl) 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 @@ -2598,24 +2759,30 @@ implicitly_declare_fn (kind, type, const_p) { 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); @@ -2623,9 +2790,15 @@ implicitly_declare_fn (kind, type, const_p) 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); @@ -2639,8 +2812,11 @@ implicitly_declare_fn (kind, type, const_p) 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); } @@ -2648,7 +2824,7 @@ implicitly_declare_fn (kind, type, const_p) 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); diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 72f0090..e2fab52 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1964,10 +1964,7 @@ check_final_overrider (overrider, basefn) } /* Check throw specifier is subset. */ - /* XXX At the moment, punt with artificial functions. We - don't generate their exception specifiers, so can't check properly. */ - if (! DECL_ARTIFICIAL (overrider) - && !comp_except_specs (base_throw, over_throw, 0)) + if (!comp_except_specs (base_throw, over_throw, 0)) { cp_error_at ("looser throw specifier for `%#F'", overrider); cp_error_at (" overriding `%#F'", basefn); diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 62b384a..5cccddc 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1296,3 +1296,39 @@ add_exception_specifier (list, spec, complain) incomplete_type_error (NULL_TREE, core); return list; } + +/* Combine the two exceptions specifier lists LIST and ADD, and return + their union. */ + +tree +merge_exception_specifiers (list, add) + tree list, add; +{ + if (!list || !add) + return NULL_TREE; + else if (!TREE_VALUE (list)) + return add; + else if (!TREE_VALUE (add)) + return list; + else + { + tree orig_list = list; + + for (; add; add = TREE_CHAIN (add)) + { + tree spec = TREE_VALUE (add); + tree probe; + + for (probe = orig_list; probe; probe = TREE_CHAIN (probe)) + if (same_type_p (TREE_VALUE (probe), spec)) + break; + if (!probe) + { + spec = build_tree_list (NULL_TREE, spec); + TREE_CHAIN (spec) = list; + list = spec; + } + } + } + return list; +} diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e591e1b..c45ae5c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2001-01-03 Nathan Sidwell + + * g++.old-deja/g++.eh/spec6.C: Remove remaining XFAIL. + 2001-01-02 Kaveh R. Ghazi * gcc.c-torture/compile/20010102-1.c: New test. diff --git a/gcc/testsuite/g++.old-deja/g++.eh/spec6.C b/gcc/testsuite/g++.old-deja/g++.eh/spec6.C index b6cd06a..6ecaec0 100644 --- a/gcc/testsuite/g++.old-deja/g++.eh/spec6.C +++ b/gcc/testsuite/g++.old-deja/g++.eh/spec6.C @@ -126,10 +126,7 @@ struct C : A, A1 { virtual void foo() throw(int); // ERROR - looser throw - A::foo virtual void bar() throw(int); // ERROR - looser throw - A1::bar - // The xfail is because we don't build exception specifiers for implicit - // members. So we don't check them either. - // C::~C() throw(int), is the correct specification of the destructor. -}; // ERROR - looser throw - A::~A() - XFAIL +}; // ERROR - looser throw - A::~A() struct D : A, A1 {