Implement exceptions specifiers for implicit member functions.
authorNathan Sidwell <nathan@codesourcery.com>
Wed, 3 Jan 2001 14:39:10 +0000 (14:39 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Wed, 3 Jan 2001 14:39:10 +0000 (14:39 +0000)
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

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/method.c
gcc/cp/search.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.old-deja/g++.eh/spec6.C

index 4b81b72..bee60d6 100644 (file)
@@ -1,3 +1,14 @@
+2001-01-03  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. 
+
 2001-01-03  Jason Merrill  <jason@redhat.com>
 
        * init.c (build_default_init): New fn.
index 8d5c512..0531865 100644 (file)
@@ -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 *));
index 4c59822..574d6ec 100644 (file)
@@ -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);
 
index 72f0090..e2fab52 100644 (file)
@@ -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);
index 62b384a..5cccddc 100644 (file)
@@ -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;
+}
index e591e1b..c45ae5c 100644 (file)
@@ -1,3 +1,7 @@
+2001-01-03  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * g++.old-deja/g++.eh/spec6.C: Remove remaining XFAIL.
+
 2001-01-02  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        * gcc.c-torture/compile/20010102-1.c: New test.
index b6cd06a..6ecaec0 100644 (file)
@@ -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
 {