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>
}
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);
--- /dev/null
+// 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>();
--- /dev/null
+// 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>();