diff mbox series

c++: requires-expr with dependent extra args [PR101181]

Message ID 20210708152804.2235731-1-ppalka@redhat.com
State New
Headers show
Series c++: requires-expr with dependent extra args [PR101181] | expand

Commit Message

Patrick Palka July 8, 2021, 3:28 p.m. UTC
Here we're crashing ultimately because the mechanism for delaying
substitution into a requires-expression (or constexpr if) doesn't
expect to see dependent args.  But we end up capturing dependent
args here when substituting into the default template argument during
coerce_template_parms for the dependent specialization p<T>.

This patch enables the commented out code in add_extra_args for
handling this situation.  It turns out we also need to make a copy of
the captured arguments so that coerce_template_parms doesn't later
add to the argument, which would form an unexpected cycle.  And we
need to make tsubst_template_args more forgiving about missing template
arguments, since the arguments we capture from coerce_template_parms are
incomplete.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/11?

	PR c++/101181

gcc/cp/ChangeLog:

	* constraint.cc (tsubst_requires_expr): Pass complain/in_decl to
	add_extra_args.
	* cp-tree.h (add_extra_args): Add complain/in_decl parameters.
	* pt.c (build_extra_args): Make a copy of args.
	(add_extra_args): Add complain/in_decl parameters.  Handle the
	case where the extra arguments are dependent.
	(tsubst_pack_expansion): Pass complain/in_decl to
	add_extra_args.
	(tsubst_template_args): Handle missing template arguments.
	(tsubst_expr) <case IF_STMT>: Pass complain/in_decl to
	add_extra_args.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/concepts-requires26.C: New test.
	* g++.dg/cpp2a/lambda-uneval16.C: New test.
---
 gcc/cp/constraint.cc                          |  3 +-
 gcc/cp/cp-tree.h                              |  2 +-
 gcc/cp/pt.c                                   | 31 +++++++++----------
 .../g++.dg/cpp2a/concepts-requires26.C        | 18 +++++++++++
 gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C  | 22 +++++++++++++
 5 files changed, 58 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires26.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C

Comments

