On Wed, 10 Apr 2024, Jason Merrill wrote:

> On 3/12/24 10:51, Patrick Palka wrote:
> > On Tue, 12 Mar 2024, Patrick Palka wrote:
> > > On Tue, 12 Mar 2024, Jason Merrill wrote:
> > > > On 3/11/24 12:53, Patrick Palka wrote:
> > > > > 
> > > > > r13-6452-g341e6cd8d603a3 made build_extra_args walk evaluated contexts
> > > > > first so that we prefer processing a local specialization in an
> > > > > evaluated
> > > > > context even if its first use is in an unevaluated context.  But this
> > > > > means we need to avoid walking a tree that already has extra
> > > > > args/specs
> > > > > saved because the list of saved specs appears to be an evaluated
> > > > > context.  It seems then that we should be calculating the saved specs
> > > > > from scratch each time, rather than potentially walking the saved
> > > > > specs
> > > > > list from an earlier partial instantiation when calling
> > > > > build_extra_args
> > > > > a second time around.
> > > > 
> > > > Makes sense, but I wonder if we want to approach that by avoiding
> > > > walking into
> > > > *_EXTRA_ARGS in extract_locals_r?  Or do we still want to walk into any
> > > > nested
> > > > extra args?  And if so, will we run into this same problem then?
> > > 
> > > I'm not sure totally but I'd expect a nested extra-args tree to always
> > > have empty *_EXTRA_ARGS since the outer extra-args tree should intercept
> > > any substitution before the inner extra-args tree can see it?
> > 
> > ... and so in extract_locals_r I think we can assume *_EXTRA_ARGS is
> > empty, and not have to explicitly avoid walking it.
> 
> It seems more robust to me to handle _EXTRA_ARGS appropriately in
> build_extra_args rather than expect callers to know that they shouldn't pass
> in a tree with _EXTRA_ARGS set.  At least check and abort in that case?

Sounds good.  That IMHO seems simpler than actually avoiding walking
into *_EXTRA_ARGS from extract_locals_r because we'd have to repeat
the walking logic from cp_walk_subtree modulo the *_EXTRA_ARGS walk.

How does the following look? Bootstraped and regtested on
x86_64-pc-linux-gnu.

-- > 8--

Subject: [PATCH] c++: build_extra_args recapturing local specs [PR114303]

        PR c++/114303

gcc/cp/ChangeLog:

        * constraint.cc (tsubst_requires_expr): Clear
        REQUIRES_EXPR_EXTRA_ARGS before calling build_extra_args.
        * pt.cc (extract_locals_r): Assert *_EXTRA_ARGS is empty.
        (tsubst_stmt) <case IF_STMT>: Call build_extra_args
        on the new IF_STMT instead of t which might already have
        IF_STMT_EXTRA_ARGS.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp1z/constexpr-if-lambda6.C: New test.
---
 gcc/cp/constraint.cc                             |  1 +
 gcc/cp/pt.cc                                     | 16 +++++++++++++++-
 .../g++.dg/cpp1z/constexpr-if-lambda6.C          | 16 ++++++++++++++++
 3 files changed, 32 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 49de3211d4c..8a3b5d80ba7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2362,6 +2362,7 @@ tsubst_requires_expr (tree t, tree args, sat_info info)
         matching or dguide constraint rewriting), in which case we need
         to partially substitute.  */
       t = copy_node (t);
+      REQUIRES_EXPR_EXTRA_ARGS (t) = NULL_TREE;
       REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain);
       return t;
     }
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index c38594cd862..6cc9b95fc06 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -13310,6 +13310,19 @@ extract_locals_r (tree *tp, int *walk_subtrees, void 
*data_)
     /* Remember local typedefs (85214).  */
     tp = &TYPE_NAME (*tp);
 
+  if (has_extra_args_mechanism_p (*tp))
+    {
+      if (PACK_EXPANSION_P (*tp))
+       gcc_checking_assert (!PACK_EXPANSION_EXTRA_ARGS (*tp));
+      else if (TREE_CODE (*tp) == REQUIRES_EXPR)
+       gcc_checking_assert (!REQUIRES_EXPR_EXTRA_ARGS (*tp));
+      else if (TREE_CODE (*tp) == IF_STMT
+              && IF_STMT_CONSTEXPR_P (*tp))
+       gcc_checking_assert (!IF_STMT_EXTRA_ARGS (*tp));
+      else
+       gcc_unreachable ();
+    }
+
   if (TREE_CODE (*tp) == DECL_EXPR)
     {
       tree decl = DECL_EXPR_DECL (*tp);
@@ -18738,7 +18751,8 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
          IF_COND (stmt) = IF_COND (t);
          THEN_CLAUSE (stmt) = THEN_CLAUSE (t);
          ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t);
-         IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain);
+         IF_SCOPE (stmt) = NULL_TREE;
+         IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (stmt, args, complain);
          add_stmt (stmt);
          break;
        }
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
new file mode 100644
index 00000000000..038c2a41210
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
@@ -0,0 +1,16 @@
+// PR c++/114303
+// { dg-do compile { target c++17 } }
+
+struct A { static constexpr bool value = true; };
+
+int main() {
+  [](auto x1) {
+    return [&](auto) {
+      return [&](auto x3) {
+        if constexpr (decltype(x3)::value) {
+          static_assert(decltype(x1)::value);
+        }
+      }(A{});
+    }(0);
+  }(A{});
+}
-- 
2.44.0.548.g91ec36f2cc

Reply via email to