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


Hi,
I've committed the attached patch, which was originally submitted as
http://egcs.cygnus.com/ml/gcc-patches/1999-04/msg00243.html

This patch is slightly altered, in that it implements the letter of the
standard wrt 15.4/7 at compile time. I.e. If the type has cv qualifiers it does
not participate in base class lookup. This is at variance as to how 15.1/3 and
15.3/3 behave (toplevel cv qualifiers are removed from the thrown type and
additional cv qualifiers can be inserted in the caught type. We implement the
runtime behavious of throw specifiers as a sequence of catch clauses, and will
do these cv conversions. So at compile time when we check the throw specifier
of an overriding virtual function we follow the standard.

Martin and I had a discussion about this, archived around
http://egcs.cygnus.com/ml/gcc/1999-03/msg00150.html, which details the
`surprise' which the standard mandates.

This patch introduces a new global variable `empty_except_spec' which you
should use when generating the type of a nothrow function, i.e.
    void_ftype_ptr
!     = build_exception_variant (void_ftype_ptr, empty_except_spec);

rather than consing an empty tree node. [the patch will work even if you do
that, but there's no need].

Also you should use the new function add_exception_specifier to cons up the
exception specification of a function. This will ensure no incomplete types get
added etc.

The patch still keeps exception specifiers as unordered lists. I'll be
submitting a patch to this to order them and hence speed up comparing exception
sets (Ok Mark :-)

That's all for the moment.

nathan
-- 
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
        I have seen the death of PhotoShop -- it is called GIMP
nathan@acm.org  http://www.cs.bris.ac.uk/~nathan/  nathan@cs.bris.ac.uk
Index: egcs/gcc/cp/ChangeLog
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/ChangeLog,v
retrieving revision 1.1162
diff -c -3 -p -r1.1162 ChangeLog
*** ChangeLog	1999/08/03 15:04:44	1.1162
--- ChangeLog	1999/08/04 08:56:14
***************
*** 1,3 ****
--- 1,33 ----
+ 1999-08-04  Nathan Sidwell  <nathan@acm.org>
+ 
+ 	* cp-tree.h (empty_except_spec): New global var.
+ 	(compexcepttypes): Remove prototype.
+ 	(comp_except_specs): Prototype new global function.
+ 	(add_exception_specifier): Prototype new global function.
+ 	* decl.c (empty_except_spec): Define new global var.
+ 	(duplicate_decls): Use comp_except_specs, reword error message.
+ 	(init_decl_processing): Initialize empty_except_spec.
+ 	Adjust build_exception_variant calls.
+ 	* parse.y (exception_specification_opt): Use empty_except_spec.
+ 	(ansi_raise_identifier): Call check_for_new_type.
+ 	(ansi_raise_identifiers): Use add_exception_specifier.
+ 	* pt.c (tsubst): Use add_exception_specifier to build exception
+ 	specifier.
+ 	* search.c (check_final_overrider): New static function, broken
+ 	out of get_matching_virtual. Check throw specifiers, reword
+ 	diagnostics.
+ 	(get_matching_virtual): Use check_final_overrider.
+ 	* tree.c (build_exception_variant): Use comp_except_specs.
+ 	* typeck.c (compexcepttypes): Remove.
+ 	(comp_except_types): New static function, helper for
+ 	comp_except_specs. Compare two types as exception specifiers.
+ 	(comp_except_specs): New global function, compare two exception
+ 	specifiers.
+ 	(comptypes): Adjust for comp_except_specs.
+ 	* typeck2.c (add_exception_specifier): New global function.
+ 	
+ 	* class.c (check_for_override): Reword error message.
+ 
  1999-08-03  Nathan Sidwell  <nathan@acm.org>
  
  	* call.c (convert_arg_to_ellipsis): Use pod_type_p.
Index: egcs/gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.254
diff -c -3 -p -r1.254 cp-tree.h
*** cp-tree.h	1999/08/03 15:04:48	1.254
--- cp-tree.h	1999/08/04 08:56:18
*************** extern tree delta2_identifier;
*** 2288,2293 ****
--- 2288,2294 ----
  extern tree pfn_or_delta2_identifier;
  extern tree tag_identifier;
  extern tree vt_off_identifier;
+ extern tree empty_except_spec;
  
  /* A node that is a list (length 1) of error_mark_nodes.  */
  extern tree error_mark_list;
*************** extern int fntype_p				PROTO((tree));
*** 3533,3539 ****
  extern tree commonparms				PROTO((tree, tree));
  extern tree original_type			PROTO((tree));
  extern tree common_type				PROTO((tree, tree));
! extern int compexcepttypes			PROTO((tree, tree));
  extern int comptypes				PROTO((tree, tree, int));
  extern int comp_target_types			PROTO((tree, tree, int));
  extern int compparms				PROTO((tree, tree));
--- 3534,3540 ----
  extern tree commonparms				PROTO((tree, tree));
  extern tree original_type			PROTO((tree));
  extern tree common_type				PROTO((tree, tree));
! extern int comp_except_specs			PROTO((tree, tree, int));
  extern int comptypes				PROTO((tree, tree, int));
  extern int comp_target_types			PROTO((tree, tree, int));
  extern int compparms				PROTO((tree, tree));
*************** extern tree build_functional_cast		PROTO
*** 3618,3623 ****
--- 3619,3625 ----
  extern char *enum_name_string			PROTO((tree, tree));
  extern void report_case_error			PROTO((int, tree, tree, tree));
  extern void check_for_new_type			PROTO((const char *, flagged_type_tree));
+ extern tree add_exception_specifier             PROTO((tree, tree, int));
  
  /* in xref.c */
  extern void GNU_xref_begin			PROTO((const char *));
Index: egcs/gcc/cp/decl.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/decl.c,v
retrieving revision 1.390
diff -c -3 -p -r1.390 decl.c
*** decl.c	1999/08/03 14:24:05	1.390
--- decl.c	1999/08/04 08:56:30
*************** tree pfn_identifier, index_identifier, d
*** 336,341 ****
--- 336,344 ----
  tree pfn_or_delta2_identifier, tag_identifier;
  tree vt_off_identifier;
  
+ /* Exception specifier used for throw().  */
+ tree empty_except_spec;
+ 
  struct named_label_list
  {
    struct binding_level *binding_level;
*************** duplicate_decls (newdecl, olddecl)
*** 3478,3488 ****
  	  if ((pedantic || ! DECL_IN_SYSTEM_HEADER (olddecl))
  	      && DECL_SOURCE_LINE (olddecl) != 0
  	      && flag_exceptions
! 	      && ! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl)))
  	    {
! 	      cp_pedwarn ("declaration of `%D' throws different exceptions",
  			newdecl);
! 	      cp_pedwarn_at ("previous declaration here", olddecl);
  	    }
  	}
        TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
