c++: wrong ambiguity in accessing static field [PR112744]

Given

  struct A { constexpr static int a = 0; };
  struct B : A {};
  struct C : A {};
  struct D : B, C {};

we give the "'A' is an ambiguous base of 'D'" error for

  D{}.A::a;

which seems wrong: 'a' is a static data member so there is only one copy
so it can be unambiguously referred to even if there are multiple A
objects.  clang++/MSVC/icx agree.

This patch uses ba_any: [class.access.base] requires conversion to a unique
base subobject for non-static data members, but it does not require that the
base be unique or accessible for static data members.

	PR c++/112744

gcc/cp/ChangeLog:

	* typeck.cc (finish_class_member_access_expr): When accessing
	a static data member, use ba_any for lookup_base.

gcc/testsuite/ChangeLog:

	* g++.dg/lookup/scoped11.C: New test.
	* g++.dg/lookup/scoped12.C: New test.
	* g++.dg/lookup/scoped13.C: New test.
	* g++.dg/lookup/scoped14.C: New test.
	* g++.dg/lookup/scoped15.C: New test.
This commit is contained in:
Marek Polacek 2023-11-28 14:44:24 -05:00
parent e81e84e02b
commit 725c68c54c
6 changed files with 95 additions and 3 deletions

View File

@ -3467,7 +3467,7 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
name, scope);
return error_mark_node;
}
if (TREE_SIDE_EFFECTS (object))
val = build2 (COMPOUND_EXPR, TREE_TYPE (val), object, val);
return val;
@ -3484,9 +3484,24 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
return error_mark_node;
}
/* NAME may refer to a static data member, in which case there is
one copy of the data member that is shared by all the objects of
the class. So NAME can be unambiguously referred to even if
there are multiple indirect base classes containing NAME. */
const base_access ba = [scope, name] ()
{
if (identifier_p (name))
{
tree m = lookup_member (scope, name, /*protect=*/0,
/*want_type=*/false, tf_none);
if (!m || shared_member_p (m))
return ba_any;
}
return ba_check;
} ();
/* Find the base of OBJECT_TYPE corresponding to SCOPE. */
access_path = lookup_base (object_type, scope, ba_check,
NULL, complain);
access_path = lookup_base (object_type, scope, ba, NULL, complain);
if (access_path == error_mark_node)
return error_mark_node;
if (!access_path)

View File

@ -0,0 +1,14 @@
// PR c++/112744
// { dg-do compile }
struct A { const static int a = 0; };
struct B : A {};
struct C : A {};
struct D : B, C {};
int main()
{
D d;
(void) d.a;
(void) d.A::a;
}

View File

@ -0,0 +1,14 @@
// PR c++/112744
// { dg-do compile }
class A { const static int a = 0; };
struct B : A {};
struct C : A {};
struct D : B, C {};
int main()
{
D d;
(void) d.a; // { dg-error "private" }
(void) d.A::a; // { dg-error "private" }
}

View File

@ -0,0 +1,14 @@
// PR c++/112744
// { dg-do compile }
struct A { const static int a = 0; };
struct B : A {};
struct C : A {};
struct D : B, C {};
int main()
{
D d;
(void) d.x; // { dg-error ".struct D. has no member named .x." }
(void) d.A::x; // { dg-error ".struct A. has no member named .x." }
}

View File

@ -0,0 +1,14 @@
// PR c++/112744
// { dg-do compile { target c++11 } }
struct A { int a = 0; };
struct B : A {};
struct C : A {};
struct D : B, C {};
int main()
{
D d;
(void) d.a; // { dg-error "request for member .a. is ambiguous" }
(void) d.A::a; // { dg-error ".A. is an ambiguous base of .D." }
}

View File

@ -0,0 +1,21 @@
// PR c++/112744
// { dg-do compile { target c++11 } }
struct A { constexpr static int a = 0; };
struct D : private A {};
// The injected-class-name of A is private when named in D, but if A is named
// some other way, there is no requirement in [class.access.base] for static data
// members that it be an accessible base.
void f() {
D{}.A::a; // { dg-error "inaccessible" }
D{}.::A::a;
}
template<class T>
void g() {
D{}.T::a;
}
template void g<A>();