https://gcc.gnu.org/g:3e2077d8c7a0acba2d54bd0666ae578fe114cd72

commit r16-3543-g3e2077d8c7a0acba2d54bd0666ae578fe114cd72
Author: Patrick Palka <ppa...@redhat.com>
Date:   Wed Sep 3 10:10:00 2025 -0400

    c++: constant non-dep init folding vs FIELD_DECL access [PR97740]
    
    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 <ja...@redhat.com>

Diff:
---
 gcc/cp/pt.cc                                  |  6 ++++++
 gcc/testsuite/g++.dg/cpp0x/constexpr-97740a.C | 18 ++++++++++++++++++
 gcc/testsuite/g++.dg/cpp0x/constexpr-97740b.C | 20 ++++++++++++++++++++
 3 files changed, 44 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 65de1cff0e64..365a6c55a837 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -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
index 000000000000..7cb65c5eb535
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-97740a.C
@@ -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
index 000000000000..0ea767d94449
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-97740b.C
@@ -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>();

Reply via email to