aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2001-01-03 14:39:10 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2001-01-03 14:39:10 +0000
commit03378143aca4cb4276e6fb1d2f790ea58bdcaa86 (patch)
treeacdad70455870f766fb7e96793203aa55d4c5eb1 /gcc
parentfc5769d98c11b8e31c6e800cc90d751dd1ab9fc8 (diff)
downloadgcc-03378143aca4cb4276e6fb1d2f790ea58bdcaa86.zip
gcc-03378143aca4cb4276e6fb1d2f790ea58bdcaa86.tar.gz
gcc-03378143aca4cb4276e6fb1d2f790ea58bdcaa86.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/method.c184
-rw-r--r--gcc/cp/search.c5
-rw-r--r--gcc/cp/typeck2.c36
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.old-deja/g++.eh/spec6.C5
7 files changed, 234 insertions, 12 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 4b81b72..bee60d6 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,14 @@
+2001-01-03 Nathan Sidwell <nathan@codesourcery.com>
+
+ Implement exceptions specifiers for implicit member functions.
+ * cp-tree.h (merge_exceptions_specifiers): Declare new function.
+ * method.c (synthesize_exception_spec): New function.
+ (locate_dtor, locate_ctor, locate_copy): New functions.
+ (implicitly_declare_fn): Generate the exception spec too.
+ * search.c (check_final_overrider): Check artificial functions
+ too.
+ * typeck2.c (merge_exception_specifiers): New function.
+
2001-01-03 Jason Merrill <jason@redhat.com>
* init.c (build_default_init): New fn.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8d5c512..0531865 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4532,6 +4532,7 @@ extern tree build_m_component_ref PARAMS ((tree, tree));
extern tree build_functional_cast PARAMS ((tree, tree));
extern void check_for_new_type PARAMS ((const char *, flagged_type_tree));
extern tree add_exception_specifier PARAMS ((tree, tree, int));
+extern tree merge_exception_specifiers PARAMS ((tree, tree));
/* in xref.c */
extern void GNU_xref_begin PARAMS ((const char *));
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 4c59822..574d6ec 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -98,6 +98,10 @@ static int is_back_referenceable_type PARAMS ((tree));
static int check_btype PARAMS ((tree));
static void build_mangled_name_for_type PARAMS ((tree));
static void build_mangled_name_for_type_with_Gcode PARAMS ((tree, int));
+static tree synthesize_exception_spec PARAMS ((tree, tree (*) (tree, void *), void *));
+static tree locate_dtor PARAMS ((tree, void *));
+static tree locate_ctor PARAMS ((tree, void *));
+static tree locate_copy PARAMS ((tree, void *));
# define OB_INIT() (scratch_firstobj ? (obstack_free (&scratch_obstack, scratch_firstobj), 0) : 0)
# define OB_PUTC(C) (obstack_1grow (&scratch_obstack, (C)))
@@ -2585,6 +2589,163 @@ synthesize_method (fndecl)
pop_function_context_from (context);
}
+/* Use EXTRACTOR to locate the relevant function called for each base &
+ class field of TYPE. CLIENT allows additional information to be passed
+ to EXTRACTOR. Generates the union of all exceptions generated by
+ those functions. */
+
+static tree
+synthesize_exception_spec (type, extractor, client)
+ tree type;
+ tree (*extractor) (tree, void *);
+ void *client;
+{
+ tree raises = empty_except_spec;
+ tree fields = TYPE_FIELDS (type);
+ int i, n_bases = CLASSTYPE_N_BASECLASSES (type);
+ tree binfos = TYPE_BINFO_BASETYPES (type);
+
+ for (i = 0; i != n_bases; i++)
+ {
+ tree base = BINFO_TYPE (TREE_VEC_ELT (binfos, i));
+ tree fn = (*extractor) (base, client);
+ if (fn)
+ {
+ tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+
+ raises = merge_exception_specifiers (raises, fn_raises);
+ }
+ }
+ for (; fields; fields = TREE_CHAIN (fields))
+ {
+ tree type = TREE_TYPE (fields);
+ tree fn;
+
+ if (TREE_CODE (fields) != FIELD_DECL)
+ continue;
+ while (TREE_CODE (type) == ARRAY_TYPE)
+ type = TREE_TYPE (type);
+ if (TREE_CODE (type) != RECORD_TYPE)
+ continue;
+
+ fn = (*extractor) (type, client);
+ if (fn)
+ {
+ tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+
+ raises = merge_exception_specifiers (raises, fn_raises);
+ }
+ }
+ return raises;
+}
+
+/* Locate the dtor of TYPE. */
+
+static tree
+locate_dtor (type, client)
+ tree type;
+ void *client ATTRIBUTE_UNUSED;
+{
+ tree fns;
+
+ if (!TYPE_HAS_DESTRUCTOR (type))
+ return NULL_TREE;
+ fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type),
+ CLASSTYPE_DESTRUCTOR_SLOT);
+ return fns;
+}
+
+/* Locate the default ctor of TYPE. */
+
+static tree
+locate_ctor (type, client)
+ tree type;
+ void *client ATTRIBUTE_UNUSED;
+{
+ tree fns;
+
+ if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
+ return NULL_TREE;
+
+ fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type),
+ CLASSTYPE_CONSTRUCTOR_SLOT);
+ for (; fns; fns = OVL_NEXT (fns))
+ {
+ tree fn = OVL_CURRENT (fns);
+ tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
+
+ if (sufficient_parms_p (TREE_CHAIN (parms)))
+ return fn;
+ }
+ return NULL_TREE;
+}
+
+struct copy_data
+{
+ tree name;
+ int quals;
+};
+
+/* Locate the copy ctor or copy assignment of TYPE. CLIENT_
+ points to a COPY_DATA holding the name (NULL for the ctor)
+ and desired qualifiers of the source operand. */
+
+static tree
+locate_copy (type, client_)
+ tree type;
+ void *client_;
+{
+ struct copy_data *client = (struct copy_data *)client_;
+ tree fns;
+ int ix = -1;
+ tree best = NULL_TREE;
+ int excess_p = 0;
+
+ if (client->name)
+ {
+ if (TYPE_HAS_ASSIGN_REF (type))
+ ix = lookup_fnfields_1 (type, client->name);
+ }
+ else if (TYPE_HAS_INIT_REF (type))
+ ix = CLASSTYPE_CONSTRUCTOR_SLOT;
+ if (ix < 0)
+ return NULL_TREE;
+ fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), ix);
+
+ for (; fns; fns = OVL_NEXT (fns))
+ {
+ tree fn = OVL_CURRENT (fns);
+ tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ tree src_type;
+ int excess;
+ int quals;
+
+ parms = TREE_CHAIN (parms);
+ if (!parms)
+ continue;
+ src_type = TREE_VALUE (parms);
+ if (TREE_CODE (src_type) == REFERENCE_TYPE)
+ src_type = TREE_TYPE (src_type);
+ if (!same_type_ignoring_top_level_qualifiers_p (src_type, type))
+ continue;
+ if (!sufficient_parms_p (TREE_CHAIN (parms)))
+ continue;
+ quals = CP_TYPE_QUALS (src_type);
+ if (client->quals & ~quals)
+ continue;
+ excess = quals & ~client->quals;
+ if (!best || (excess_p && !excess))
+ {
+ best = fn;
+ excess_p = excess;
+ }
+ else
+ /* Ambiguous */
+ return NULL_TREE;
+ }
+ return best;
+}
+
/* Implicitly declare the special function indicated by KIND, as a
member of TYPE. For copy constructors and assignment operators,
CONST_P indicates whether these functions should take a const
@@ -2598,24 +2759,30 @@ implicitly_declare_fn (kind, type, const_p)
{
tree declspecs = NULL_TREE;
tree fn, args = NULL_TREE;
+ tree raises = empty_except_spec;
tree argtype;
int retref = 0;
tree name = constructor_name (TYPE_IDENTIFIER (type));
switch (kind)
{
- /* Destructors. */
case sfk_destructor:
+ /* Destructor. */
name = build_parse_node (BIT_NOT_EXPR, name);
args = void_list_node;
+ raises = synthesize_exception_spec (type, &locate_dtor, 0);
break;
case sfk_constructor:
/* Default constructor. */
args = void_list_node;
+ raises = synthesize_exception_spec (type, &locate_ctor, 0);
break;
case sfk_copy_constructor:
+ {
+ struct copy_data data;
+
if (const_p)
type = build_qualified_type (type, TYPE_QUAL_CONST);
argtype = build_reference_type (type);
@@ -2623,9 +2790,15 @@ implicitly_declare_fn (kind, type, const_p)
build_tree_list (hash_tree_chain (argtype, NULL_TREE),
get_identifier ("_ctor_arg")),
void_list_node);
+ data.name = NULL;
+ data.quals = const_p ? TYPE_QUAL_CONST : 0;
+ raises = synthesize_exception_spec (type, &locate_copy, &data);
break;
-
+ }
case sfk_assignment_operator:
+ {
+ struct copy_data data;
+
retref = 1;
declspecs = build_tree_list (NULL_TREE, type);
@@ -2639,8 +2812,11 @@ implicitly_declare_fn (kind, type, const_p)
build_tree_list (hash_tree_chain (argtype, NULL_TREE),
get_identifier ("_ctor_arg")),
void_list_node);
+ data.name = name;
+ data.quals = const_p ? TYPE_QUAL_CONST : 0;
+ raises = synthesize_exception_spec (type, &locate_copy, &data);
break;
-
+ }
default:
my_friendly_abort (59);
}
@@ -2648,7 +2824,7 @@ implicitly_declare_fn (kind, type, const_p)
TREE_PARMLIST (args) = 1;
{
- tree declarator = make_call_declarator (name, args, NULL_TREE, NULL_TREE);
+ tree declarator = make_call_declarator (name, args, NULL_TREE, raises);
if (retref)
declarator = build_parse_node (ADDR_EXPR, declarator);
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 72f0090..e2fab52 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -1964,10 +1964,7 @@ check_final_overrider (overrider, basefn)
}
/* Check throw specifier is subset. */
- /* XXX At the moment, punt with artificial functions. We
- don't generate their exception specifiers, so can't check properly. */
- if (! DECL_ARTIFICIAL (overrider)
- && !comp_except_specs (base_throw, over_throw, 0))
+ if (!comp_except_specs (base_throw, over_throw, 0))
{
cp_error_at ("looser throw specifier for `%#F'", overrider);
cp_error_at (" overriding `%#F'", basefn);
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 62b384a..5cccddc 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1296,3 +1296,39 @@ add_exception_specifier (list, spec, complain)
incomplete_type_error (NULL_TREE, core);
return list;
}
+
+/* Combine the two exceptions specifier lists LIST and ADD, and return
+ their union. */
+
+tree
+merge_exception_specifiers (list, add)
+ tree list, add;
+{
+ if (!list || !add)
+ return NULL_TREE;
+ else if (!TREE_VALUE (list))
+ return add;
+ else if (!TREE_VALUE (add))
+ return list;
+ else
+ {
+ tree orig_list = list;
+
+ for (; add; add = TREE_CHAIN (add))
+ {
+ tree spec = TREE_VALUE (add);
+ tree probe;
+
+ for (probe = orig_list; probe; probe = TREE_CHAIN (probe))
+ if (same_type_p (TREE_VALUE (probe), spec))
+ break;
+ if (!probe)
+ {
+ spec = build_tree_list (NULL_TREE, spec);
+ TREE_CHAIN (spec) = list;
+ list = spec;
+ }
+ }
+ }
+ return list;
+}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e591e1b..c45ae5c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2001-01-03 Nathan Sidwell <nathan@codesourcery.com>
+
+ * g++.old-deja/g++.eh/spec6.C: Remove remaining XFAIL.
+
2001-01-02 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* gcc.c-torture/compile/20010102-1.c: New test.
diff --git a/gcc/testsuite/g++.old-deja/g++.eh/spec6.C b/gcc/testsuite/g++.old-deja/g++.eh/spec6.C
index b6cd06a..6ecaec0 100644
--- a/gcc/testsuite/g++.old-deja/g++.eh/spec6.C
+++ b/gcc/testsuite/g++.old-deja/g++.eh/spec6.C
@@ -126,10 +126,7 @@ struct C : A, A1
{
virtual void foo() throw(int); // ERROR - looser throw - A::foo
virtual void bar() throw(int); // ERROR - looser throw - A1::bar
- // The xfail is because we don't build exception specifiers for implicit
- // members. So we don't check them either.
- // C::~C() throw(int), is the correct specification of the destructor.
-}; // ERROR - looser throw - A::~A() - XFAIL
+}; // ERROR - looser throw - A::~A()
struct D : A, A1
{