]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: constant non-dep init folding vs FIELD_DECL access [PR97740]
authorPatrick Palka <ppalka@redhat.com>
Wed, 3 Sep 2025 14:10:00 +0000 (10:10 -0400)
committerPatrick Palka <ppalka@redhat.com>
Wed, 3 Sep 2025 14:10:00 +0000 (10:10 -0400)
Here although the local templated variables x and y have the same
reduced constant value, only x's initializer {a.get()} is well-formed
as written since A::m has private access.  We correctly reject y's
initializer {&a.m} (at instantiation time), but we also reject x's
initializer because we happen to constant fold it ahead of time, which
means at instantiation time it's already represented as a COMPONENT_REF
to a FIELD_DECL, and so when substituting this COMPONENT_REF we naively
double check that the given FIELD_DECL is accessible, which fails.

This patch sidesteps around this particular issue by not checking access
when substituting a COMPONENT_REF to a FIELD_DECL.  If the target of a
COMPONENT_REF is already a FIELD_DECL (i.e. before substitution), then I
think we can assume access has been already checked appropriately.

PR c++/97740

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) <case COMPONENT_REF>: Don't check access
when the given member is already a FIELD_DECL.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/constexpr-97740a.C: New test.
* g++.dg/cpp0x/constexpr-97740b.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/cp/pt.cc
gcc/testsuite/g++.dg/cpp0x/constexpr-97740a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/constexpr-97740b.C [new file with mode: 0644]

index 65de1cff0e64a852f7c41b8e66caf3116c226011..365a6c55a83714cb05be03c4e9f7b628d0dbdb88 100644 (file)
@@ -22092,8 +22092,14 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
          }
        else if (TREE_CODE (member) == FIELD_DECL)
          {
+           /* Assume access of this FIELD_DECL has already been checked; we
+              don't recheck it to avoid bogus access errors when substituting
+              a reduced constant initializer (97740).  */
+           gcc_checking_assert (TREE_CODE (TREE_OPERAND (t, 1)) == FIELD_DECL);
+           push_deferring_access_checks (dk_deferred);
            r = finish_non_static_data_member (member, object, NULL_TREE,
                                               complain);
+           pop_deferring_access_checks ();
            if (REF_PARENTHESIZED_P (t))
              r = force_paren_expr (r);
            RETURN (r);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-97740a.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-97740a.C
new file mode 100644 (file)
index 0000000..7cb65c5
--- /dev/null
@@ -0,0 +1,18 @@
+// PR c++/97740
+// { dg-do compile { target c++11 } }
+
+struct A {
+  constexpr const int* get() const { return &m; }
+private:
+  int m;
+} a;
+
+struct B { const int* p; };
+
+template<class T>
+void f() {
+  constexpr B x = {a.get()}; // { dg-bogus "private" }
+  constexpr B y = {&a.m};    // { dg-error "private" }
+}
+
+template void f<int>();
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-97740b.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-97740b.C
new file mode 100644 (file)
index 0000000..0ea767d
--- /dev/null
@@ -0,0 +1,20 @@
+// PR c++/97740
+// { dg-do compile { target c++14 } }
+
+struct A {
+  constexpr const int* get() const { return &m; }
+private:
+  int m;
+} a;
+
+struct B { const int* p; };
+
+template<A* arg>
+void f() {
+  [] (auto) {
+    constexpr B x = {arg->get()}; // { dg-bogus "private" }
+    constexpr B y = {&arg->m};    // { dg-error "private" }
+  }(0);
+}
+
+template void f<&a>();