--- 3481,3492 ----
  	  if ((pedantic || ! DECL_IN_SYSTEM_HEADER (olddecl))
  	      && DECL_SOURCE_LINE (olddecl) != 0
  	      && flag_exceptions
! 	      && !comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)),
! 	                             TYPE_RAISES_EXCEPTIONS (TREE_TYPE (olddecl)), 1))
  	    {
! 	      cp_error ("declaration of `%F' throws different exceptions",
  			newdecl);
! 	      cp_error_at ("to previous declaration `%F'", olddecl);
  	    }
  	}
        TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
*************** init_decl_processing ()
*** 6361,6366 ****
--- 6365,6371 ----
    const_string_type_node
      = build_pointer_type (build_qualified_type (char_type_node, 
  						TYPE_QUAL_CONST));
+   empty_except_spec = build_tree_list (NULL_TREE, NULL_TREE);
  #if 0
    record_builtin_type (RID_MAX, NULL_PTR, string_type_node);
  #endif
*************** init_decl_processing ()
*** 6400,6407 ****
    c_common_nodes_and_builtins (1, flag_no_builtin, flag_no_nonansi_builtin);
  
    void_ftype_ptr
!     = build_exception_variant (void_ftype_ptr,
! 			       tree_cons (NULL_TREE, NULL_TREE, NULL_TREE));
  
    /* C++ extensions */
  
--- 6405,6411 ----
    c_common_nodes_and_builtins (1, flag_no_builtin, flag_no_nonansi_builtin);
  
    void_ftype_ptr
!     = build_exception_variant (void_ftype_ptr, empty_except_spec);
  
    /* C++ extensions */
  
*************** init_decl_processing ()
*** 6547,6555 ****
      if (flag_honor_std)
        pop_namespace ();
      newtype = build_exception_variant
!       (ptr_ftype_sizetype, build_tree_list (NULL_TREE, bad_alloc_type_node));
!     deltype = build_exception_variant
!       (void_ftype_ptr, build_tree_list (NULL_TREE, NULL_TREE));
      auto_function (ansi_opname[(int) NEW_EXPR], newtype, NOT_BUILT_IN);
      auto_function (ansi_opname[(int) VEC_NEW_EXPR], newtype, NOT_BUILT_IN);
      global_delete_fndecl
--- 6551,6558 ----
      if (flag_honor_std)
        pop_namespace ();
      newtype = build_exception_variant
!       (ptr_ftype_sizetype, add_exception_specifier (NULL_TREE, bad_alloc_type_node, -1));
!     deltype = build_exception_variant (void_ftype_ptr, empty_except_spec);
      auto_function (ansi_opname[(int) NEW_EXPR], newtype, NOT_BUILT_IN);
      auto_function (ansi_opname[(int) VEC_NEW_EXPR], newtype, NOT_BUILT_IN);
      global_delete_fndecl
