From: Patrick Palka Date: Thu, 1 Jul 2021 00:21:16 +0000 (-0400) Subject: c++: Extend the PR96204 fix to variable templates too X-Git-Tag: basepoints/gcc-13~6368 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=613497aa6e28ca009d8498002424019d2a8a9ca5;p=thirdparty%2Fgcc.git c++: Extend the PR96204 fix to variable templates too r12-1829 corrected the access scope during partial specialization matching of class templates, but overlooked the variable template case. This patch moves the access scope adjustment to within most_specialized_partial_spec so that all callers can benefit. This patch also adjusts a couple of these callers to avoid always passing the most general template of a variable template specialization, since that'd cause us to push the wrong access scope for e.g. the second testcase below (we'd push A instead of A/A). We ought to be passing the partially instantiated template instead. PR c++/96204 gcc/cp/ChangeLog: * pt.c (finish_template_variable): Pass the partially instantiated template and its args to instantiate_template. (instantiate_class_template_1): No need to call push_nested_class and pop_nested_class around the call to most_specialized_partial_spec. (instantiate_template_1): Pass the partially instantiated template to lookup_template_variable. (most_specialized_partial_spec): Use push_access_scope_guard to set the access scope appropriately. Use deferring_access_check_sentinel to force access to get checked immediately. (instantiate_decl): Just pass the VAR_DECL to most_specialized_partial_spec. gcc/testsuite/ChangeLog: * g++.dg/template/access41.C: New test. * g++.dg/template/access41a.C: New test. --- diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f8f7616bf2a1..dda6c9e940d4 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10268,10 +10268,6 @@ finish_template_variable (tree var, tsubst_flags_t complain) tree templ = TREE_OPERAND (var, 0); tree arglist = TREE_OPERAND (var, 1); - tree tmpl_args = DECL_TI_ARGS (DECL_TEMPLATE_RESULT (templ)); - arglist = add_outermost_template_args (tmpl_args, arglist); - - templ = most_general_template (templ); tree parms = DECL_TEMPLATE_PARMS (templ); arglist = coerce_innermost_template_parms (parms, arglist, templ, complain, /*req_all*/true, @@ -11774,11 +11770,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) @@ -21134,7 +21127,7 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain) /* We need to determine if we're using a partial or explicit specialization now, because the type of the variable could be different. */ - tree tid = lookup_template_variable (gen_tmpl, targ_ptr); + tree tid = lookup_template_variable (tmpl, targ_ptr); tree elt = most_specialized_partial_spec (tid, complain); if (elt == error_mark_node) pattern = error_mark_node; @@ -24987,26 +24980,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 @@ -26011,8 +26011,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) if (variable_template_specialization_p (d)) { /* Look up an explicit specialization, if any. */ - tree tid = lookup_template_variable (gen_tmpl, gen_args); - tree elt = most_specialized_partial_spec (tid, tf_warning_or_error); + tree elt = most_specialized_partial_spec (d, tf_warning_or_error); if (elt && elt != error_mark_node) { td = TREE_VALUE (elt); diff --git a/gcc/testsuite/g++.dg/template/access41.C b/gcc/testsuite/g++.dg/template/access41.C new file mode 100644 index 000000000000..1ab9a1ab243b --- /dev/null +++ b/gcc/testsuite/g++.dg/template/access41.C @@ -0,0 +1,24 @@ +// 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 +constexpr bool has_type_member = false; + +template +constexpr bool has_type_member = true; + +struct Parent; + +struct Child { +private: + friend struct Parent; + typedef void type; +}; + +struct Parent { + // The partial specialization does not match despite Child::type + // being accessible from the current scope. + static_assert(!has_type_member, ""); +}; diff --git a/gcc/testsuite/g++.dg/template/access41a.C b/gcc/testsuite/g++.dg/template/access41a.C new file mode 100644 index 000000000000..e108049048de --- /dev/null +++ b/gcc/testsuite/g++.dg/template/access41a.C @@ -0,0 +1,29 @@ +// PR c++/96204 +// { dg-do compile { target c++14 } } +// A variant of access40a.C where has_type_member is a variable template instead +// of a class template. + +template +struct A { + template + static constexpr bool has_type_member = false; +}; + +template +template +constexpr int A::has_type_member = true; + +struct Child { +private: + friend struct A; + typedef void type; +}; + +// The partial specialization matches because A is a friend of Child. +static_assert(A::has_type_member, ""); +using type1 = const int; +using type1 = decltype(A::has_type_member); + +static_assert(!A::has_type_member, ""); +using type2 = const bool; +using type2 = decltype(A::has_type_member);