diff options
author | Patrick Palka <ppalka@redhat.com> | 2021-06-30 13:12:36 -0400 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2021-06-30 13:12:36 -0400 |
commit | c28e1d288ab727de6eb493e1aa2eadf5d5eef3ab (patch) | |
tree | e345163ba2fd085640f5288911c6c2bbe91fe8f1 /gcc | |
parent | b5bb7f328d56cccfb85932ff586138e5a4ef1436 (diff) | |
download | gcc-c28e1d288ab727de6eb493e1aa2eadf5d5eef3ab.zip gcc-c28e1d288ab727de6eb493e1aa2eadf5d5eef3ab.tar.gz gcc-c28e1d288ab727de6eb493e1aa2eadf5d5eef3ab.tar.bz2 |
c++: Fix push_access_scope and introduce RAII wrapper for it
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 make use of this wrapper right away by
replacing the only user of push_nested_class_guard with this new
wrapper, which means we can remove push_nested_class_guard (whose
functionality is basically subsumed by the new wrapper).
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.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/constraint.cc | 7 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 23 | ||||
-rw-r--r-- | gcc/cp/pt.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/concepts-access2.C | 13 |
4 files changed, 33 insertions, 17 deletions
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 6df3ca6..99d3ccc 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 6f71371..58da746 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 d2936c1..f8f7616 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 0000000..8ddcad2 --- /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" } |