Index: egcs/gcc/cp/parse.y
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/parse.y,v
retrieving revision 1.127
diff -c -3 -p -r1.127 parse.y
*** parse.y	1999/08/03 14:24:07	1.127
--- parse.y	1999/08/04 08:56:32
*************** exception_specification_opt:
*** 3685,3705 ****
  	| THROW '(' ansi_raise_identifiers  ')'  %prec EMPTY
  		{ $$ = $3; }
  	| THROW LEFT_RIGHT  %prec EMPTY
! 		{ $$ = build_decl_list (NULL_TREE, NULL_TREE); }
  	;
  
  ansi_raise_identifier:
  	  type_id
! 		{ $$ = build_decl_list (NULL_TREE, groktypename($1.t)); }
  	;
  
  ansi_raise_identifiers:
  	  ansi_raise_identifier
  	| ansi_raise_identifiers ',' ansi_raise_identifier
! 		{
! 		  TREE_CHAIN ($3) = $$;
! 		  $$ = $3;
! 		}
  	;
  
  conversion_declarator:
--- 3685,3706 ----
  	| THROW '(' ansi_raise_identifiers  ')'  %prec EMPTY
  		{ $$ = $3; }
  	| THROW LEFT_RIGHT  %prec EMPTY
! 		{ $$ = empty_except_spec; }
  	;
  
  ansi_raise_identifier:
  	  type_id
! 		{
! 		  check_for_new_type ("exception specifier", $1);
! 		  $$ = groktypename ($1.t);
! 		}
  	;
  
  ansi_raise_identifiers:
  	  ansi_raise_identifier
+ 		{ $$ = add_exception_specifier (NULL_TREE, $1, 1); }
  	| ansi_raise_identifiers ',' ansi_raise_identifier
! 		{ $$ = add_exception_specifier ($1, $3, 1); }
  	;
  
  conversion_declarator:
Index: egcs/gcc/cp/pt.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/pt.c,v
retrieving revision 1.318
diff -c -3 -p -r1.318 pt.c
*** pt.c	1999/08/03 01:37:47	1.318
--- pt.c	1999/08/04 08:56:36
*************** lookup_template_class (d1, arglist, in_d
*** 3937,3942 ****
--- 3937,3943 ----
  	  type_decl = build_decl (TYPE_DECL, DECL_NAME (template), t);
  	  SET_DECL_ARTIFICIAL (type_decl);
  	  DECL_CONTEXT (type_decl) = TYPE_CONTEXT (t);
+ 	  
  	  DECL_SOURCE_FILE (type_decl) 
  	    = DECL_SOURCE_FILE (TYPE_STUB_DECL (template_type));
  	  DECL_SOURCE_LINE (type_decl) 
*************** tsubst (t, args, complain, in_decl)
*** 6499,6508 ****
  	raises = TYPE_RAISES_EXCEPTIONS (t);
  	if (raises)
  	  {
! 	    raises = tsubst (raises, args, complain, in_decl);
! 	    if (raises == error_mark_node)
! 	      return raises;
! 	    fntype = build_exception_variant (fntype, raises);
  	  }
  	return fntype;
        }
--- 6500,6520 ----
  	raises = TYPE_RAISES_EXCEPTIONS (t);
  	if (raises)
  	  {
! 	    tree   list = NULL_TREE;
! 	    
! 	    if (! TREE_VALUE (raises))
! 	      list = raises;
! 	    else
! 	      for (; raises != NULL_TREE; raises = TREE_CHAIN (raises))
! 	        {
! 	          tree spec = TREE_VALUE (raises);
! 	          
! 	          spec = tsubst (spec, args, complain, in_decl);
! 	          if (spec == error_mark_node)
! 	            return spec;
! 	          list = add_exception_specifier (list, spec, complain);
! 	        }
! 	    fntype = build_exception_variant (fntype, list);
  	  }
  	return fntype;
        }
Index: egcs/gcc/cp/search.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/search.c,v
retrieving revision 1.113
diff -c -3 -p -r1.113 search.c
*** search.c	1999/07/27 18:15:20	1.113
--- search.c	1999/08/04 08:56:38
*************** static tree get_virtuals_named_this PROT
*** 117,122 ****
--- 117,123 ----
  static tree get_virtual_destructor PROTO((tree, void *));
  static tree tree_has_any_destructor_p PROTO((tree, void *));
  static int covariant_return_p PROTO((tree, tree));
+ static int check_final_overrider PROTO((tree, tree));
  static struct search_level *push_search_level
  	PROTO((struct stack_level *, struct obstack *));
  static struct search_level *pop_search_level
*************** covariant_return_p (brettype, drettype)
*** 1884,1889 ****
--- 1885,1947 ----
    return 1;
  }
  
