This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Hi, the attached patch sythesizes the exception specifiers for implicitly defined member functions. It also turns on the checking of these for artificial virtual functions -- primarily dtors -- and hence fixes the last XFAIL in g++.eh/spec6.C. This patch will lead to additional code size, as we will generate the exception specification checking code for these functions -- even though it is guaranteed that they won't be violated. This led to about 10K increase (in about 3MB) in the size of libstdc++.so on i86. The quick hack fix for that is to not generate the exception checking code for such synthesized functions - the general fix is to track what exceptions could be emitted from a scope, and optimize accordingly. Thoughts? built & tested on i686-pc-linux-gnu, ok? nathan -- Dr Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery LLC 'But that's a lie.' - 'Yes it is. What's your point?' nathan@codesourcery.com : http://www.cs.bris.ac.uk/~nathan/ : nathan@acm.org
2000-12-06 Nathan Sidwell <nathan@codesourcery.com> 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. Index: cp/cp-tree.h =================================================================== RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v retrieving revision 1.545 diff -c -3 -p -r1.545 cp-tree.h *** cp-tree.h 2000/12/05 15:50:01 1.545 --- cp-tree.h 2000/12/06 14:24:18 *************** extern tree build_m_component_ref PARAM *** 4570,4575 **** --- 4570,4576 ---- 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 *)); Index: cp/method.c =================================================================== RCS file: /cvs/gcc/egcs/gcc/cp/method.c,v retrieving revision 1.183 diff -c -3 -p -r1.183 method.c *** method.c 2000/12/04 17:00:03 1.183 --- method.c 2000/12/06 14:24:43 *************** static int is_back_referenceable_type PA *** 98,103 **** --- 98,107 ---- 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))) *************** synthesize_method (fndecl) *** 2585,2590 **** --- 2589,2750 ---- pop_function_context_from (context); } + /* Use EXTRACTOR to locate the relevant function called for each base & + class field of TYPE. QUALS allows cv quals 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 *************** implicitly_declare_fn (kind, type, const *** 2598,2621 **** { tree declspecs = NULL_TREE; tree fn, args = NULL_TREE; tree argtype; int retref = 0; tree name = constructor_name (TYPE_IDENTIFIER (type)); switch (kind) { - /* Destructors. */ case sfk_destructor: name = build_parse_node (BIT_NOT_EXPR, name); args = void_list_node; break; case sfk_constructor: /* Default constructor. */ args = void_list_node; break; case sfk_copy_constructor: if (const_p) type = build_qualified_type (type, TYPE_QUAL_CONST); argtype = build_reference_type (type); --- 2758,2787 ---- { 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) { 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); *************** implicitly_declare_fn (kind, type, const *** 2623,2631 **** build_tree_list (hash_tree_chain (argtype, NULL_TREE), get_identifier ("_ctor_arg")), void_list_node); break; ! case sfk_assignment_operator: retref = 1; declspecs = build_tree_list (NULL_TREE, type); --- 2789,2803 ---- 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); *************** implicitly_declare_fn (kind, type, const *** 2639,2646 **** build_tree_list (hash_tree_chain (argtype, NULL_TREE), get_identifier ("_ctor_arg")), void_list_node); break; ! default: my_friendly_abort (59); } --- 2811,2821 ---- 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); } *************** implicitly_declare_fn (kind, type, const *** 2648,2654 **** TREE_PARMLIST (args) = 1; { ! tree declarator = make_call_declarator (name, args, NULL_TREE, NULL_TREE); if (retref) declarator = build_parse_node (ADDR_EXPR, declarator); --- 2823,2829 ---- TREE_PARMLIST (args) = 1; { ! tree declarator = make_call_declarator (name, args, NULL_TREE, raises); if (retref) declarator = build_parse_node (ADDR_EXPR, declarator); Index: cp/search.c =================================================================== RCS file: /cvs/gcc/egcs/gcc/cp/search.c,v retrieving revision 1.193 diff -c -3 -p -r1.193 search.c *** search.c 2000/12/05 15:50:03 1.193 --- search.c 2000/12/06 14:24:46 *************** check_final_overrider (overrider, basefn *** 1962,1971 **** } /* 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)) { cp_error_at ("looser throw specifier for `%#F'", overrider); cp_error_at (" overriding `%#F'", basefn); --- 1962,1968 ---- } /* Check throw specifier is subset. */ ! if (!comp_except_specs (base_throw, over_throw, 0)) { cp_error_at ("looser throw specifier for `%#F'", overrider); cp_error_at (" overriding `%#F'", basefn); Index: cp/typeck2.c =================================================================== RCS file: /cvs/gcc/egcs/gcc/cp/typeck2.c,v retrieving revision 1.91 diff -c -3 -p -r1.91 typeck2.c *** typeck2.c 2000/11/17 09:48:53 1.91 --- typeck2.c 2000/12/06 14:24:48 *************** add_exception_specifier (list, spec, com *** 1283,1285 **** --- 1283,1318 ---- incomplete_type_error (NULL_TREE, core); return list; } + + 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; + } Index: testsuite/g++.old-deja/g++.eh/spec6.C =================================================================== RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.eh/spec6.C,v retrieving revision 1.4 diff -c -3 -p -r1.4 spec6.C *** spec6.C 2000/12/05 15:50:06 1.4 --- spec6.C 2000/12/06 14:28:23 *************** struct C : A, A1 *** 126,135 **** { 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 struct D : A, A1 { --- 126,132 ---- { virtual void foo() throw(int); // ERROR - looser throw - A::foo virtual void bar() throw(int); // ERROR - looser throw - A1::bar ! }; // ERROR - looser throw - A::~A() struct D : A, A1 {
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |