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]

[C++ PATCH] exception specifiers for implicit members


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]