]> gcc.gnu.org Git - gcc.git/commitdiff
c++: parameterized requires-expr as default argument [PR101725]
authorPatrick Palka <ppalka@redhat.com>
Wed, 11 Aug 2021 20:53:53 +0000 (16:53 -0400)
committerPatrick Palka <ppalka@redhat.com>
Wed, 11 Aug 2021 20:53:53 +0000 (16:53 -0400)
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.

gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/parser.c
gcc/cp/tree.c
gcc/testsuite/g++.dg/DRs/dr2082.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/concepts-uneval4.C [new file with mode: 0644]

index 9a47a8787d6aa2520bb990fb485314e53187c2a2..6a8264b0c618a43fe7d74ad62ca2cea3d0c0b2cd 100644 (file)
@@ -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.  */
index f626f1e65ee644a494eb57fa5bcb7f1eb05ff667..b3671ee89565820bf34c133ea6cda8592ce1eeea 100644 (file)
@@ -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;
index b5e117d5bda1329f51b8aa17fcdf09c4536760e8..d564e3ba2fadc8bfdf8a5836765d33789e07b57f 100644 (file)
@@ -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
index 8345396ec33947ca0ba51da400944d2f75a87ca6..e8831b218022b9b027540165431744ed90e3d506 100644 (file)
@@ -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 (file)
index 0000000..84bb23f
--- /dev/null
@@ -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 (file)
index 0000000..1be27d1
--- /dev/null
@@ -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(); }));
This page took 0.141423 seconds and 5 git commands to generate.