+ /* Check that virtual overrider OVERRIDER is acceptable for base function
+    BASEFN. Issue diagnostic, and return zero, if unacceptable.  */
+ 
+ int
+ check_final_overrider (overrider, basefn)
+      tree overrider, basefn;
+ {
+   tree over_type = TREE_TYPE (overrider);
+   tree base_type = TREE_TYPE (basefn);
+   tree over_return = TREE_TYPE (over_type);
+   tree base_return = TREE_TYPE (base_type);
+   tree over_throw = TYPE_RAISES_EXCEPTIONS (over_type);
+   tree base_throw = TYPE_RAISES_EXCEPTIONS (base_type);
+   int i;
+   
+   if (same_type_p (base_return, over_return))
+     /* OK */;
+   else if ((i = covariant_return_p (base_return, over_return)))
+     {
+       if (i == 2)
+ 	sorry ("adjusting pointers for covariant returns");
+ 
+       if (pedantic && i == -1)
+ 	{
+ 	  cp_pedwarn_at ("invalid covariant return type for `virtual %#D'", overrider);
+ 	  cp_pedwarn_at ("  overriding `virtual %#D' (must be pointer or reference to class)", basefn);
+ 	}
+     }
+   else if (IS_AGGR_TYPE_2 (base_return, over_return)
+ 	   && same_or_base_type_p (base_return, over_return))
+     {
+       cp_error_at ("invalid covariant return type for `virtual %#D'", overrider);
+       cp_error_at ("  overriding `virtual %#D' (must use pointer or reference)", basefn);
+       return 0;
+     }
+   else if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)) == NULL_TREE)
+     {
+       cp_error_at ("conflicting return type specified for `virtual %#D'", overrider);
+       cp_error_at ("  overriding `virtual %#D'", basefn);
+       SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider),
+                                   DECL_CLASS_CONTEXT (overrider));
+       return 0;
+     }
+   
+   /* Check throw specifier is subset.  */
+   /* XXX At the moment, punt on an overriding artificial function. We
+      don't generate its exception specifier, so can't check it properly.  */
+   if (! DECL_ARTIFICIAL (overrider)
+       && !comp_except_specs (base_throw, over_throw, 0))
+     {
+       cp_error_at ("looser throw specifier for `virtual %#F'", overrider);
+       cp_error_at ("  overriding `virtual %#F'", basefn);
+       return 0;
+     }
+   return 1;
+ }
+ 
  /* Given a class type TYPE, and a function decl FNDECL, look for a
     virtual function in TYPE's hierarchy which FNDECL could match as a
     virtual function.  It doesn't matter which one we find.
*************** get_matching_virtual (binfo, fndecl, dto
*** 1897,1903 ****
       int dtorp;
  {
    tree tmp = NULL_TREE;
-   int i;
  
    if (TREE_CODE (fndecl) == TEMPLATE_DECL)
      /* In [temp.mem] we have:
--- 1955,1960 ----
*************** get_matching_virtual (binfo, fndecl, dto
*** 1914,1922 ****
    else
      {
        tree drettype, dtypes, btypes, instptr_type;
-       tree basetype = DECL_CLASS_CONTEXT (fndecl);
        tree baselink, best = NULL_TREE;
-       tree name = DECL_ASSEMBLER_NAME (fndecl);
        tree declarator = DECL_NAME (fndecl);
        if (IDENTIFIER_VIRTUAL_P (declarator) == 0)
  	return NULL_TREE;
--- 1971,1977 ----
*************** get_matching_virtual (binfo, fndecl, dto
*** 1958,1990 ****
  		   == TYPE_QUALS (instptr_type))
  		  && compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes)))
  		{
! 		  tree brettype = TREE_TYPE (TREE_TYPE (tmp));
! 		  if (same_type_p (brettype, drettype))
! 		    /* OK */;
! 		  else if ((i = covariant_return_p (brettype, drettype)))
! 		    {
! 		      if (i == 2)
! 			sorry ("adjusting pointers for covariant returns");
! 
! 		      if (pedantic && i == -1)
! 			{
! 			  cp_pedwarn_at ("invalid covariant return type for `%#D' (must be pointer or reference to class)", fndecl);
! 			  cp_pedwarn_at ("  overriding `%#D'", tmp);
! 			}
! 		    }
! 		  else if (IS_AGGR_TYPE_2 (brettype, drettype)
! 			   && same_or_base_type_p (brettype, drettype))
! 		    {
! 		      error ("invalid covariant return type (must use pointer or reference)");
! 		      cp_error_at ("  overriding `%#D'", tmp);
! 		      cp_error_at ("  with `%#D'", fndecl);
! 		    }
! 		  else if (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE)
! 		    {
! 		      cp_error_at ("conflicting return type specified for virtual function `%#D'", fndecl);
! 		      cp_error_at ("  overriding definition as `%#D'", tmp);
! 		      SET_IDENTIFIER_ERROR_LOCUS (name, basetype);
! 		    }
  
  		  /* FNDECL overrides this function.  We continue to
  		     check all the other functions in order to catch
--- 2013,2019 ----
  		   == TYPE_QUALS (instptr_type))
  		  && compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes)))
  		{
! 	          check_final_overrider (fndecl, tmp);
  
  		  /* FNDECL overrides this function.  We continue to
  		     check all the other functions in order to catch
Index: egcs/gcc/cp/tree.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/tree.c,v
retrieving revision 1.121
diff -c -3 -p -r1.121 tree.c
*** tree.c	1999/08/03 15:04:49	1.121
--- tree.c	1999/08/04 08:56:40
*************** build_exception_variant (type, raises)
*** 1484,1508 ****
    int type_quals = TYPE_QUALS (type);
  
    for (; v; v = TYPE_NEXT_VARIANT (v))
!     {
!       tree t;
!       tree u;
! 
!       if (TYPE_QUALS (v) != type_quals)
! 	continue;
! 
!       for (t = TYPE_RAISES_EXCEPTIONS (v), u = raises;
! 	   t != NULL_TREE && u != NULL_TREE;
! 	   t = TREE_CHAIN (t), u = TREE_CHAIN (u))
! 	if (((TREE_VALUE (t) != NULL_TREE) 
! 	     != (TREE_VALUE (u) != NULL_TREE))
! 	    || !same_type_p (TREE_VALUE (t), TREE_VALUE (u)))
! 	  break;
! 
!       if (!t && !u)
! 	/* There's a memory leak here; RAISES is not freed.  */
! 	return v;
!     }
  
    /* Need to build a new variant.  */
    v = build_type_copy (type);
