c++: access scope during partial spec matching [PR96204]
Here, when determining whether the partial specialization matches has_type_member<Child>, we do so from the scope of where the template-id appears rather than from the scope of the specialization, and this causes us to select the partial specialization (since Child::type is accessible from Parent). When we later instantiate this partial specialization, we've entered the scope of the specialization and so substitution into e.g. the DECL_CONTEXT of has_type_member::value fails with access errors since the friend declaration that we relied on to choose the partial specialization no longer applies. It seems the appropriate access scope from which to perform partial specialization matching is the specialization itself (similar to how we check access of base-clauses), which is what this patch implements. PR c++/96204 gcc/cp/ChangeLog: * pt.c (instantiate_class_template_1): Enter the scope of the type when calling most_specialized_partial_spec. gcc/testsuite/ChangeLog: * g++.dg/template/access40.C: New test. * g++.dg/template/access40a.C: New test.
This commit is contained in:
parent
5b1ce655b2
commit
9f26e34a5a
@ -11769,8 +11769,11 @@ instantiate_class_template_1 (tree type)
|
||||
deferring_access_check_sentinel acs (dk_no_deferred);
|
||||
|
||||
/* Determine what specialization of the original template to
|
||||
instantiate. */
|
||||
instantiate; do this relative to the scope of the class for
|
||||
sake of access checking. */
|
||||
push_nested_class (type);
|
||||
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)
|
||||
|
28
gcc/testsuite/g++.dg/template/access40.C
Normal file
28
gcc/testsuite/g++.dg/template/access40.C
Normal file
@ -0,0 +1,28 @@
|
||||
// PR c++/96204
|
||||
|
||||
template<class, class = void>
|
||||
struct has_type_member {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct has_type_member<T, typename T::type> {
|
||||
static const bool value = 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.
|
||||
extern int x[1];
|
||||
extern int x[!has_type_member<Child>::value];
|
||||
}
|
||||
};
|
28
gcc/testsuite/g++.dg/template/access40a.C
Normal file
28
gcc/testsuite/g++.dg/template/access40a.C
Normal file
@ -0,0 +1,28 @@
|
||||
// PR c++/96204
|
||||
|
||||
template<class, class = void>
|
||||
struct has_type_member {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct has_type_member<T, typename T::type> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
struct Parent;
|
||||
|
||||
struct Child {
|
||||
private:
|
||||
friend struct has_type_member<Child>;
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
struct Parent {
|
||||
static void f() {
|
||||
// The partial specialization matches because has_type_member<Child>
|
||||
// is a friend of Child.
|
||||
extern int x[1];
|
||||
extern int x[has_type_member<Child>::value];
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user