This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: Exception specifiers
- To: egcs-patches at egcs dot cygnus dot com
- Subject: C++ PATCH: Exception specifiers
- From: Nathan Sidwell <nathan at acm dot org>
- Date: Wed, 04 Aug 1999 10:29:11 +0100
- Organization: University of Bristol
- Reply-To: nathan at compsci dot bristol dot ac dot uk
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