--- 1484,1492 ----
    int type_quals = TYPE_QUALS (type);
  
    for (; v; v = TYPE_NEXT_VARIANT (v))
!     if (TYPE_QUALS (v) == type_quals
!         && comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (v), 1))
!       return v;
  
    /* Need to build a new variant.  */
    v = build_type_copy (type);
Index: egcs/gcc/cp/typeck.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/typeck.c,v
retrieving revision 1.182
diff -c -3 -p -r1.182 typeck.c
*** typeck.c	1999/08/03 00:58:19	1.182
--- typeck.c	1999/08/04 08:56:45
*************** static int comp_target_parms PROTO((tree
*** 48,53 ****
--- 48,54 ----
  static int comp_ptr_ttypes_real PROTO((tree, tree, int));
  static int comp_ptr_ttypes_const PROTO((tree, tree));
  static int comp_ptr_ttypes_reinterpret PROTO((tree, tree));
+ static int comp_except_types PROTO((tree, tree, int));
  static int comp_array_types PROTO((int (*) (tree, tree, int), tree,
  				   tree, int));
  static tree common_base_type PROTO((tree, tree));
*************** common_type (t1, t2)
*** 853,865 ****
      }
  }
  
! /* Return 1 if TYPE1 and TYPE2 raise the same exceptions.  */
  
  int
! compexcepttypes (t1, t2)
       tree t1, t2;
  {
!   return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2);
  }
  
  /* Compare the array types T1 and T2, using CMP as the type comparison
--- 854,955 ----
      }
  }
  
! /* Compare two exception specifier types for exactness or subsetness, if
!    allowed. Returns 0 for mismatch, 1 for same, 2 if B is allowed by A.
!  
!    [except.spec] "If a class X ... objects of class X or any class publicly
!    and unambigously derrived from X. Similarly, if a pointer type Y * ...
!    exceptions of type Y * or that are pointers to any type publicly and
!    unambigously derrived from Y. Otherwise a function only allows exceptions
!    that have the same type ..."
!    This does not mention cv qualifiers and is different to what throw
!    [except.throw] and catch [except.catch] will do. They will ignore the
!    top level cv qualifiers, and allow qualifiers in the pointer to class
!    example.
!    
!    We implement the letter of the standard.  */
! 
! static int
! comp_except_types (a, b, exact)
!      tree a, b;
!      int exact;
! {
!   if (same_type_p (a, b))
!     return 1;
!   else if (!exact)
!     {
!       if (CP_TYPE_QUALS (a) || CP_TYPE_QUALS (b))
!         return 0;
!       
!       if (TREE_CODE (a) == POINTER_TYPE
!           && TREE_CODE (b) == POINTER_TYPE)
!         {
!           a = TREE_TYPE (a);
!           b = TREE_TYPE (b);
!           if (CP_TYPE_QUALS (a) || CP_TYPE_QUALS (b))
!             return 0;
!         }
!       
!       if (TREE_CODE (a) != RECORD_TYPE
!           || TREE_CODE (b) != RECORD_TYPE)
!         return 0;
!       
!       if (ACCESSIBLY_UNIQUELY_DERIVED_P (a, b))
!         return 2;
!     }
!   return 0;
! }
! 
! /* Return 1 if TYPE1 and TYPE2 are equivalent exception specifiers.
!    If EXACT is 0, T2 can be a subset of T1 (according to 15.4/7),
!    otherwise it must be exact. Exception lists are unordered, but
!    we've already filtered out duplicates. Most lists will be in order,
!    we should try to make use of that.  */
  
  int
! comp_except_specs (t1, t2, exact)
       tree t1, t2;
