public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-3488] c++: parameter pack inside constexpr if [PR101764]
@ 2021-09-13 14:31 Patrick Palka
  0 siblings, 0 replies; only message in thread
From: Patrick Palka @ 2021-09-13 14:31 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:c8b2b89358481d36755dbc99e585a251780453b0

commit r12-3488-gc8b2b89358481d36755dbc99e585a251780453b0
Author: Patrick Palka <ppalka@redhat.com>
Date:   Mon Sep 13 10:29:32 2021 -0400

    c++: parameter pack inside constexpr if [PR101764]
    
    Here when partially instantiating the first pack expansion, substitution
    into the condition of the constexpr if yields a still-dependent tree, so
    tsubst_expr returns an IF_STMT with an unsubstituted IF_COND and with
    IF_STMT_EXTRA_ARGS added to.  Hence after partial instantiation the pack
    expansion pattern still refers to the unlowered parameter pack 'ts' of
    level 2, and it's thusly recorded in the new PACK_EXPANSION_PARAMETER_PACKS.
    During the subsequent final instantiation of the regenerated lambda we
    crash in tsubst_pack_expansion because it can't find an argument pack
    for this unlowered 'ts', due to the level mismatch.  (Likewise when the
    constexpr if is replaced by a requires-expr, which also uses the extra
    args mechanism for avoiding partial instantiation.)
    
    So essentially, a pack expansion pattern that contains an "extra args"
    tree doesn't play well with partial instantiation.  This patch fixes
    this by forcing such pack expansions to use the extra args mechanism as
    well.
    
            PR c++/101764
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (PACK_EXPANSION_FORCE_EXTRA_ARGS_P): New accessor
            macro.
            * pt.c (has_extra_args_mechanism_p): New function.
            (find_parameter_pack_data::found_extra_args_tree_p): New data
            member.
            (find_parameter_packs_r): Set ppd->found_extra_args_tree_p
            appropriately.
            (make_pack_expansion): Set PACK_EXPANSION_FORCE_EXTRA_ARGS_P if
            ppd.found_extra_args_tree_p.
            (use_pack_expansion_extra_args_p): Return true if there were
            unsubstituted packs and PACK_EXPANSION_FORCE_EXTRA_ARGS_P.
            (tsubst_pack_expansion): Pass the pack expansion to
            use_pack_expansion_extra_args_p.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp1z/constexpr-if35.C: New test.

Diff:
---
 gcc/cp/cp-tree.h                            |  5 +++++
 gcc/cp/pt.c                                 | 35 +++++++++++++++++++++++++++--
 gcc/testsuite/g++.dg/cpp1z/constexpr-if35.C | 18 +++++++++++++++
 3 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ceb53591926..a82747ca627 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -493,6 +493,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       CONSTRUCTOR_C99_COMPOUND_LITERAL (in CONSTRUCTOR)
       OVL_NESTED_P (in OVERLOAD)
       DECL_MODULE_EXPORT_P (in _DECL)
+      PACK_EXPANSION_FORCE_EXTRA_ARGS_P (in *_PACK_EXPANSION)
    4: IDENTIFIER_MARKED (IDENTIFIER_NODEs)
       TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
 	  CALL_EXPR, or FIELD_DECL).
