aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2025-09-03 10:10:00 -0400
committerPatrick Palka <ppalka@redhat.com>2025-09-03 10:10:00 -0400
commit3e2077d8c7a0acba2d54bd0666ae578fe114cd72 (patch)
tree8841fa0451b0230281ea1c46491da38bc1174a10
parentdf64893e7082d7fae5d6863fd02371b37c78557f (diff)
downloadgcc-3e2077d8c7a0acba2d54bd0666ae578fe114cd72.zip
gcc-3e2077d8c7a0acba2d54bd0666ae578fe114cd72.tar.gz
gcc-3e2077d8c7a0acba2d54bd0666ae578fe114cd72.tar.bz2
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 <jason@redhat.com>
-rw-r--r--gcc/cp/pt.cc6
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/constexpr-97740a.C18
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/constexpr-97740b.C20
3 files changed, 44 insertions, 0 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 65de1cf..365a6c5 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 0000000..7cb65c5
--- /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 0000000..0ea767d
--- /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>();