+      int exact;
  {
!   tree probe;
!   tree base;
!   int  length = 0;
! 
!   if (t1 == t2)
!     return 1;
!   
!   if (t1 == NULL_TREE)              /* T1 is ... */
!     return t2 == NULL_TREE || !exact;
!   if (!TREE_VALUE (t1)) /* t1 is EMPTY */
!     return t2 != NULL_TREE && !TREE_VALUE (t2);
!   if (t2 == NULL_TREE)              /* T2 is ... */
!     return 0;
!   if (TREE_VALUE(t1) && !TREE_VALUE (t2)) /* T2 is EMPTY, T1 is not */
!     return !exact;
!   
!   /* Neither set is ... or EMPTY, make sure each part of T2 is in T1.
!      Count how many we find, to determine exactness. For exact matching and
!      ordered T1, T2, this is an O(n) operation, otherwise its worst case is
!      O(nm).  */
!   for (base = t1; t2 != NULL_TREE; t2 = TREE_CHAIN (t2))
!     {
!       for (probe = base; probe != NULL_TREE; probe = TREE_CHAIN (probe))
!         {
!           tree a = TREE_VALUE (probe);
!           tree b = TREE_VALUE (t2);
!           
!           if (comp_except_types (a, b, exact))
!             {
!               if (probe == base && exact)
!                 base = TREE_CHAIN (probe);
!               length++;
!               break;
!             }
!         }
!       if (probe == NULL_TREE)
!         return 0;
!     }
!   return !exact || base == NULL_TREE || length == list_length (t1);
  }
  
  /* Compare the array types T1 and T2, using CMP as the type comparison
*************** comptypes (t1, t2, strict)
*** 1031,1037 ****
        break;
  
      case METHOD_TYPE:
!       if (! compexcepttypes (t1, t2))
  	return 0;
  
        /* This case is anti-symmetrical!
--- 1121,1128 ----
        break;
  
      case METHOD_TYPE:
!       if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
!                              TYPE_RAISES_EXCEPTIONS (t2), 1))
  	return 0;
  
        /* This case is anti-symmetrical!
*************** comptypes (t1, t2, strict)
*** 1058,1064 ****
        break;
  
      case FUNCTION_TYPE:
!       if (! compexcepttypes (t1, t2))
  	return 0;
  
        val = ((TREE_TYPE (t1) == TREE_TYPE (t2)
--- 1149,1156 ----
        break;
  
      case FUNCTION_TYPE:
!       if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
!                              TYPE_RAISES_EXCEPTIONS (t2), 1))
  	return 0;
  
        val = ((TREE_TYPE (t1) == TREE_TYPE (t2)
*************** build_component_ref (datum, component, b
*** 2175,2180 ****
--- 2267,2275 ----
        tree name = component;
        if (TREE_CODE (component) == VAR_DECL)
  	name = DECL_NAME (component);
+       if (TREE_CODE (component) == NAMESPACE_DECL)
+         /* Source is in error, but produce a sensible diagnostic.  */
+         name = DECL_NAME (component);
        if (basetype_path == NULL_TREE)
  	basetype_path = TYPE_BINFO (basetype);
        field = lookup_field (basetype_path, name,
Index: egcs/gcc/cp/typeck2.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/typeck2.c,v
retrieving revision 1.58
diff -c -3 -p -r1.58 typeck2.c
*** typeck2.c	1999/08/03 00:13:45	1.58
--- typeck2.c	1999/08/04 08:56:47
*************** check_for_new_type (string, inptree)
*** 1520,1522 ****
--- 1520,1575 ----
        && (pedantic || strcmp (string, "cast") != 0))
      pedwarn ("ANSI C++ forbids defining types within %s",string);
  }
+ 
+ /* Add new exception specifier SPEC, to the LIST we currently have.
+    If it's already in LIST then do nothing.
+    Moan if it's bad and we're allowed to. COMPLAIN < 0 means we
+    know what we're doing.  */
+ 
+ tree
+ add_exception_specifier (list, spec, complain)
+      tree list, spec;
+      int complain;
+ {
+   int ok;
+   tree core = spec;
+   int is_ptr;
+   
+   if (spec == error_mark_node)
+     return list;
+   
+   my_friendly_assert (spec && (!list || TREE_VALUE (list)), 19990317);
+   
+   /* [except.spec] 1, type in an exception specifier shall not be
+      incomplete, or pointer or ref to incomplete other than pointer
+      to cv void.  */
+   is_ptr = TREE_CODE (core) == POINTER_TYPE;
+   if (is_ptr || TREE_CODE (core) == REFERENCE_TYPE)
+     core = TREE_TYPE (core);
+   if (complain < 0)
+     ok = 1;
+   else if (TYPE_MAIN_VARIANT (core) == void_type_node)
+     ok = is_ptr;
+   else if (TREE_CODE (core) == TEMPLATE_TYPE_PARM)
+     ok = 1;
+   else
+     ok = TYPE_SIZE (core) != NULL_TREE;
+   
+   if (ok)
+     {
+       tree probe;
+       
+       for (probe = list; probe; probe = TREE_CHAIN (probe))
+         if (same_type_p (TREE_VALUE (probe), spec))
+           break;
+       if (!probe)
+         {
+           spec = build_decl_list (NULL_TREE, spec);
+           TREE_CHAIN (spec) = list;
+           list = spec;
+         }
+     }
+   else if (complain)
+     incomplete_type_error (NULL_TREE, core);
+   return list;
+ }
Index: egcs/gcc/cp/class.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/cp/class.c,v
retrieving revision 1.172
diff -c -3 -p -r1.172 class.c
*** class.c	1999/08/03 15:04:49	1.172
--- class.c	1999/08/04 08:56:52
*************** check_for_override (decl, ctype)
*** 2977,2985 ****
  		 path to its virtual baseclass.  */
  	      if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)
  		{
! 		  cp_error_at ("method `%D' may not be declared static",
! 			       decl);
! 		  cp_error_at ("(since `%D' declared virtual in base class.)",
  			       tmp);
  		  break;
  		}
