aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2021-08-11 16:53:53 -0400
committerPatrick Palka <ppalka@redhat.com>2021-08-11 16:53:53 -0400
commit9707d2e5dbb92d2bc990c922461a5a16ae652319 (patch)
tree0c36cbadf41c64bdcb4cc6f4bb66e1d0eb42c68d
parentee8f9ff00d79998274c967ad0c23692be9dd3ada (diff)
downloadgcc-9707d2e5dbb92d2bc990c922461a5a16ae652319.zip
gcc-9707d2e5dbb92d2bc990c922461a5a16ae652319.tar.gz
gcc-9707d2e5dbb92d2bc990c922461a5a16ae652319.tar.bz2
c++: parameterized requires-expr as default argument [PR101725]
Here we're rejecting the default template argument requires (T t) { x(t); } because we consider the 't' in the requirement to be a local variable (according to local_variable_p), and we generally forbid local variables from appearing inside default arguments. We can perhaps fix this by giving special treatment to parameters introduced by requires-expressions, but DR 2082 relaxed the restriction about local variables appearing within default arguments to permit them inside unevaluated operands thereof. So this patch just implements DR 2082 which also fixes this PR since a requires-expression is an unevaluated context. PR c++/101725 DR 2082 gcc/cp/ChangeLog: * cp-tree.h (unevaluated_p): Return true for REQUIRES_EXPR. * decl.c (local_variable_p_walkfn): Don't walk into unevaluated operands. * parser.c (cp_parser_primary_expression) <case CPP_NAME>: Never reject uses of local variables in unevaluated contexts. * tree.c (cp_walk_subtrees) <case REQUIRES_EXPR>: Increment cp_unevaluated_operand. Use cp_walk_tree directly instead of WALK_SUBTREE to avoid the goto. Use REQUIRES_EXPR_REQS instead of TREE_OPERAND directly. gcc/testsuite/ChangeLog: * g++.dg/DRs/dr2082.C: New test. * g++.dg/cpp2a/concepts-uneval4.C: New test.
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/decl.c8
-rw-r--r--gcc/cp/parser.c5
-rw-r--r--gcc/cp/tree.c4
-rw-r--r--gcc/testsuite/g++.dg/DRs/dr2082.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-uneval4.C12
6 files changed, 41 insertions, 3 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9a47a87..6a8264b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8494,7 +8494,8 @@ unevaluated_p (tree_code code)
return (code == DECLTYPE_TYPE
|| code == ALIGNOF_EXPR
|| code == SIZEOF_EXPR
- || code == NOEXCEPT_EXPR);
+ || code == NOEXCEPT_EXPR
+ || code == REQUIRES_EXPR);
}
/* RAII class to push/pop the access scope for T. */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index f626f1e..b3671ee 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -14270,6 +14270,14 @@ static tree
local_variable_p_walkfn (tree *tp, int *walk_subtrees,
void * /*data*/)
{
+ if (unevaluated_p (TREE_CODE (*tp)))
+ {
+ /* DR 2082 permits local variables in unevaluated contexts
+ within a default argument. */
+ *walk_subtrees = 0;
+ return NULL_TREE;
+ }
+
if (local_variable_p (*tp)
&& (!DECL_ARTIFICIAL (*tp) || DECL_NAME (*tp) == this_identifier))
return *tp;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index b5e117d..d564e3b 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5989,7 +5989,10 @@ cp_parser_primary_expression (cp_parser *parser,
/* Check to see if DECL is a local variable in a context
where that is forbidden. */
if ((parser->local_variables_forbidden_p & LOCAL_VARS_FORBIDDEN)
- && local_variable_p (decl))
+ && local_variable_p (decl)
+ /* DR 2082 permits local variables in unevaluated contexts
+ within a default argument. */
+ && !cp_unevaluated_operand)
{
const char *msg
= (TREE_CODE (decl) == PARM_DECL
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 8345396..e8831b2 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -5386,7 +5386,9 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
// walk the parameter list. Doing so causes false
// positives in the pack expansion checker since the
// requires parameters are introduced as pack expansions.
- WALK_SUBTREE (TREE_OPERAND (*tp, 1));
+ ++cp_unevaluated_operand;
+ result = cp_walk_tree (&REQUIRES_EXPR_REQS (*tp), func, data, pset);
+ --cp_unevaluated_operand;
*walk_subtrees_p = 0;
break;
diff --git a/gcc/testsuite/g++.dg/DRs/dr2082.C b/gcc/testsuite/g++.dg/DRs/dr2082.C
new file mode 100644
index 0000000..84bb23f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/DRs/dr2082.C
@@ -0,0 +1,12 @@
+// DR 2082
+
+void f() {
+ int i;
+ extern void h(int x = sizeof(i));
+}
+
+class A {
+ void f(A* p = this) { } // { dg-error "this" }
+};
+
+int h(int a, int b = sizeof(a));
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-uneval4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-uneval4.C
new file mode 100644
index 0000000..1be27d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-uneval4.C
@@ -0,0 +1,12 @@
+// PR c++/101725
+// { dg-do compile { target c++20 } }
+
+template<class T, bool V = requires (T t) { x(t); }> void f();
+
+struct A {
+ int m;
+ void f(int a, int b = requires (int t) { a + m + t; });
+};
+
+void g();
+static_assert(noexcept(requires { g(); }));