diff options
author | Marek Polacek <polacek@redhat.com> | 2023-11-28 14:44:24 -0500 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2023-11-30 16:40:57 -0500 |
commit | 725c68c54c265fe7f6fc7babff7139f3161bdfa6 (patch) | |
tree | b0c3d7d83da08349379e61d79a77fad9c10b0283 | |
parent | e81e84e02be2f9d6d87c41a512539214cb1a8bdc (diff) | |
download | gcc-725c68c54c265fe7f6fc7babff7139f3161bdfa6.zip gcc-725c68c54c265fe7f6fc7babff7139f3161bdfa6.tar.gz gcc-725c68c54c265fe7f6fc7babff7139f3161bdfa6.tar.bz2 |
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.
-rw-r--r-- | gcc/cp/typeck.cc | 21 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lookup/scoped11.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lookup/scoped12.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lookup/scoped13.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lookup/scoped14.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lookup/scoped15.C | 21 |
6 files changed, 95 insertions, 3 deletions
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 0839d0a..bf8ffaa 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -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) diff --git a/gcc/testsuite/g++.dg/lookup/scoped11.C b/gcc/testsuite/g++.dg/lookup/scoped11.C new file mode 100644 index 0000000..be74352 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/scoped11.C @@ -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; +} diff --git a/gcc/testsuite/g++.dg/lookup/scoped12.C b/gcc/testsuite/g++.dg/lookup/scoped12.C new file mode 100644 index 0000000..ffa1455 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/scoped12.C @@ -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" } +} diff --git a/gcc/testsuite/g++.dg/lookup/scoped13.C b/gcc/testsuite/g++.dg/lookup/scoped13.C new file mode 100644 index 0000000..970e1aa --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/scoped13.C @@ -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." } +} diff --git a/gcc/testsuite/g++.dg/lookup/scoped14.C b/gcc/testsuite/g++.dg/lookup/scoped14.C new file mode 100644 index 0000000..141aa0d --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/scoped14.C @@ -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." } +} diff --git a/gcc/testsuite/g++.dg/lookup/scoped15.C b/gcc/testsuite/g++.dg/lookup/scoped15.C new file mode 100644 index 0000000..2cc4eb5 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/scoped15.C @@ -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>(); |