--- 2977,2984 ----
  		 path to its virtual baseclass.  */
  	      if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)
  		{
! 		  cp_error_at ("`static %#D' cannot be declared", decl);
! 		  cp_error_at ("  since `virtual %#D' declared in base class",
  			       tmp);
  		  break;
  		}
Index: egcs/gcc/testsuite/ChangeLog
===================================================================
RCS file: /cvs/egcs/egcs/gcc/testsuite/ChangeLog,v
retrieving revision 1.305
diff -c -3 -p -r1.305 ChangeLog
*** ChangeLog	1999/08/04 07:18:41	1.305
--- ChangeLog	1999/08/04 09:02:41
***************
*** 1,3 ****
--- 1,7 ----
+ 1999-08-04  Nathan Sidwell  <nathan@acm.org>
+ 
+ 	* g++.old-deja/g++.eh/spec6.C: Add more tests. Remove XFAILS.
+ 
  Wed Aug  4 01:17:17 1999  Jeffrey A Law  (law@cygnus.com)
  
  	* gcc.c-torture/execute/990804-1.c: New test.
Index: egcs/gcc/testsuite/g++.old-deja/g++.eh/spec6.C
===================================================================
RCS file: /cvs/egcs/egcs/gcc/testsuite/g++.old-deja/g++.eh/spec6.C,v
retrieving revision 1.2
diff -c -3 -p -r1.2 spec6.C
*** spec6.C	1999/02/23 09:11:19	1.2
--- spec6.C	1999/08/04 09:02:41
***************
*** 7,46 ****
  
  // [except.spec] 1, a type in an exception specifier shall not be incomplete,
  // or pointer or ref to incomplete
! struct X; // ERROR - forward declaration - XFAIL
! void fn1() throw(X);  // ERROR - incomplete type - XFAIL
! void fn2() throw(X *); // ERROR - incomplete type - XFAIL
! void fn3() throw(X &); // ERROR - incomplete type - XFAIL
! void fn4() throw(void); // ERROR - incomplete type - XFAIL
  // except for cv pointer to void
! void fn5() throw(void *);
  
  // [except.spec] 2, exception specifiers must be the same set of types (but
  // can be reordered)
! void fn() throw(int, char);   // gets bogus error - XFAIL
! void fn() throw(char, int){}  // gets bogus error - ordering is irrelevant - XFAIL
  
  // [except.spec] 3, virtual function overriders shall throw a subset of the
  // overridden function
  struct E {};
  struct F : public E {};
  struct A
  {
!   virtual void foo() throw();
    virtual void baz() throw(double, int);
    virtual void bar();
    virtual void qux() throw(E);
!   virtual void quux() throw(F);
  };
  
  struct B : A
  {
!   virtual void foo() throw(int);  // ERROR - not in base function - XFAIL
!   virtual void baz() throw(double);
!   virtual void bar(int) throw(int);
!   virtual void qux() throw(F);
!   virtual void quux() throw(E);   // ERROR - not in base function - XFAIL
  };
  
  // [except.spec] 5, types shall not be defined in exception specifiers
! void fn6() throw(struct Z {}); // ERROR - types shall not be defined - XFAIL
--- 7,142 ----
  
  // [except.spec] 1, a type in an exception specifier shall not be incomplete,
  // or pointer or ref to incomplete
! struct X;                         // ERROR - forward declaration.*
! void fn1() throw(X);              // ERROR - invalid use of undefined type
! void fn2() throw(X *);            // ERROR - invalid use of undefined type
! void fn3() throw(X &);            // ERROR - invalid use of undefined tyoe
! void fn4() throw(void);           // ERROR - invalid use of void expression
! void fn5() throw(void &);         // ERROR - invalid type // ERROR - invalid use of void
  // except for cv pointer to void
! void fn6() throw(void *);         // ok -- pointer to void
! void fn7() throw(void const *);   // ok -- pointer to cv void
  
