On 6/25/25 3:08 AM, Jakub Jelinek wrote:
On Tue, Jun 24, 2025 at 05:19:59PM -0400, Jason Merrill wrote:
I think we could move the initialization of the fixed_type_p and
virtual_access variables up, they don't need to be after cp_build_addr_expr.
I don't understand why it doesn't depend on cp_build_addr_expr.
I've tried the following patch and while it didn't regress anything on
make GXX_TESTSUITE_STDS=98,11,14,17,^C,23,26 check-g++
it regressed
FAIL: 23_containers/vector/bool/cmp_c++20.cc -std=gnu++20 (test for excess
errors)
FAIL: 23_containers/vector/bool/cmp_c++20.cc -std=gnu++26 (test for excess
errors)
In there code is PLUS_EXPR, !want_pointer, !has_empty, but uneval is true
and expr is
std::vector<bool>::begin (&c)
before cp_build_addr_expr and
&TARGET_EXPR <D.316846, std::vector<bool>::begin (&c)>
after it. resolves_to_fixed_type_p (expr) is 0 before cp_build_addr_expr
and 1 after it.
Ah, looks like fixed_type_or_null needs to handle a CALL_EXPR of class
type like a TARGET_EXPR. I also wonder why the call isn't already
wrapped in a TARGET_EXPR by build_cxx_call=>build_cplus_new at this point.
v_binfo is false though, so in that
particular case I think we don't actually care about fixed_type_p value,
but it doesn't raise confidence that testing resolves_to_fixed_type_p
early is ok.
So, shall I e.g. for the if (TREE_PRIVATE case if the outer type has
CLASSTYPE_VBASECLASSES walk the
for (vbase = TYPE_BINFO (t); vbase; vbase = TREE_CHAIN (vbase))
if (BINFO_VIRTUAL_P (vbase) && !BINFO_PRIMARY_P (vbase))
and in that case try to compare byte_position (TREE_OPERAND (path, 1))
against BINFO_OFFSET (vbase) and if it matches (plus perhaps some type
check?) then decide based on BINFO_BASE_ACCESS or something like that
whether it was a private/protected vs. public virtual base?
It seems simpler to pass an accurate access to the build_base_field above.
At least whether the whole BINFO_INHERITANCE_CHAIN is public or not, I
suppose the distinction between private and protected doesn't matter.
I'm afraid I'm quite lost on what actually is public base class
that [expr.dynamic.cast] talks about in the case of virtual bases because
a virtual base can appear many times among the bases and if it is virtual
in all cases, there is just one copy of it and it can be public in some
paths and private/protected in others. And where to find that information.
I think it would make sense to add a publicly_virtually_derived_p
function after publicly_uniquely_derived_p, which adds
ba_require_virtual to the flags passed by the latter function. And then
you can use that here.
I've tried the following testcase and it seems that it succeeds unless
-DP1 -DP2
-DP1 -DP3
-DP1 -DP6
-DP2 -DP3 -DP6
-DP4 -DP5 -DP6
-DP2 -DP3 -DP4 -DP5
is a subset of the -DPN options or in case of clang++ also
-DP2 -DP4 -DP5 (for that g++ passes, clang++ fails).
E.g. what is the difference between -DP1 which works and
S is private in one case and public in 2 others, while -DP1 -DP2
doesn't work and is private in two cases and public in one.
Hmm, that does seem wrong. For -DP1 -DP2 dynamic_cast<T&>, following
the logic in https://eel.is/c++draft/expr#dynamic.cast-9 we get
9.1) in t, (S&)t does not refer to a public base of a T, because -DP1
makes it a private base. So move on.
9.2) (S&)t does refer to a public base of t because we didn't specify
-DP4. V does have an unambiguous (because virtual) public (because no
-DP3 -DP5) T base, so this ought to succeed.
This looks like https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81078
Jason
#ifdef P1
#undef P1
#define P1 private
#else
#define P1
#endif
#ifdef P2
#undef P2
#define P2 private
#else
#define P2
#endif
#ifdef P3
#undef P3
#define P3 private
#else
#define P3
#endif
#ifdef P4
#undef P4
#define P4 private
#else
#define P4
#endif
#ifdef P5
#undef P5
#define P5 private
#else
#define P5
#endif
#ifdef P6
#undef P6
#define P6 private
#else
#define P6
#endif
struct S { int a, b; virtual int bar (int) { return 0; } };
struct T : virtual P1 S { int c, d; };
struct U : virtual P2 S, virtual P3 T { int e; };
struct V : virtual P4 S, virtual P5 T, virtual P6 U { int f; S &foo () { return (S
&)*this; } };
int
main ()
{
V t;
t.f = 1;
// t.c = 2;
dynamic_cast<V &> (t.foo ());
dynamic_cast<T &> (t.foo ());
dynamic_cast<U &> (t.foo ());
}