Bootstrapped and regtested on x86_64-cp-linux-gnu, does this look
OK for trunk and eventual backports?

-- >8 --

Here although the local templated variables x and y have the same
reduced constant value, only x's initializer is well-formed as written
since A::m has private access.  We correctly reject y's initializer (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 (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.
---
 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(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-97740a.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-97740b.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d628744dbfd1..31e88887e1aa 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -22091,8 +22091,14 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
          }
        else if (TREE_CODE (member) == FIELD_DECL)
          {
+           /* Assume access has already been checked appropriately; we don't
+              want to recheck it to avoid false negatives when substituting a
+              constant non-dependent 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..92902ff24a85
--- /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 = 42;
+} 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..c51590944d7e
--- /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 = 42;
+} 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>();
-- 
2.51.0.167.g6ad8021821

Reply via email to