r12-1829 corrected the access scope during partial specialization matching of class templates, but neglected the variable template case. This patch moves the access scope adjustment to inside most_specialized_partial_spec, so that all callers can benefit.
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk? PR c++/96204 gcc/cp/ChangeLog: * pt.c (instantiate_class_template_1): Remove call to push_nested_class and pop_nested_class added by r12-1829. (most_specialized_partial_spec): Use push_access_scope_guard and deferring_access_check_sentinel. gcc/testsuite/ChangeLog: * g++.dg/template/access40b.C: New test. --- gcc/cp/pt.c | 12 +++++++---- gcc/testsuite/g++.dg/template/access40b.C | 26 +++++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/access40b.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index bd8b17ca047..1e2e2ba5329 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11776,11 +11776,8 @@ instantiate_class_template_1 (tree type) deferring_access_check_sentinel acs (dk_no_deferred); /* Determine what specialization of the original template to - instantiate; do this relative to the scope of the class for - sake of access checking. */ - push_nested_class (type); + instantiate. */ t = most_specialized_partial_spec (type, tf_warning_or_error); - pop_nested_class (); if (t == error_mark_node) return error_mark_node; else if (t) @@ -24989,26 +24986,33 @@ most_specialized_partial_spec (tree target, tsubst_flags_t complain) tree outer_args = NULL_TREE; tree tmpl, args; + tree decl; if (TYPE_P (target)) { tree tinfo = CLASSTYPE_TEMPLATE_INFO (target); tmpl = TI_TEMPLATE (tinfo); args = TI_ARGS (tinfo); + decl = TYPE_NAME (target); } else if (TREE_CODE (target) == TEMPLATE_ID_EXPR) { tmpl = TREE_OPERAND (target, 0); args = TREE_OPERAND (target, 1); + decl = DECL_TEMPLATE_RESULT (tmpl); } else if (VAR_P (target)) { tree tinfo = DECL_TEMPLATE_INFO (target); tmpl = TI_TEMPLATE (tinfo); args = TI_ARGS (tinfo); + decl = target; } else gcc_unreachable (); + push_access_scope_guard pas (decl); + deferring_access_check_sentinel acs (dk_no_deferred); + tree main_tmpl = most_general_template (tmpl); /* For determining which partial specialization to use, only the diff --git a/gcc/testsuite/g++.dg/template/access40b.C b/gcc/testsuite/g++.dg/template/access40b.C new file mode 100644 index 00000000000..040e3d18096 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/access40b.C @@ -0,0 +1,26 @@ +// PR c++/96204 +// { dg-do compile { target c++14 } } +// A variant of access40.C where has_type_member is a variable template instead +// of a class template. + +template<class, class = void> +constexpr bool has_type_member = false; + +template<class T> +constexpr bool has_type_member<T, typename T::type> = true; + +struct Parent; + +struct Child { +private: + friend struct Parent; + typedef void type; +}; + +struct Parent { + static void f() { + // The partial specialization does not match despite Child::type + // being accessible from the current scope. + static_assert(!has_type_member<Child>, ""); + } +}; -- 2.32.0.93.g670b81a890