summaryrefslogtreecommitdiff
path: root/gcc/cp/search.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/search.c')
-rw-r--r--gcc/cp/search.c141
1 files changed, 69 insertions, 72 deletions
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index fefd11b8b16..4c03f073afd 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -25,6 +25,8 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "cp-tree.h"
#include "obstack.h"
@@ -97,7 +99,6 @@ static tree dfs_push_type_decls PARAMS ((tree, void *));
static tree dfs_push_decls PARAMS ((tree, void *));
static tree dfs_unuse_fields PARAMS ((tree, void *));
static tree add_conversions PARAMS ((tree, void *));
-static int covariant_return_p PARAMS ((tree, tree));
static int look_for_overrides_r PARAMS ((tree, tree));
static struct search_level *push_search_level
PARAMS ((struct stack_level *, struct obstack *));
@@ -1850,58 +1851,6 @@ dfs_walk (binfo, fn, qfn, data)
return dfs_walk_real (binfo, 0, fn, qfn, data);
}
-/* Returns > 0 if a function with type DRETTYPE overriding a function
- with type BRETTYPE is covariant, as defined in [class.virtual].
-
- Returns 1 if trivial covariance, 2 if non-trivial (requiring runtime
- adjustment), or -1 if pedantically invalid covariance. */
-
-static int
-covariant_return_p (brettype, drettype)
- tree brettype, drettype;
-{
- tree binfo;
- base_kind kind;
-
- if (TREE_CODE (brettype) == FUNCTION_DECL)
- {
- brettype = TREE_TYPE (TREE_TYPE (brettype));
- drettype = TREE_TYPE (TREE_TYPE (drettype));
- }
- else if (TREE_CODE (brettype) == METHOD_TYPE)
- {
- brettype = TREE_TYPE (brettype);
- drettype = TREE_TYPE (drettype);
- }
-
- if (same_type_p (brettype, drettype))
- return 0;
-
- if (! (TREE_CODE (brettype) == TREE_CODE (drettype)
- && (TREE_CODE (brettype) == POINTER_TYPE
- || TREE_CODE (brettype) == REFERENCE_TYPE)
- && TYPE_QUALS (brettype) == TYPE_QUALS (drettype)))
- return 0;
-
- if (! can_convert (brettype, drettype))
- return 0;
-
- brettype = TREE_TYPE (brettype);
- drettype = TREE_TYPE (drettype);
-
- /* If not pedantic, allow any standard pointer conversion. */
- if (! IS_AGGR_TYPE (drettype) || ! IS_AGGR_TYPE (brettype))
- return -1;
-
- binfo = lookup_base (drettype, brettype, ba_check | ba_quiet, &kind);
-
- if (!binfo)
- return 0;
- if (BINFO_OFFSET_ZEROP (binfo) && kind != bk_via_virtual)
- return 1;
- return 2;
-}
-
/* Check that virtual overrider OVERRIDER is acceptable for base function
BASEFN. Issue diagnostic, and return zero, if unacceptable. */
@@ -1915,32 +1864,74 @@ check_final_overrider (overrider, basefn)
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;
+ int fail = 0;
if (same_type_p (base_return, over_return))
/* OK */;
- else if ((i = covariant_return_p (base_return, over_return)))
+ else if ((CLASS_TYPE_P (over_return) && CLASS_TYPE_P (base_return))
+ || (TREE_CODE (base_return) == TREE_CODE (over_return)
+ && POINTER_TYPE_P (base_return)))
{
- if (i == 2)
- sorry ("adjusting pointers for covariant returns");
+ /* Potentially covariant. */
+ unsigned base_quals, over_quals;
+
+ fail = !POINTER_TYPE_P (base_return);
+ if (!fail)
+ {
+ fail = cp_type_quals (base_return) != cp_type_quals (over_return);
+
+ base_return = TREE_TYPE (base_return);
+ over_return = TREE_TYPE (over_return);
+ }
+ base_quals = cp_type_quals (base_return);
+ over_quals = cp_type_quals (over_return);
+
+ if ((base_quals & over_quals) != over_quals)
+ fail = 1;
+
+ if (CLASS_TYPE_P (base_return) && CLASS_TYPE_P (over_return))
+ {
+ tree binfo = lookup_base (over_return, base_return,
+ ba_check | ba_quiet, NULL);
- if (pedantic && i == -1)
+ if (!binfo)
+ fail = 1;
+ }
+ else if (!pedantic
+ && can_convert (TREE_TYPE (base_type), TREE_TYPE (over_type)))
+ /* GNU extension, allow trivial pointer conversions such as
+ converting to void *, or qualification conversion. */
{
- cp_pedwarn_at ("invalid covariant return type for `%#D'", overrider);
- cp_pedwarn_at (" overriding `%#D' (must be pointer or reference to class)", basefn);
+ /* can_convert will permit user defined conversion from a
+ (reference to) class type. We must reject them. */
+ over_return = TREE_TYPE (over_type);
+ if (TREE_CODE (over_return) == REFERENCE_TYPE)
+ over_return = TREE_TYPE (over_return);
+ if (CLASS_TYPE_P (over_return))
+ fail = 2;
}
+ else
+ fail = 2;
}
- 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 `%#D'", overrider);
- cp_error_at (" overriding `%#D' (must use pointer or reference)", basefn);
- return 0;
- }
- else if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)) == NULL_TREE)
+ else
+ fail = 2;
+ if (!fail)
+ /* OK */;
+ else if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)))
+ return 0;
+ else
{
- cp_error_at ("conflicting return type specified for `%#D'", overrider);
- cp_error_at (" overriding `%#D'", basefn);
+ if (fail == 1)
+ {
+ cp_error_at ("invalid covariant return type for `%#D'", overrider);
+ cp_error_at (" overriding `%#D'", basefn);
+ }
+ else
+ {
+ cp_error_at ("conflicting return type specified for `%#D'",
+ overrider);
+ cp_error_at (" overriding `%#D'", basefn);
+ }
SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider),
DECL_CONTEXT (overrider));
return 0;
@@ -1949,10 +1940,16 @@ check_final_overrider (overrider, basefn)
/* Check throw specifier is at least as strict. */
if (!comp_except_specs (base_throw, over_throw, 0))
{
- cp_error_at ("looser throw specifier for `%#F'", overrider);
- cp_error_at (" overriding `%#F'", basefn);
+ if (!IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)))
+ {
+ cp_error_at ("looser throw specifier for `%#F'", overrider);
+ cp_error_at (" overriding `%#F'", basefn);
+ SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider),
+ DECL_CONTEXT (overrider));
+ }
return 0;
}
+
return 1;
}