public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
From: Patrick Palka <ppalka@gcc.gnu.org>
To: gcc-cvs@gcc.gnu.org
Subject: [gcc r13-4730] c++: extract_local_specs and unevaluated contexts [PR100295]
Date: Thu, 15 Dec 2022 21:03:03 +0000 (GMT)	[thread overview]
Message-ID: <20221215210303.3A9E6388DD43@sourceware.org> (raw)

https://gcc.gnu.org/g:18499b9f848707aee42d810e99ac0a4c9788433c

commit r13-4730-g18499b9f848707aee42d810e99ac0a4c9788433c
Author: Patrick Palka <ppalka@redhat.com>
Date:   Thu Dec 15 16:02:05 2022 -0500

    c++: extract_local_specs and unevaluated contexts [PR100295]
    
    Here during partial instantiation of the constexpr if, extra_local_specs
    walks the statement looking for local specializations within to capture.
    However, we're thwarted by the fact that 'ts' first appears inside an
    unevaluated context, and so the calls to process_outer_var_ref for its
    local specializations are a no-op.  And since we walk each tree exactly
    once, we end up not capturing the local specializations despite 'ts'
    later occurring in an evaluated context.
    
    This patch fixes this by making extract_local_specs walk evaluated
    contexts first before walking unevaluated contexts.  We could probably
    get away with not walking unevaluated contexts at all, but this approach
    seems more clearly safe.
    
            PR c++/100295
            PR c++/107579
    
    gcc/cp/ChangeLog:
    
            * pt.cc (el_data::skip_unevaluated_operands): New data member.
            (extract_locals_r): If skip_unevaluated_operands is true,
            don't walk into unevaluated contexts.
            (extract_local_specs): Walk the pattern twice, first with
            skip_unevaluated_operands true followed by it set to false.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp1z/constexpr-if-lambda5.C: New test.

Diff:
---
 gcc/cp/pt.cc                                      | 19 ++++++++++++++++++-
 gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda5.C | 15 +++++++++++++++
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 38e3a1672c1..b9933ec6e06 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -13016,17 +13016,26 @@ public:
   /* List of local_specializations used within the pattern.  */
   tree extra;
   tsubst_flags_t complain;
+  /* True iff we don't want to walk into unevaluated contexts.  */
+  bool skip_unevaluated_operands = false;
 
   el_data (tsubst_flags_t c)
     : extra (NULL_TREE), complain (c) {}
 };
 static tree
-extract_locals_r (tree *tp, int */*walk_subtrees*/, void *data_)
+extract_locals_r (tree *tp, int *walk_subtrees, void *data_)
 {
   el_data &data = *reinterpret_cast<el_data*>(data_);
   tree *extra = &data.extra;
   tsubst_flags_t complain = data.complain;
 
+  if (data.skip_unevaluated_operands
+      && unevaluated_p (TREE_CODE (*tp)))
+    {
+      *walk_subtrees = 0;
+      return NULL_TREE;
+    }
+
   if (TYPE_P (*tp) && typedef_variant_p (*tp))
     /* Remember local typedefs (85214).  */
     tp = &TYPE_NAME (*tp);
@@ -13118,6 +13127,14 @@ static tree
 extract_local_specs (tree pattern, tsubst_flags_t complain)
 {
   el_data data (complain);
+  /* Walk the pattern twice, ignoring unevaluated operands the first time
+     around, so that if a local specialization appears in both an evaluated
+     and unevaluated context we prefer to process it in the evaluated context
+     (since e.g. process_outer_var_ref is a no-op inside an unevaluated
+     context).  */
+  data.skip_unevaluated_operands = true;
+  cp_walk_tree (&pattern, extract_locals_r, &data, &data.visited);
+  data.skip_unevaluated_operands = false;
   cp_walk_tree (&pattern, extract_locals_r, &data, &data.visited);
   return data.extra;
 }
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda5.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda5.C
new file mode 100644
index 00000000000..d2bf0221743
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda5.C
@@ -0,0 +1,15 @@
+// PR c++/100295
+// { dg-do compile { target c++17 } }
+
+template<typename... Ts>
+void f(Ts... ts) {
+  auto lambda = [=](auto x) {
+    if constexpr (sizeof((ts+x) + ...) != 0)
+      (..., ts);
+  };
+  lambda(0);
+}
+
+int main() {
+  f(0, 'a');
+}

                 reply	other threads:[~2022-12-15 21:03 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221215210303.3A9E6388DD43@sourceware.org \
    --to=ppalka@gcc.gnu.org \
    --cc=gcc-cvs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).