]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: wrong ambiguity in accessing static field [PR112744]
authorMarek Polacek <polacek@redhat.com>
Tue, 28 Nov 2023 19:44:24 +0000 (14:44 -0500)
committerMarek Polacek <polacek@redhat.com>
Thu, 30 Nov 2023 21:40:57 +0000 (16:40 -0500)
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.

gcc/cp/typeck.cc
gcc/testsuite/g++.dg/lookup/scoped11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lookup/scoped12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lookup/scoped13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lookup/scoped14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lookup/scoped15.C [new file with mode: 0644]

index 0839d0a4167c7ad0e63dd84c88bf599b9ba128c2..bf8ffaa7e7567986709d15afc9f4f7026e8c754b 100644 (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)
diff --git a/gcc/testsuite/g++.dg/lookup/scoped11.C b/gcc/testsuite/g++.dg/lookup/scoped11.C
new file mode 100644 (file)
index 0000000..be74352
--- /dev/null
@@ -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 (file)
index 0000000..ffa1455
--- /dev/null
@@ -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 (file)
index 0000000..970e1aa
--- /dev/null
@@ -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 (file)
index 0000000..141aa0d
--- /dev/null
@@ -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 (file)
index 0000000..2cc4eb5
--- /dev/null
@@ -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>();