@@ -3903,6 +3904,10 @@ struct GTY(()) lang_decl {
 /* True iff this pack expansion is for auto... in lambda init-capture.  */
 #define PACK_EXPANSION_AUTO_P(NODE) TREE_LANG_FLAG_2 (NODE)
 
+/* True if we must use PACK_EXPANSION_EXTRA_ARGS and avoid partial
+   instantiation of this pack expansion.  */
+#define PACK_EXPANSION_FORCE_EXTRA_ARGS_P(NODE) TREE_LANG_FLAG_3 (NODE)
+
 /* True iff the wildcard can match a template parameter pack.  */
 #define WILDCARD_PACK_P(NODE) TREE_LANG_FLAG_0 (NODE)
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 1b81501386b..224dd9ebd2b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3855,6 +3855,18 @@ expand_builtin_pack_call (tree call, tree args, tsubst_flags_t complain,
   return NULL_TREE;
 }
 
+/* Return true if the tree T has the extra args mechanism for
+   avoiding partial instantiation.  */
+
+static bool
+has_extra_args_mechanism_p (const_tree t)
+{
+  return (PACK_EXPANSION_P (t) /* PACK_EXPANSION_EXTRA_ARGS  */
+	  || TREE_CODE (t) == REQUIRES_EXPR /* REQUIRES_EXPR_EXTRA_ARGS  */
+	  || (TREE_CODE (t) == IF_STMT
+	      && IF_STMT_CONSTEXPR_P (t))); /* IF_STMT_EXTRA_ARGS  */
+}
+
 /* Structure used to track the progress of find_parameter_packs_r.  */
 struct find_parameter_pack_data
 {
@@ -3867,6 +3879,9 @@ struct find_parameter_pack_data
 
   /* True iff we're making a type pack expansion.  */
   bool type_pack_expansion_p;
+
+  /* True iff we found a subtree that has the extra args mechanism.  */
+  bool found_extra_args_tree_p = false;
 };
 
 /* Identifies all of the argument packs that occur in a template
@@ -3968,6 +3983,9 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
       *ppd->parameter_packs = tree_cons (NULL_TREE, t, *ppd->parameter_packs);
     }
 
+  if (has_extra_args_mechanism_p (t) && !PACK_EXPANSION_P (t))
+    ppd->found_extra_args_tree_p = true;
+
   if (TYPE_P (t))
     cp_walk_tree (&TYPE_CONTEXT (t),
 		  &find_parameter_packs_r, ppd, ppd->visited);
@@ -4229,6 +4247,14 @@ make_pack_expansion (tree arg, tsubst_flags_t complain)
   PACK_EXPANSION_PARAMETER_PACKS (result) = parameter_packs;
 
   PACK_EXPANSION_LOCAL_P (result) = at_function_scope_p ();
+  if (ppd.found_extra_args_tree_p)
+    /* If the pattern of this pack expansion contains a subtree that has
+       the extra args mechanism for avoiding partial instantiation, then
+       force this pack expansion to also use extra args.  Otherwise
+       partial instantiation of this pack expansion may not lower the
+       level of some parameter packs within the pattern, which would
+       confuse tsubst_pack_expansion later (PR101764).  */
+    PACK_EXPANSION_FORCE_EXTRA_ARGS_P (result) = true;
 
   return result;
 }
@@ -12405,10 +12431,15 @@ make_argument_pack_select (tree arg_pack, unsigned index)
     substitution.  */
 
 static bool
-use_pack_expansion_extra_args_p (tree parm_packs,
+use_pack_expansion_extra_args_p (tree t,
+				 tree parm_packs,
 				 int arg_pack_len,
 				 bool has_empty_arg)
 {
+  if (has_empty_arg
+      && PACK_EXPANSION_FORCE_EXTRA_ARGS_P (t))
+    return true;
+
   /* If one pack has an expansion and another pack has a normal
      argument or if one pack has an empty argument and an another
      one hasn't then tsubst_pack_expansion cannot perform the
@@ -13161,7 +13192,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 
   /* We cannot expand this expansion expression, because we don't have
      all of the argument packs we need.  */
-  if (use_pack_expansion_extra_args_p (packs, len, unsubstituted_packs))
+  if (use_pack_expansion_extra_args_p (t, packs, len, unsubstituted_packs))
     {
       /* We got some full packs, but we can't substitute them in until we
 	 have values for all the packs.  So remember these until then.  */
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if35.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if35.C
new file mode 100644
index 00000000000..b1248fe23e8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if35.C
@@ -0,0 +1,18 @@
+// PR c++/101764
+// { dg-do compile { target c++17 } }
+
+void g(...);
+
+template<class>
+auto f() {
+  return [](auto... ts) {
+    g([] { if constexpr (sizeof(ts)); }...);
+#if __cpp_concepts
+    g(requires { decltype(ts){0}; }...);
+#endif
+  };
+}
+
+int main() {
+  f<int>()('a', true);
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-09-13 14:31 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-13 14:31 [gcc r12-3488] c++: parameter pack inside constexpr if [PR101764] Patrick Palka

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).