+ template<class T> void fny() throw(T);  // ok (so far)
+ template<> void fny<int>() throw(int);  // ok
+ template<> void fny<void>() throw(void); // ERROR - invalid use of void
+ 
+ template<class T> void fnx(T *) throw(T){}  // ERROR - invalid use of void expression
+ void fx()
+ {
+   fnx((int *)0);
+   fnx((void *)0);
+ }
+ 
  // [except.spec] 2, exception specifiers must be the same set of types (but
  // can be reordered)
! void baz1() throw(int, char);
! void baz1() throw(char, int){}       // reordering is ok
! 
! void baz2() throw(int, char);
! void baz2() throw(int, char, int){}  // duplicates are ignored
! 
! typedef int Int;
! void baz3() throw(int, char);
! void baz3() throw(Int, char){}       // typedefs are the same type ...
! 
! void baz4() throw(int, Int, char);   // ... so this is a duplicate
! void baz4() throw(Int, char){}
! 
! void fna() throw(int, char);  // ERROR - to previous declaration
! void fna() throw(int const, char);  // ERROR - declaration  different exceptions // ERROR - to previous declaration
! void fna() throw(int){}       // ERROR - declaration  different exceptions
! 
! void fnb() throw(int, char);  // ERROR - to previous declaration
! void fnb() throw(char){}      // ERROR - declaration  different exceptions
! 
! void fnc() throw(int, char);  // ERROR - to previous declaration
! void fnc() throw(char, int, float){}  // ERROR - declaration  different exceptions
! 
! void fnd() throw();           // ERROR - to previous declaration
! void fnd() throw(char){}      // ERROR - declaration  different exceptions
! 
! void fne() throw(char);       // ERROR - to previous declaration
! void fne() throw(){}          // ERROR - declaration  different exceptions
! 
! void fnf();                   // ERROR - to previous declaration
! void fnf() throw(char){}      // ERROR - declaration  different exceptions
! 
! void fng() throw(char);       // ERROR - to previous declaration
! void fng(){}                  // ERROR - declaration  different exceptions
  
+ void fnh() throw(int, char);  // ERROR - to previous declaration
+ void fnh() throw(int, float){}   // ERROR - declaration  different exceptions
+ 
+ void fni() throw(int, char);  // ERROR - to previous declaration
+ void fni() throw(float, char){}  // ERROR - declaration  different exceptions
+ 
  // [except.spec] 3, virtual function overriders shall throw a subset of the
  // overridden function
  struct E {};
  struct F : public E {};
+ struct F1 : public E {};
+ struct G : public F, F1 {};
+ struct H : private E {};
  struct A
  {
!   virtual void foo() throw();             // ERROR - overriding 
    virtual void baz() throw(double, int);
    virtual void bar();
    virtual void qux() throw(E);
!   virtual void qux(int) throw(E const *); // ERROR - overriding (pedantically)
!   virtual void quux() throw(F);           // ERROR - overriding 
!   virtual void quux(int) throw(F *);      // ERROR - overriding 
!   virtual void wibble() throw(E);         // ERROR - overriding 
!   virtual void wobble() throw(E *);       // ERROR - overriding 
!   virtual void wobble(int) throw(E *);    // ERROR - overriding 
!   virtual void wabble(int) throw(E *);
!   virtual void wubble(int) throw(E *, H *);
!   virtual ~A() throw();                   // ERROR - overriding XFAIL
  };
  
  struct B : A
+ {
+   virtual void foo() throw(int);          // ERROR - looser throw - A::foo
+   virtual void baz() throw(double);       // ok subset
+   virtual void bar(int) throw(int);       // ok not overriding
+   virtual void qux() throw(F);            // ok subset
+   virtual void qux(int) throw(F *);       // ERROR - looser (pedantically)
+   virtual void quux() throw(E);           // ERROR - looser throw - A::quux()
+   virtual void quux(int) throw(E *);      // ERROR - looser throw - A::quux(int)
+   virtual void wibble() throw(E *);       // ERROR - looser throw - A::wibble
+   virtual void wobble() throw(G *);       // ERROR - looser throw - A::wobble()
+   virtual void wobble(int) throw(H *);    // ERROR - looser throw - A::wobble(int)
+   virtual void wubble(int) throw(H *);    // ok
+   virtual void wabble(int) throw(F1 *, F *);    // ok
+ };
+ 
+ struct A1
+ {
+   virtual void foo() throw(int);
+   virtual void bar() throw();       // ERROR - overriding 
+   virtual ~A1() throw(int);
+ };
+ 
+ struct B1 : A
+ {
+ };
+ 
+ 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
+ 
+ struct D : A, A1
  {
!   // The xfail here is because we don't have the check in the right place to
!   // catch dtor failings.
!   virtual ~D() throw(int); // ERROR - looser throw - A::~A() - XFAIL
  };
  
  // [except.spec] 5, types shall not be defined in exception specifiers
! void fn8() throw(struct Z {}); // ERROR - ANSI C++ forbids 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]