Commit 03378143 by Nathan Sidwell Committed by Nathan Sidwell

Implement exceptions specifiers for implicit member functions.

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
parent fc5769d9
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> 2001-01-03 Jason Merrill <jason@redhat.com>
* init.c (build_default_init): New fn. * init.c (build_default_init): New fn.
......
...@@ -4532,6 +4532,7 @@ extern tree build_m_component_ref PARAMS ((tree, tree)); ...@@ -4532,6 +4532,7 @@ extern tree build_m_component_ref PARAMS ((tree, tree));
extern tree build_functional_cast PARAMS ((tree, tree)); extern tree build_functional_cast PARAMS ((tree, tree));
extern void check_for_new_type PARAMS ((const char *, flagged_type_tree)); extern void check_for_new_type PARAMS ((const char *, flagged_type_tree));
extern tree add_exception_specifier PARAMS ((tree, tree, int)); extern tree add_exception_specifier PARAMS ((tree, tree, int));
extern tree merge_exception_specifiers PARAMS ((tree, tree));
/* in xref.c */ /* in xref.c */
extern void GNU_xref_begin PARAMS ((const char *)); extern void GNU_xref_begin PARAMS ((const char *));
......
...@@ -98,6 +98,10 @@ static int is_back_referenceable_type PARAMS ((tree)); ...@@ -98,6 +98,10 @@ static int is_back_referenceable_type PARAMS ((tree));
static int check_btype PARAMS ((tree)); static int check_btype PARAMS ((tree));
static void build_mangled_name_for_type PARAMS ((tree)); static void build_mangled_name_for_type PARAMS ((tree));
static void build_mangled_name_for_type_with_Gcode PARAMS ((tree, int)); 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_INIT() (scratch_firstobj ? (obstack_free (&scratch_obstack, scratch_firstobj), 0) : 0)
# define OB_PUTC(C) (obstack_1grow (&scratch_obstack, (C))) # define OB_PUTC(C) (obstack_1grow (&scratch_obstack, (C)))
...@@ -2585,6 +2589,163 @@ synthesize_method (fndecl) ...@@ -2585,6 +2589,163 @@ synthesize_method (fndecl)
pop_function_context_from (context); 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 /* Implicitly declare the special function indicated by KIND, as a
member of TYPE. For copy constructors and assignment operators, member of TYPE. For copy constructors and assignment operators,
CONST_P indicates whether these functions should take a const CONST_P indicates whether these functions should take a const
...@@ -2598,24 +2759,30 @@ implicitly_declare_fn (kind, type, const_p) ...@@ -2598,24 +2759,30 @@ implicitly_declare_fn (kind, type, const_p)
{ {
tree declspecs = NULL_TREE; tree declspecs = NULL_TREE;
tree fn, args = NULL_TREE; tree fn, args = NULL_TREE;
tree raises = empty_except_spec;
tree argtype; tree argtype;
int retref = 0; int retref = 0;
tree name = constructor_name (TYPE_IDENTIFIER (type)); tree name = constructor_name (TYPE_IDENTIFIER (type));
switch (kind) switch (kind)
{ {
/* Destructors. */
case sfk_destructor: case sfk_destructor:
/* Destructor. */
name = build_parse_node (BIT_NOT_EXPR, name); name = build_parse_node (BIT_NOT_EXPR, name);
args = void_list_node; args = void_list_node;
raises = synthesize_exception_spec (type, &locate_dtor, 0);
break; break;
case sfk_constructor: case sfk_constructor:
/* Default constructor. */ /* Default constructor. */
args = void_list_node; args = void_list_node;
raises = synthesize_exception_spec (type, &locate_ctor, 0);
break; break;
case sfk_copy_constructor: case sfk_copy_constructor:
{
struct copy_data data;
if (const_p) if (const_p)
type = build_qualified_type (type, TYPE_QUAL_CONST); type = build_qualified_type (type, TYPE_QUAL_CONST);
argtype = build_reference_type (type); argtype = build_reference_type (type);
...@@ -2623,9 +2790,15 @@ implicitly_declare_fn (kind, type, const_p) ...@@ -2623,9 +2790,15 @@ implicitly_declare_fn (kind, type, const_p)
build_tree_list (hash_tree_chain (argtype, NULL_TREE), build_tree_list (hash_tree_chain (argtype, NULL_TREE),
get_identifier ("_ctor_arg")), get_identifier ("_ctor_arg")),
void_list_node); void_list_node);
data.name = NULL;
data.quals = const_p ? TYPE_QUAL_CONST : 0;
raises = synthesize_exception_spec (type, &locate_copy, &data);
break; break;
}
case sfk_assignment_operator: case sfk_assignment_operator:
{
struct copy_data data;
retref = 1; retref = 1;
declspecs = build_tree_list (NULL_TREE, type); declspecs = build_tree_list (NULL_TREE, type);
...@@ -2639,8 +2812,11 @@ implicitly_declare_fn (kind, type, const_p) ...@@ -2639,8 +2812,11 @@ implicitly_declare_fn (kind, type, const_p)
build_tree_list (hash_tree_chain (argtype, NULL_TREE), build_tree_list (hash_tree_chain (argtype, NULL_TREE),
get_identifier ("_ctor_arg")), get_identifier ("_ctor_arg")),
void_list_node); void_list_node);
data.name = name;
data.quals = const_p ? TYPE_QUAL_CONST : 0;
raises = synthesize_exception_spec (type, &locate_copy, &data);
break; break;
}
default: default:
my_friendly_abort (59); my_friendly_abort (59);
} }
...@@ -2648,7 +2824,7 @@ implicitly_declare_fn (kind, type, const_p) ...@@ -2648,7 +2824,7 @@ implicitly_declare_fn (kind, type, const_p)
TREE_PARMLIST (args) = 1; 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) if (retref)
declarator = build_parse_node (ADDR_EXPR, declarator); declarator = build_parse_node (ADDR_EXPR, declarator);
......
...@@ -1964,10 +1964,7 @@ check_final_overrider (overrider, basefn) ...@@ -1964,10 +1964,7 @@ check_final_overrider (overrider, basefn)
} }
/* Check throw specifier is subset. */ /* Check throw specifier is subset. */
/* XXX At the moment, punt with artificial functions. We if (!comp_except_specs (base_throw, over_throw, 0))
don't generate their exception specifiers, so can't check properly. */
if (! DECL_ARTIFICIAL (overrider)
&& !comp_except_specs (base_throw, over_throw, 0))
{ {
cp_error_at ("looser throw specifier for `%#F'", overrider); cp_error_at ("looser throw specifier for `%#F'", overrider);
cp_error_at (" overriding `%#F'", basefn); cp_error_at (" overriding `%#F'", basefn);
......
...@@ -1296,3 +1296,39 @@ add_exception_specifier (list, spec, complain) ...@@ -1296,3 +1296,39 @@ add_exception_specifier (list, spec, complain)
incomplete_type_error (NULL_TREE, core); incomplete_type_error (NULL_TREE, core);
return list; 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;
}
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> 2001-01-02 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* gcc.c-torture/compile/20010102-1.c: New test. * gcc.c-torture/compile/20010102-1.c: New test.
......
...@@ -126,10 +126,7 @@ struct C : A, A1 ...@@ -126,10 +126,7 @@ struct C : A, A1
{ {
virtual void foo() throw(int); // ERROR - looser throw - A::foo virtual void foo() throw(int); // ERROR - looser throw - A::foo
virtual void bar() throw(int); // ERROR - looser throw - A1::bar virtual void bar() throw(int); // ERROR - looser throw - A1::bar
// The xfail is because we don't build exception specifiers for implicit }; // ERROR - looser throw - A::~A()
// 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 struct D : A, A1
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment