cp-tree.h (empty_except_spec): New global var.

* 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.

From-SVN: r28494
This commit is contained in:
Nathan Sidwell 1999-08-04 09:07:51 +00:00 committed by Nathan Sidwell
parent bc3c01c507
commit 4cc1d46201
10 changed files with 284 additions and 76 deletions

View File

@ -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.

View File

@ -2977,9 +2977,8 @@ check_for_override (decl, ctype)
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.)",
cp_error_at ("`static %#D' cannot be declared", decl);
cp_error_at (" since `virtual %#D' declared in base class",
tmp);
break;
}

View File

@ -2288,6 +2288,7 @@ extern tree delta2_identifier;
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;
@ -3533,7 +3534,7 @@ extern int fntype_p PROTO((tree));
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 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));
@ -3618,6 +3619,7 @@ extern tree build_functional_cast PROTO((tree, tree));
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 *));

View File

@ -336,6 +336,9 @@ tree pfn_identifier, index_identifier, delta_identifier, delta2_identifier;
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;
@ -3478,11 +3481,12 @@ duplicate_decls (newdecl, olddecl)
if ((pedantic || ! DECL_IN_SYSTEM_HEADER (olddecl))
&& DECL_SOURCE_LINE (olddecl) != 0
&& flag_exceptions
&& ! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl)))
&& !comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)),
TYPE_RAISES_EXCEPTIONS (TREE_TYPE (olddecl)), 1))
{
cp_pedwarn ("declaration of `%D' throws different exceptions",
cp_error ("declaration of `%F' throws different exceptions",
newdecl);
cp_pedwarn_at ("previous declaration here", olddecl);
cp_error_at ("to previous declaration `%F'", olddecl);
}
}
TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
@ -6361,6 +6365,7 @@ init_decl_processing ()
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
@ -6400,8 +6405,7 @@ init_decl_processing ()
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));
= build_exception_variant (void_ftype_ptr, empty_except_spec);
/* C++ extensions */
@ -6547,9 +6551,8 @@ init_decl_processing ()
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));
(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

View File

@ -3685,21 +3685,22 @@ exception_specification_opt:
| THROW '(' ansi_raise_identifiers ')' %prec EMPTY
{ $$ = $3; }
| THROW LEFT_RIGHT %prec EMPTY
{ $$ = build_decl_list (NULL_TREE, NULL_TREE); }
{ $$ = empty_except_spec; }
;
ansi_raise_identifier:
type_id
{ $$ = build_decl_list (NULL_TREE, groktypename($1.t)); }
{
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
{
TREE_CHAIN ($3) = $$;
$$ = $3;
}
{ $$ = add_exception_specifier ($1, $3, 1); }
;
conversion_declarator:

View File

@ -3937,6 +3937,7 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope)
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)
@ -6499,10 +6500,21 @@ tsubst (t, args, complain, in_decl)
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);
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;
}

View File

@ -117,6 +117,7 @@ static tree get_virtuals_named_this PROTO((tree, tree));
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
@ -1884,6 +1885,63 @@ covariant_return_p (brettype, drettype)
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.
@ -1897,7 +1955,6 @@ get_matching_virtual (binfo, fndecl, dtorp)
int dtorp;
{
tree tmp = NULL_TREE;
int i;
if (TREE_CODE (fndecl) == TEMPLATE_DECL)
/* In [temp.mem] we have:
@ -1914,9 +1971,7 @@ get_matching_virtual (binfo, fndecl, dtorp)
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;
@ -1958,33 +2013,7 @@ get_matching_virtual (binfo, fndecl, dtorp)
== 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);
}
check_final_overrider (fndecl, tmp);
/* FNDECL overrides this function. We continue to
check all the other functions in order to catch

View File

@ -1484,25 +1484,9 @@ build_exception_variant (type, raises)
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;
}
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);

View File

@ -48,6 +48,7 @@ static int comp_target_parms PROTO((tree, tree, int));
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));
@ -853,13 +854,102 @@ common_type (t1, t2)
}
}
/* Return 1 if TYPE1 and TYPE2 raise the same exceptions. */
/* 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
compexcepttypes (t1, t2)
comp_except_specs (t1, t2, exact)
tree t1, t2;
int exact;
{
return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2);
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
@ -1031,7 +1121,8 @@ comptypes (t1, t2, strict)
break;
case METHOD_TYPE:
if (! compexcepttypes (t1, t2))
if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
TYPE_RAISES_EXCEPTIONS (t2), 1))
return 0;
/* This case is anti-symmetrical!
@ -1058,7 +1149,8 @@ comptypes (t1, t2, strict)
break;
case FUNCTION_TYPE:
if (! compexcepttypes (t1, t2))
if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
TYPE_RAISES_EXCEPTIONS (t2), 1))
return 0;
val = ((TREE_TYPE (t1) == TREE_TYPE (t2)
@ -2175,6 +2267,9 @@ build_component_ref (datum, component, basetype_path, protect)
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,

View File

@ -1520,3 +1520,56 @@ check_for_new_type (string, inptree)
&& (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;
}