On Tue, 29 Jun 2021, Jason Merrill wrote: > On 6/29/21 1:57 PM, Patrick Palka wrote: > > When push_access_scope is passed a TYPE_DECL for a class type (which > > can happen during e.g. satisfaction), we undesirably push only the > > enclosing context of the class instead of the class itself. This causes > > us to mishandle e.g. testcase below due to us not entering the scope of > > A before checking its constraints. > > > > This patch adjusts push_access_scope accordingly, and introduces an > > RAII wrapper for it. We also make use of this wrapper right away by > > replacing the only use of push_nested_class_guard with this new wrapper, > > which means we can remove this old wrapper (whose functionality is > > basically subsumed by the new wrapper). > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > > trunk? > > > > gcc/cp/ChangeLog: > > > > * constraint.cc (get_normalized_constraints_from_decl): Use > > push_access_scope_guard instead of push_nested_class_guard. > > * cp-tree.h (struct push_nested_class_guard): Replace with ... > > (struct push_access_scope_guard): ... this. > > * pt.c (push_access_scope): When the argument corresponds to > > a class type, push the class instead of its context. > > (pop_access_scope): Adjust accordingly. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/cpp2a/concepts-access2.C: New test. > > --- > > gcc/cp/constraint.cc | 7 +----- > > gcc/cp/cp-tree.h | 23 +++++++++++-------- > > gcc/cp/pt.c | 9 +++++++- > > gcc/testsuite/g++.dg/cpp2a/concepts-access2.C | 13 +++++++++++ > > 4 files changed, 35 insertions(+), 17 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-access2.C > > > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc > > index 6df3ca6ce32..99d3ccc6998 100644 > > --- a/gcc/cp/constraint.cc > > +++ b/gcc/cp/constraint.cc > > @@ -926,12 +926,7 @@ get_normalized_constraints_from_decl (tree d, bool diag > > = false) > > tree norm = NULL_TREE; > > if (tree ci = get_constraints (decl)) > > { > > - push_nested_class_guard pncs (DECL_CONTEXT (d)); > > - > > - temp_override<tree> ovr (current_function_decl); > > - if (TREE_CODE (decl) == FUNCTION_DECL) > > - current_function_decl = decl; > > - > > + push_access_scope_guard pas (decl); > > norm = get_normalized_constraints_from_info (ci, tmpl, diag); > > } > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > > index 6f713719589..58da7460001 100644 > > --- a/gcc/cp/cp-tree.h > > +++ b/gcc/cp/cp-tree.h > > @@ -8463,21 +8463,24 @@ is_constrained_auto (const_tree t) > > return is_auto (t) && PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t); > > } > > -/* RAII class to push/pop class scope T; if T is not a class, do nothing. > > */ > > +/* RAII class to push/pop the access scope for T. */ > > -struct push_nested_class_guard > > +struct push_access_scope_guard > > { > > - bool push; > > - push_nested_class_guard (tree t) > > - : push (t && CLASS_TYPE_P (t)) > > + tree decl; > > + push_access_scope_guard (tree t) > > + : decl (t) > > { > > - if (push) > > - push_nested_class (t); > > + if (VAR_OR_FUNCTION_DECL_P (decl) > > + || TREE_CODE (decl) == TYPE_DECL) > > + push_access_scope (decl); > > + else > > + decl = NULL_TREE; > > } > > - ~push_nested_class_guard () > > + ~push_access_scope_guard () > > { > > - if (push) > > - pop_nested_class (); > > + if (decl) > > + pop_access_scope (decl); > > } > > }; > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > > index f2039e09cd7..bd8b17ca047 100644 > > --- a/gcc/cp/pt.c > > +++ b/gcc/cp/pt.c > > @@ -224,7 +224,7 @@ static void instantiate_body (tree pattern, tree args, > > tree d, bool nested); > > /* Make the current scope suitable for access checking when we are > > processing T. T can be FUNCTION_DECL for instantiated function > > template, VAR_DECL for static member variable, or TYPE_DECL for > > - alias template (needed by instantiate_decl). */ > > + for a class or alias template (needed by instantiate_decl). */ > > void > > push_access_scope (tree t) > > @@ -234,6 +234,10 @@ push_access_scope (tree t) > > if (DECL_FRIEND_CONTEXT (t)) > > push_nested_class (DECL_FRIEND_CONTEXT (t)); > > + else if (TREE_CODE (t) == TYPE_DECL > > + && CLASS_TYPE_P (TREE_TYPE (t)) > > + && DECL_ORIGINAL_TYPE (t) == NULL_TREE) > > I suspect DECL_IMPLICIT_TYPEDEF_P is a better test for this case.
That works nicely. How does the following look? Bootstrapped and regtested on x86_64-pc-linux-gnu. -- >8 -- gcc/cp/ChangeLog: * constraint.cc (get_normalized_constraints_from_decl): Use push_access_scope_guard instead of push_nested_class_guard. * cp-tree.h (struct push_nested_class_guard): Replace with ... (struct push_access_scope_guard): ... this. * pt.c (push_access_scope): When the argument corresponds to a class type, push the class instead of its context. (pop_access_scope): Adjust accordingly. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-access2.C: New test. --- gcc/cp/constraint.cc | 7 +----- gcc/cp/cp-tree.h | 23 +++++++++++-------- gcc/cp/pt.c | 7 +++++- gcc/testsuite/g++.dg/cpp2a/concepts-access2.C | 13 +++++++++++ 4 files changed, 33 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-access2.C diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 6df3ca6ce32..99d3ccc6998 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -926,12 +926,7 @@ get_normalized_constraints_from_decl (tree d, bool diag = false) tree norm = NULL_TREE; if (tree ci = get_constraints (decl)) { - push_nested_class_guard pncs (DECL_CONTEXT (d)); - - temp_override<tree> ovr (current_function_decl); - if (TREE_CODE (decl) == FUNCTION_DECL) - current_function_decl = decl; - + push_access_scope_guard pas (decl); norm = get_normalized_constraints_from_info (ci, tmpl, diag); } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6f713719589..58da7460001 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8463,21 +8463,24 @@ is_constrained_auto (const_tree t) return is_auto (t) && PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t); } -/* RAII class to push/pop class scope T; if T is not a class, do nothing. */ +/* RAII class to push/pop the access scope for T. */ -struct push_nested_class_guard +struct push_access_scope_guard { - bool push; - push_nested_class_guard (tree t) - : push (t && CLASS_TYPE_P (t)) + tree decl; + push_access_scope_guard (tree t) + : decl (t) { - if (push) - push_nested_class (t); + if (VAR_OR_FUNCTION_DECL_P (decl) + || TREE_CODE (decl) == TYPE_DECL) + push_access_scope (decl); + else + decl = NULL_TREE; } - ~push_nested_class_guard () + ~push_access_scope_guard () { - if (push) - pop_nested_class (); + if (decl) + pop_access_scope (decl); } }; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d2936c106ba..f8f7616bf2a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -224,7 +224,7 @@ static void instantiate_body (tree pattern, tree args, tree d, bool nested); /* Make the current scope suitable for access checking when we are processing T. T can be FUNCTION_DECL for instantiated function template, VAR_DECL for static member variable, or TYPE_DECL for - alias template (needed by instantiate_decl). */ + for a class or alias template (needed by instantiate_decl). */ void push_access_scope (tree t) @@ -234,6 +234,9 @@ push_access_scope (tree t) if (DECL_FRIEND_CONTEXT (t)) push_nested_class (DECL_FRIEND_CONTEXT (t)); + else if (DECL_IMPLICIT_TYPEDEF_P (t) + && CLASS_TYPE_P (TREE_TYPE (t))) + push_nested_class (TREE_TYPE (t)); else if (DECL_CLASS_SCOPE_P (t)) push_nested_class (DECL_CONTEXT (t)); else if (deduction_guide_p (t) && DECL_ARTIFICIAL (t)) @@ -260,6 +263,8 @@ pop_access_scope (tree t) current_function_decl = saved_access_scope->pop(); if (DECL_FRIEND_CONTEXT (t) + || (DECL_IMPLICIT_TYPEDEF_P (t) + && CLASS_TYPE_P (TREE_TYPE (t))) || DECL_CLASS_SCOPE_P (t) || (deduction_guide_p (t) && DECL_ARTIFICIAL (t))) pop_nested_class (); diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-access2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-access2.C new file mode 100644 index 00000000000..8ddcad236e3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-access2.C @@ -0,0 +1,13 @@ +// { dg-do compile { target concepts } } + +template<class T> requires T::value struct A { }; +template<class T> requires T::value struct B { }; // { dg-error "private" } + +struct S { +private: + static constexpr bool value = true; + template<class T> requires T::value friend struct A; +}; + +A<S> x; +B<S> y; // { dg-error "constraint" } -- 2.32.0.93.g670b81a890