Jason Merrill July 8, 2021, 9:43 p.m. UTC | #1
On 7/8/21 11:28 AM, Patrick Palka wrote:
> Here we're crashing ultimately because the mechanism for delaying
> substitution into a requires-expression (or constexpr if) doesn't
> expect to see dependent args.  But we end up capturing dependent
> args here when substituting into the default template argument during
> coerce_template_parms for the dependent specialization p<T>.
> 
> This patch enables the commented out code in add_extra_args for
> handling this situation.  It turns out we also need to make a copy of
> the captured arguments so that coerce_template_parms doesn't later
> add to the argument, which would form an unexpected cycle.  And we
> need to make tsubst_template_args more forgiving about missing template
> arguments, since the arguments we capture from coerce_template_parms are
> incomplete.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk/11?
> 
> 	PR c++/101181
> 
> gcc/cp/ChangeLog:
> 
> 	* constraint.cc (tsubst_requires_expr): Pass complain/in_decl to
> 	add_extra_args.
> 	* cp-tree.h (add_extra_args): Add complain/in_decl parameters.
> 	* pt.c (build_extra_args): Make a copy of args.
> 	(add_extra_args): Add complain/in_decl parameters.  Handle the
> 	case where the extra arguments are dependent.
> 	(tsubst_pack_expansion): Pass complain/in_decl to
> 	add_extra_args.
> 	(tsubst_template_args): Handle missing template arguments.
> 	(tsubst_expr) <case IF_STMT>: Pass complain/in_decl to
> 	add_extra_args.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp2a/concepts-requires26.C: New test.
> 	* g++.dg/cpp2a/lambda-uneval16.C: New test.
> ---
>   gcc/cp/constraint.cc                          |  3 +-
>   gcc/cp/cp-tree.h                              |  2 +-
>   gcc/cp/pt.c                                   | 31 +++++++++----------
>   .../g++.dg/cpp2a/concepts-requires26.C        | 18 +++++++++++
>   gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C  | 22 +++++++++++++
>   5 files changed, 58 insertions(+), 18 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires26.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 99d3ccc6998..4ee5215df50 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -2266,7 +2266,8 @@ tsubst_requires_expr (tree t, tree args, sat_info info)
>     /* A requires-expression is an unevaluated context.  */
>     cp_unevaluated u;
>   
> -  args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args);
> +  args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args,
> +			 info.complain, info.in_decl);
>     if (processing_template_decl)
>       {
>         /* We're partially instantiating a generic lambda.  Substituting into
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 58da7460001..0a5f13489cc 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7289,7 +7289,7 @@ extern void add_mergeable_specialization        (bool is_decl, bool is_alias,
>   						 tree outer, unsigned);
>   extern tree add_to_template_args		(tree, tree);
>   extern tree add_outermost_template_args		(tree, tree);
> -extern tree add_extra_args			(tree, tree);
> +extern tree add_extra_args			(tree, tree, tsubst_flags_t, tree);
>   extern tree build_extra_args			(tree, tree, tsubst_flags_t);
>   
>   /* in rtti.c */
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 06116d16887..e4bdac087ad 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -12928,7 +12928,9 @@ extract_local_specs (tree pattern, tsubst_flags_t complain)
>   tree
>   build_extra_args (tree pattern, tree args, tsubst_flags_t complain)
>   {
> -  tree extra = args;
> +  /* Make a copy of the extra arguments so that they won't get changed
> +     from under us.  */
> +  tree extra = copy_template_args (args);
>     if (local_specializations)
>       if (tree locals = extract_local_specs (pattern, complain))
>         extra = tree_cons (NULL_TREE, extra, locals);
> @@ -12939,7 +12941,7 @@ build_extra_args (tree pattern, tree args, tsubst_flags_t complain)
>      normal template args to ARGS.  */
>   
>   tree
> -add_extra_args (tree extra, tree args)
> +add_extra_args (tree extra, tree args, tsubst_flags_t complain, tree in_decl)
>   {
>     if (extra && TREE_CODE (extra) == TREE_LIST)
>       {
> @@ -12959,20 +12961,14 @@ add_extra_args (tree extra, tree args)
>         gcc_assert (!TREE_PURPOSE (extra));
>         extra = TREE_VALUE (extra);
>       }
> -#if 1
> -  /* I think we should always be able to substitute dependent args into the
> -     pattern.  If that turns out to be incorrect in some cases, enable the
> -     alternate code (and add complain/in_decl parms to this function).  */

Ah, because these cases aren't pack expansions, so we aren't trying to 
do the substitution; I wonder if it would be feasible to do so.  But 
this approach is probably simpler.  OK.

> -  gcc_checking_assert (!uses_template_parms (extra));
> -#else
> -  if (!uses_template_parms (extra))
> +  if (uses_template_parms (extra))
>       {
> -      gcc_unreachable ();
> +      /* This can happen during dependent substitution into a requires-expr
> +	 or a lambda that uses constexpr if.  */
>         extra = tsubst_template_args (extra, args, complain, in_decl);
>         args = add_outermost_template_args (args, extra);
>       }
>     else
> -#endif
>       args = add_to_template_args (extra, args);
>     return args;
>   }
> @@ -12998,7 +12994,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
>     pattern = PACK_EXPANSION_PATTERN (t);
>   
>     /* Add in any args remembered from an earlier partial instantiation.  */
> -  args = add_extra_args (PACK_EXPANSION_EXTRA_ARGS (t), args);
> +  args = add_extra_args (PACK_EXPANSION_EXTRA_ARGS (t), args, complain, in_decl);
>   
>     levels = TMPL_ARGS_DEPTH (args);
>   
> @@ -13370,7 +13366,9 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>         tree orig_arg = TREE_VEC_ELT (t, i);
>         tree new_arg;
>   
> -      if (TREE_CODE (orig_arg) == TREE_VEC)
> +      if (!orig_arg)
> +	new_arg = NULL_TREE;
> +      else if (TREE_CODE (orig_arg) == TREE_VEC)
>   	new_arg = tsubst_template_args (orig_arg, args, complain, in_decl);
>         else if (PACK_EXPANSION_P (orig_arg))
>           {
> @@ -13420,8 +13418,9 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>       }
>     for (i = 0, out = 0; i < len; i++)
>       {
> -      if ((PACK_EXPANSION_P (TREE_VEC_ELT (orig_t, i))
> -           || ARGUMENT_PACK_P (TREE_VEC_ELT (orig_t, i)))
> +      tree orig_arg = TREE_VEC_ELT (orig_t, i);
> +      if (orig_arg
> +	  && (PACK_EXPANSION_P (orig_arg) || ARGUMENT_PACK_P (orig_arg))
>             && TREE_CODE (elts[i]) == TREE_VEC)
>           {
>             int idx;
> @@ -18449,7 +18448,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
>         IF_STMT_CONSTEXPR_P (stmt) = IF_STMT_CONSTEXPR_P (t);
>         IF_STMT_CONSTEVAL_P (stmt) = IF_STMT_CONSTEVAL_P (t);
>         if (IF_STMT_CONSTEXPR_P (t))
> -	args = add_extra_args (IF_STMT_EXTRA_ARGS (t), args);
> +	args = add_extra_args (IF_STMT_EXTRA_ARGS (t), args, complain, in_decl);
>         tmp = RECUR (IF_COND (t));
>         tmp = finish_if_stmt_cond (tmp, stmt);
>         if (IF_STMT_CONSTEXPR_P (t)
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires26.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires26.C
> new file mode 100644
> index 00000000000..824d23431f0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires26.C
> @@ -0,0 +1,18 @@
> +// PR c++/101181
> +// { dg-do compile { target c++20 } }
> +
> +template<class T,
> +	 bool = requires { typename T::type; }>
> +struct p { using type = void; };
> +
> +template<class T>
> +struct p<T, true> { using type = typename T::type; };
> +
> +template<class T> using P = typename p<T>::type;
> +
> +using type1 = P<int>;
> +using type1 = void;
> +
> +struct A { using type = char; };
> +using type2 = P<A>;
> +using type2 = char;
> diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C
> new file mode 100644
> index 00000000000..1113c6f02b9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C
> @@ -0,0 +1,22 @@
> +// PR c++/101181
> +// { dg-do compile { target c++20 } }
> +
> +template<class T,
> +	 bool = [] () -> bool {
> +	   if constexpr (requires { typename T::type; })
> +	     return true;
> +	   return false;
> +	 }()>
> +struct p { using type = void; };
> +
> +template<class T>
> +struct p<T, true> { using type = typename T::type; };
> +
> +template<class T> using P = typename p<T>::type;
> +
> +using type1 = P<int>;
> +using type = void;
> +
> +struct A { using type = char; };
> +using type2 = P<A>;
> +using type2 = char;
>
Patrick Palka July 9, 2021, 2:10 p.m. UTC | #2
On Thu, 8 Jul 2021, Jason Merrill wrote:

> On 7/8/21 11:28 AM, Patrick Palka wrote:
> > Here we're crashing ultimately because the mechanism for delaying
> > substitution into a requires-expression (or constexpr if) doesn't
> > expect to see dependent args.  But we end up capturing dependent
> > args here when substituting into the default template argument during
> > coerce_template_parms for the dependent specialization p<T>.
> > 
> > This patch enables the commented out code in add_extra_args for
> > handling this situation.  It turns out we also need to make a copy of
> > the captured arguments so that coerce_template_parms doesn't later
> > add to the argument, which would form an unexpected cycle.  And we
> > need to make tsubst_template_args more forgiving about missing template
> > arguments, since the arguments we capture from coerce_template_parms are
> > incomplete.
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk/11?
> > 
> > 	PR c++/101181
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* constraint.cc (tsubst_requires_expr): Pass complain/in_decl to
> > 	add_extra_args.
> > 	* cp-tree.h (add_extra_args): Add complain/in_decl parameters.
> > 	* pt.c (build_extra_args): Make a copy of args.
> > 	(add_extra_args): Add complain/in_decl parameters.  Handle the
> > 	case where the extra arguments are dependent.
> > 	(tsubst_pack_expansion): Pass complain/in_decl to
> > 	add_extra_args.
> > 	(tsubst_template_args): Handle missing template arguments.
> > 	(tsubst_expr) <case IF_STMT>: Pass complain/in_decl to
> > 	add_extra_args.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/cpp2a/concepts-requires26.C: New test.
> > 	* g++.dg/cpp2a/lambda-uneval16.C: New test.
> > ---
> >   gcc/cp/constraint.cc                          |  3 +-
> >   gcc/cp/cp-tree.h                              |  2 +-
> >   gcc/cp/pt.c                                   | 31 +++++++++----------
> >   .../g++.dg/cpp2a/concepts-requires26.C        | 18 +++++++++++
> >   gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C  | 22 +++++++++++++
> >   5 files changed, 58 insertions(+), 18 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires26.C
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C
> > 
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index 99d3ccc6998..4ee5215df50 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -2266,7 +2266,8 @@ tsubst_requires_expr (tree t, tree args, sat_info
> > info)
> >     /* A requires-expression is an unevaluated context.  */
> >     cp_unevaluated u;
> >   -  args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args);
> > +  args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args,
> > +			 info.complain, info.in_decl);
> >     if (processing_template_decl)
> >       {
> >         /* We're partially instantiating a generic lambda.  Substituting
> > into
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index 58da7460001..0a5f13489cc 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -7289,7 +7289,7 @@ extern void add_mergeable_specialization        (bool
> > is_decl, bool is_alias,
> >   						 tree outer, unsigned);
> >   extern tree add_to_template_args		(tree, tree);
> >   extern tree add_outermost_template_args		(tree, tree);
> > -extern tree add_extra_args			(tree, tree);
> > +extern tree add_extra_args			(tree, tree, tsubst_flags_t,
> > tree);
> >   extern tree build_extra_args			(tree, tree,
> > tsubst_flags_t);
> >     /* in rtti.c */
> > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> > index 06116d16887..e4bdac087ad 100644
> > --- a/gcc/cp/pt.c
> > +++ b/gcc/cp/pt.c
> > @@ -12928,7 +12928,9 @@ extract_local_specs (tree pattern, tsubst_flags_t
> > complain)
> >   tree
> >   build_extra_args (tree pattern, tree args, tsubst_flags_t complain)
> >   {
> > -  tree extra = args;
> > +  /* Make a copy of the extra arguments so that they won't get changed
> > +     from under us.  */
> > +  tree extra = copy_template_args (args);
> >     if (local_specializations)
> >       if (tree locals = extract_local_specs (pattern, complain))
> >         extra = tree_cons (NULL_TREE, extra, locals);
> > @@ -12939,7 +12941,7 @@ build_extra_args (tree pattern, tree args,
> > tsubst_flags_t complain)
> >      normal template args to ARGS.  */
> >     tree
> > -add_extra_args (tree extra, tree args)
> > +add_extra_args (tree extra, tree args, tsubst_flags_t complain, tree
> > in_decl)
> >   {
> >     if (extra && TREE_CODE (extra) == TREE_LIST)
> >       {
> > @@ -12959,20 +12961,14 @@ add_extra_args (tree extra, tree args)
> >         gcc_assert (!TREE_PURPOSE (extra));
> >         extra = TREE_VALUE (extra);
> >       }
> > -#if 1
> > -  /* I think we should always be able to substitute dependent args into the
> > -     pattern.  If that turns out to be incorrect in some cases, enable the
> > -     alternate code (and add complain/in_decl parms to this function).  */
> 
> Ah, because these cases aren't pack expansions, so we aren't trying to do the
> substitution; I wonder if it would be feasible to do so.  But this approach is
> probably simpler.  OK.

For constexpr if, it seems feasible/safe to do the substitution by
setting tf_partial when the arguments are dependent.

But for requires-exprs, if one of the arguments is non-dependent then
doing the substitution could cause us to evaluate the requirements out
of order.  So this current approach might be better for requires-exprs
since it avoids out-of-order evaluation.
diff mbox series

Patch

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 99d3ccc6998..4ee5215df50 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2266,7 +2266,8 @@  tsubst_requires_expr (tree t, tree args, sat_info info)
   /* A requires-expression is an unevaluated context.  */
   cp_unevaluated u;
 
-  args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args);
+  args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args,
+			 info.complain, info.in_decl);
   if (processing_template_decl)
     {
       /* We're partially instantiating a generic lambda.  Substituting into
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 58da7460001..0a5f13489cc 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7289,7 +7289,7 @@  extern void add_mergeable_specialization        (bool is_decl, bool is_alias,
 						 tree outer, unsigned);
 extern tree add_to_template_args		(tree, tree);
 extern tree add_outermost_template_args		(tree, tree);
-extern tree add_extra_args			(tree, tree);
+extern tree add_extra_args			(tree, tree, tsubst_flags_t, tree);
 extern tree build_extra_args			(tree, tree, tsubst_flags_t);
 
 /* in rtti.c */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 06116d16887..e4bdac087ad 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12928,7 +12928,9 @@  extract_local_specs (tree pattern, tsubst_flags_t complain)
 tree
 build_extra_args (tree pattern, tree args, tsubst_flags_t complain)
 {
-  tree extra = args;
+  /* Make a copy of the extra arguments so that they won't get changed
+     from under us.  */
+  tree extra = copy_template_args (args);
   if (local_specializations)
     if (tree locals = extract_local_specs (pattern, complain))
       extra = tree_cons (NULL_TREE, extra, locals);
@@ -12939,7 +12941,7 @@  build_extra_args (tree pattern, tree args, tsubst_flags_t complain)
    normal template args to ARGS.  */
 
 tree
-add_extra_args (tree extra, tree args)
+add_extra_args (tree extra, tree args, tsubst_flags_t complain, tree in_decl)
 {
   if (extra && TREE_CODE (extra) == TREE_LIST)
     {
@@ -12959,20 +12961,14 @@  add_extra_args (tree extra, tree args)
       gcc_assert (!TREE_PURPOSE (extra));
       extra = TREE_VALUE (extra);
     }
-#if 1
-  /* I think we should always be able to substitute dependent args into the
-     pattern.  If that turns out to be incorrect in some cases, enable the
-     alternate code (and add complain/in_decl parms to this function).  */
-  gcc_checking_assert (!uses_template_parms (extra));
-#else
-  if (!uses_template_parms (extra))
+  if (uses_template_parms (extra))
     {
-      gcc_unreachable ();
+      /* This can happen during dependent substitution into a requires-expr
+	 or a lambda that uses constexpr if.  */
       extra = tsubst_template_args (extra, args, complain, in_decl);
       args = add_outermost_template_args (args, extra);
     }
   else
-#endif
     args = add_to_template_args (extra, args);
   return args;
 }
@@ -12998,7 +12994,7 @@  tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
   pattern = PACK_EXPANSION_PATTERN (t);
 
   /* Add in any args remembered from an earlier partial instantiation.  */
-  args = add_extra_args (PACK_EXPANSION_EXTRA_ARGS (t), args);
+  args = add_extra_args (PACK_EXPANSION_EXTRA_ARGS (t), args, complain, in_decl);
 
   levels = TMPL_ARGS_DEPTH (args);
 
@@ -13370,7 +13366,9 @@  tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       tree orig_arg = TREE_VEC_ELT (t, i);
       tree new_arg;
 
-      if (TREE_CODE (orig_arg) == TREE_VEC)
+      if (!orig_arg)
+	new_arg = NULL_TREE;
+      else if (TREE_CODE (orig_arg) == TREE_VEC)
 	new_arg = tsubst_template_args (orig_arg, args, complain, in_decl);
       else if (PACK_EXPANSION_P (orig_arg))
         {
@@ -13420,8 +13418,9 @@  tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     }
   for (i = 0, out = 0; i < len; i++)
     {
-      if ((PACK_EXPANSION_P (TREE_VEC_ELT (orig_t, i))
-           || ARGUMENT_PACK_P (TREE_VEC_ELT (orig_t, i)))
+      tree orig_arg = TREE_VEC_ELT (orig_t, i);
+      if (orig_arg
+	  && (PACK_EXPANSION_P (orig_arg) || ARGUMENT_PACK_P (orig_arg))
           && TREE_CODE (elts[i]) == TREE_VEC)
         {
           int idx;
@@ -18449,7 +18448,7 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
       IF_STMT_CONSTEXPR_P (stmt) = IF_STMT_CONSTEXPR_P (t);
       IF_STMT_CONSTEVAL_P (stmt) = IF_STMT_CONSTEVAL_P (t);
       if (IF_STMT_CONSTEXPR_P (t))
-	args = add_extra_args (IF_STMT_EXTRA_ARGS (t), args);
+	args = add_extra_args (IF_STMT_EXTRA_ARGS (t), args, complain, in_decl);
       tmp = RECUR (IF_COND (t));
       tmp = finish_if_stmt_cond (tmp, stmt);
       if (IF_STMT_CONSTEXPR_P (t)
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires26.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires26.C
new file mode 100644
index 00000000000..824d23431f0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires26.C
@@ -0,0 +1,18 @@ 
+// PR c++/101181
+// { dg-do compile { target c++20 } }
+
+template<class T,
+	 bool = requires { typename T::type; }>
+struct p { using type = void; };
+
+template<class T>
+struct p<T, true> { using type = typename T::type; };
+
+template<class T> using P = typename p<T>::type;
+
+using type1 = P<int>;
+using type1 = void;
+
+struct A { using type = char; };
+using type2 = P<A>;
+using type2 = char;
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C
new file mode 100644
index 00000000000..1113c6f02b9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval16.C
@@ -0,0 +1,22 @@ 
+// PR c++/101181
+// { dg-do compile { target c++20 } }
+
+template<class T,
+	 bool = [] () -> bool {
+	   if constexpr (requires { typename T::type; })
+	     return true;
+	   return false;
+	 }()>
+struct p { using type = void; };
+
+template<class T>
+struct p<T, true> { using type = typename T::type; };
+
+template<class T> using P = typename p<T>::type;
+
+using type1 = P<int>;
+using type = void;
+
+struct A { using type = char; };
+using type2 = P<A>;
+using type2 = char;