mirror of
https://github.com/gcc-mirror/gcc.git
synced 2024-11-21 13:40:47 +00:00
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:
parent
e81e84e02b
commit
725c68c54c
@ -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)
|
||||
|
14
gcc/testsuite/g++.dg/lookup/scoped11.C
Normal file
14
gcc/testsuite/g++.dg/lookup/scoped11.C
Normal 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;
|
||||
}
|
14
gcc/testsuite/g++.dg/lookup/scoped12.C
Normal file
14
gcc/testsuite/g++.dg/lookup/scoped12.C
Normal 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" }
|
||||
}
|
14
gcc/testsuite/g++.dg/lookup/scoped13.C
Normal file
14
gcc/testsuite/g++.dg/lookup/scoped13.C
Normal 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." }
|
||||
}
|
14
gcc/testsuite/g++.dg/lookup/scoped14.C
Normal file
14
gcc/testsuite/g++.dg/lookup/scoped14.C
Normal 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." }
|
||||
}
|
21
gcc/testsuite/g++.dg/lookup/scoped15.C
Normal file
21
gcc/testsuite/g++.dg/lookup/scoped15.C
Normal 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>();
|
Loading…
Reference in New Issue
Block a user