Looking in the vtable for cand->conversion_path doesn't work because
it's the base where we found the function, not the base where the
function is defined. If those are different, look farther. Applying to
trunk and 10.
The second patch uses that same base lookup for the actual conversion as
well as finding the final overrider. Applying only to trunk.
Tested x86_64-pc-linux-gnu.
commit 2c8346f6b30039be0ea898ce94a3bef85a8783cc
Author: Jason Merrill <ja...@redhat.com>
Date: Tue Jun 23 21:25:21 2020 -0400
c++: Fix ICE with using and virtual function [PR95719]
conversion_path points to the base where we found the using-declaration, not
where the function is actually a member; look up the actual base. And then
maybe look back to the derived class if the base is primary.
gcc/cp/ChangeLog:
PR c++/95719
* call.c (build_over_call): Look up the overrider in base_binfo.
* class.c (lookup_vfn_in_binfo): Look through BINFO_PRIMARY_P.
gcc/testsuite/ChangeLog:
PR c++/95719
* g++.dg/tree-ssa/final4.C: New test.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 2b39a3700fc..fe68fda1364 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -8694,7 +8694,11 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0
&& resolves_to_fixed_type_p (arg))
{
- fn = lookup_vfn_in_binfo (DECL_VINDEX (fn), cand->conversion_path);
+ tree binfo = cand->conversion_path;
+ if (BINFO_TYPE (binfo) != DECL_CONTEXT (fn))
+ binfo = lookup_base (binfo, DECL_CONTEXT (fn), ba_unique,
+ NULL, complain);
+ fn = lookup_vfn_in_binfo (DECL_VINDEX (fn), binfo);
flags |= LOOKUP_NONVIRTUAL;
}
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 629d27da894..94a95854e25 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -2455,6 +2455,10 @@ lookup_vfn_in_binfo (tree idx, tree binfo)
int ix = tree_to_shwi (idx);
if (TARGET_VTABLE_USES_DESCRIPTORS)
ix /= MAX (TARGET_VTABLE_USES_DESCRIPTORS, 1);
+ while (BINFO_PRIMARY_P (binfo))
+ /* BINFO_VIRTUALS in a primary base isn't accurate, find the derived
+ class that actually owns the vtable. */
+ binfo = BINFO_INHERITANCE_CHAIN (binfo);
tree virtuals = BINFO_VIRTUALS (binfo);
return TREE_VALUE (chain_index (ix, virtuals));
}
diff --git a/gcc/testsuite/g++.dg/tree-ssa/final4.C b/gcc/testsuite/g++.dg/tree-ssa/final4.C
new file mode 100644
index 00000000000..387d4bb26c2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/final4.C
@@ -0,0 +1,12 @@
+// PR c++/95719
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -fdump-tree-gimple }
+// { dg-final { scan-tree-dump "S2::f" "gimple" } }
+
+struct S1 { virtual ~S1(); };
+struct S2 {
+ virtual ~S2();
+ virtual void f();
+};
+struct S3 final: S1, S2 { using S2::f; };
+void g(S3 & s) { s.f(); }
commit 3d9fe61f07abb2653412259a974811917149b3b8
Author: Jason Merrill <ja...@redhat.com>
Date: Wed Jun 24 01:49:06 2020 -0400
c++: Simplify build_over_call a bit.
It occurred to me that if we're looking up the defining base within the
conversion_path binfo, we could use the result for the conversion as well
instead of doing two separate conversions.
gcc/cp/ChangeLog:
* call.c (build_over_call): Only call build_base_path once.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index fe68fda1364..d8923be1d68 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -8658,13 +8658,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
/* Bypass access control for 'this' parameter. */
else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
{
- tree parmtype = TREE_VALUE (parm);
tree arg = build_this (first_arg != NULL_TREE
? first_arg
: (*args)[arg_index]);
tree argtype = TREE_TYPE (arg);
- tree converted_arg;
- tree base_binfo;
if (arg == error_mark_node)
return error_mark_node;
@@ -8683,38 +8680,20 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
return error_mark_node;
}
+ /* The class where FN is defined. */
+ tree ctx = DECL_CONTEXT (fn);
+
/* See if the function member or the whole class type is declared
final and the call can be devirtualized. */
- if (DECL_FINAL_P (fn)
- || CLASSTYPE_FINAL (TYPE_METHOD_BASETYPE (TREE_TYPE (fn))))
+ if (DECL_FINAL_P (fn) || CLASSTYPE_FINAL (ctx))
flags |= LOOKUP_NONVIRTUAL;
- /* If we know the dynamic type of the object, look up the final overrider
- in the BINFO. */
- if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0
- && resolves_to_fixed_type_p (arg))
- {
- tree binfo = cand->conversion_path;
- if (BINFO_TYPE (binfo) != DECL_CONTEXT (fn))
- binfo = lookup_base (binfo, DECL_CONTEXT (fn), ba_unique,
- NULL, complain);
- fn = lookup_vfn_in_binfo (DECL_VINDEX (fn), binfo);
- flags |= LOOKUP_NONVIRTUAL;
- }
-
/* [class.mfct.non-static]: If a non-static member function of a class
X is called for an object that is not of type X, or of a type
derived from X, the behavior is undefined.
So we can assume that anything passed as 'this' is non-null, and
optimize accordingly. */
- gcc_assert (TYPE_PTR_P (parmtype));
- /* Convert to the base in which the function was declared. */
- gcc_assert (cand->conversion_path != NULL_TREE);
- converted_arg = build_base_path (PLUS_EXPR,
- arg,
- cand->conversion_path,
- 1, complain);
/* Check that the base class is accessible. */
if (!accessible_base_p (TREE_TYPE (argtype),
BINFO_TYPE (cand->conversion_path), true))
@@ -8728,12 +8707,25 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
}
/* If fn was found by a using declaration, the conversion path
will be to the derived class, not the base declaring fn. We
- must convert from derived to base. */
- base_binfo = lookup_base (TREE_TYPE (TREE_TYPE (converted_arg)),
- TREE_TYPE (parmtype), ba_unique,
- NULL, complain);
- converted_arg = build_base_path (PLUS_EXPR, converted_arg,
- base_binfo, 1, complain);
+ must convert to the base. */
+ tree base_binfo = cand->conversion_path;
+ if (BINFO_TYPE (base_binfo) != ctx)
+ {
+ base_binfo = lookup_base (base_binfo, ctx, ba_unique, NULL, complain);
+ if (base_binfo == error_mark_node)
+ return error_mark_node;
+ }
+ tree converted_arg = build_base_path (PLUS_EXPR, arg,
+ base_binfo, 1, complain);
+
+ /* If we know the dynamic type of the object, look up the final overrider
+ in the BINFO. */
+ if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0
+ && resolves_to_fixed_type_p (arg))
+ {
+ fn = lookup_vfn_in_binfo (DECL_VINDEX (fn), base_binfo);
+ flags |= LOOKUP_NONVIRTUAL;
+ }
argarray[j++] = converted_arg;
parm = TREE_CHAIN (parm);