aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2021-06-30 20:21:16 -0400
committerPatrick Palka <ppalka@redhat.com>2021-06-30 20:21:16 -0400
commit613497aa6e28ca009d8498002424019d2a8a9ca5 (patch)
tree3fef3700df8725b851222f694696d1b784f0e292 /gcc
parent25b6bfea5f14da53116f2d3efe2446de89b9bc03 (diff)
downloadgcc-613497aa6e28ca009d8498002424019d2a8a9ca5.zip
gcc-613497aa6e28ca009d8498002424019d2a8a9ca5.tar.gz
gcc-613497aa6e28ca009d8498002424019d2a8a9ca5.tar.bz2
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<T> instead of A<int>/A<char>). 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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/pt.c21
-rw-r--r--gcc/testsuite/g++.dg/template/access41.C24
-rw-r--r--gcc/testsuite/g++.dg/template/access41a.C29
3 files changed, 63 insertions, 11 deletions
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f8f7616..dda6c9e 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 0000000..1ab9a1a
--- /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<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 {
+ // The partial specialization does not match despite Child::type
+ // being accessible from the current scope.
+ static_assert(!has_type_member<Child>, "");
+};
diff --git a/gcc/testsuite/g++.dg/template/access41a.C b/gcc/testsuite/g++.dg/template/access41a.C
new file mode 100644
index 0000000..e108049
--- /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<class T>
+struct A {
+ template<class, class = void>
+ static constexpr bool has_type_member = false;
+};
+
+template<class T>
+template<class U>
+constexpr int A<T>::has_type_member<U, typename U::type> = true;
+
+struct Child {
+private:
+ friend struct A<int>;
+ typedef void type;
+};
+
+// The partial specialization matches because A<int> is a friend of Child.
+static_assert(A<int>::has_type_member<Child>, "");
+using type1 = const int;
+using type1 = decltype(A<int>::has_type_member<Child>);
+
+static_assert(!A<char>::has_type_member<Child>, "");
+using type2 = const bool;
+using type2 = decltype(A<char>::has_type_member<Child>);