On Wed, 2 Feb 2022, Patrick Palka wrote:

> Here we're crashing during satisfaction of the lambda's placeholder type
> constraints because the constraints depend on the template arguments
> from the enclosing scope, which aren't a part of the lambda's
> DECL_TI_ARGS.  So when inside a lambda, do_auto_deduction needs to add
> the "regenerating" template arguments to the set of outer template
> arguments, like we already do in satisfy_declaration_constraints.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk and perhaps 11?
> 
>       PR c++/103706
> 
> gcc/cp/ChangeLog:
> 
>       * constraint.cc (satisfy_declaration_constraints): Use
>       lambda_regenerating_args instead.
>       * cp-tree.h (lambda_regenerating_args): Declare.
>       * pt.cc (add_to_template_args): Handle NULL_TREE extra_args
>       gracefully.
>       (lambda_regenerating_args): Define, split out from
>       satisfy_declaration_constraints.
>       (do_auto_deduction): Use lambda_regenerating_args to obtain the
>       full set of outer template arguments when checking the
>       constraint on a placeholder type within a lambda.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/cpp2a/concepts-lambda18.C: New test.
> ---
>  gcc/cp/constraint.cc                          |  9 +----
>  gcc/cp/cp-tree.h                              |  1 +
>  gcc/cp/pt.cc                                  | 37 ++++++++++++++++---
>  .../g++.dg/cpp2a/concepts-lambda18.C          | 14 +++++++
>  4 files changed, 48 insertions(+), 13 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index cc4df4216ef..c41ee02b910 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3148,18 +3148,13 @@ satisfy_declaration_constraints (tree t, sat_info 
> info)
>       args = add_outermost_template_args (args, inh_ctor_targs);
>      }
>  
> -  if (regenerated_lambda_fn_p (t))
> +  if (LAMBDA_FUNCTION_P (t))
>      {
>        /* The TI_ARGS of a regenerated lambda contains only the innermost
>        set of template arguments.  Augment this with the outer template
>        arguments that were used to regenerate the lambda.  */
>        gcc_assert (!args || TMPL_ARGS_DEPTH (args) == 1);
> -      tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
> -      tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda));
> -      if (args)
> -     args = add_to_template_args (outer_args, args);
> -      else
> -     args = outer_args;
> +      args = add_to_template_args (lambda_regenerating_args (t), args);
>      }
>  
>    /* If any arguments depend on template parameters, we can't
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index b9eb71fbc3a..7a7fe5ba599 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7715,6 +7715,7 @@ extern void finish_lambda_scope                 (void);
>  extern tree start_lambda_function            (tree fn, tree lambda_expr);
>  extern void finish_lambda_function           (tree body);
>  extern bool regenerated_lambda_fn_p          (tree);
> +extern tree lambda_regenerating_args         (tree);
>  extern tree most_general_lambda                      (tree);
>  extern tree finish_omp_target                        (location_t, tree, 
> tree, bool);
>  extern void finish_omp_target_clauses                (location_t, tree, tree 
> *);
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 6e129da1d05..c919d2de68f 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -573,6 +573,9 @@ add_to_template_args (tree args, tree extra_args)
>    if (args == NULL_TREE || extra_args == error_mark_node)
>      return extra_args;
>  
> +  if (extra_args == NULL_TREE)
> +    return args;
> +

Whoops, this last-minute change to add_to_template_args turned out to
be a bad idea as some callers apparently rely on add_to_template_args
treating NULL_TREE extra_args as a depth 1 targ vector (whereas for
the calls in satisfy_declaration_constraints and do_auto_deduction we
want NULL_TREE extra_args to be treated as a depth 0 targ vector).

Please consider the below patch instead, which doesn't attempt to change
the behavior of add_to_template_args:

-- >8 --

Subject: [PATCH] c++: constrained auto in lambda using outer tparms [PR103706]

Here we're crashing during satisfaction of the lambda's placeholder type
constraints because the constraints depend on the template arguments
from the enclosing scope, which aren't part of the lambda's DECL_TI_ARGS.
So when inside a lambda, do_auto_deduction needs to add its
"regenerating" template arguments to the set of outer template
arguments, like we already do in satisfy_declaration_constraints.

        PR c++/103706

gcc/cp/ChangeLog:

        * constraint.cc (satisfy_declaration_constraints): Use
        lambda_regenerating_args instead.
        * cp-tree.h (lambda_regenerating_args): Declare.
        * pt.cc (lambda_regenerating_args): Define, split out from
        satisfy_declaration_constraints.
        (do_auto_deduction): Use lambda_regenerating_args to obtain the
        full set of outer template arguments for satisfaction.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/concepts-lambda18.C: New test.
---
 gcc/cp/constraint.cc                          |  9 ++---
 gcc/cp/cp-tree.h                              |  1 +
 gcc/cp/pt.cc                                  | 39 ++++++++++++++++---
 .../g++.dg/cpp2a/concepts-lambda18.C          | 14 +++++++
 4 files changed, 52 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index cc4df4216ef..c0ebe63a0a2 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3148,18 +3148,17 @@ satisfy_declaration_constraints (tree t, sat_info info)
        args = add_outermost_template_args (args, inh_ctor_targs);
     }
 
-  if (regenerated_lambda_fn_p (t))
+  if (LAMBDA_FUNCTION_P (t))
     {
       /* The TI_ARGS of a regenerated lambda contains only the innermost
         set of template arguments.  Augment this with the outer template
         arguments that were used to regenerate the lambda.  */
       gcc_assert (!args || TMPL_ARGS_DEPTH (args) == 1);
-      tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
-      tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda));
+      tree regen_args = lambda_regenerating_args (t);
       if (args)
-       args = add_to_template_args (outer_args, args);
+       args = add_to_template_args (regen_args, args);
       else
-       args = outer_args;
+       args = regen_args;
     }
 
   /* If any arguments depend on template parameters, we can't
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b9eb71fbc3a..7a7fe5ba599 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7715,6 +7715,7 @@ extern void finish_lambda_scope                   (void);
 extern tree start_lambda_function              (tree fn, tree lambda_expr);
 extern void finish_lambda_function             (tree body);
 extern bool regenerated_lambda_fn_p            (tree);
+extern tree lambda_regenerating_args           (tree);
 extern tree most_general_lambda                        (tree);
 extern tree finish_omp_target                  (location_t, tree, tree, bool);
 extern void finish_omp_target_clauses          (location_t, tree, tree *);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 6e129da1d05..46754c611e7 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -14442,6 +14442,21 @@ most_general_lambda (tree t)
   return t;
 }
 
+/* Return the set of template arguments used to regenerate the lambda T
+   from its most general lambda.  */
+
+tree
+lambda_regenerating_args (tree t)
+{
+  if (LAMBDA_FUNCTION_P (t))
+    t = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
+  gcc_assert (TREE_CODE (t) == LAMBDA_EXPR);
+  if (tree ti = LAMBDA_EXPR_REGEN_INFO (t))
+    return TI_ARGS (ti);
+  else
+    return NULL_TREE;
+}
+
 /* We're instantiating a variable from template function TCTX.  Return the
    corresponding current enclosing scope.  We can match them up using
    DECL_SOURCE_LOCATION because lambdas only ever have one source location, and
@@ -30100,12 +30115,24 @@ do_auto_deduction (tree type, tree init, tree 
auto_node,
            return type;
        }
 
-      if ((context == adc_return_type
-          || context == adc_variable_type
-          || context == adc_decomp_type)
-         && current_function_decl
-         && DECL_TEMPLATE_INFO (current_function_decl))
-       outer_targs = DECL_TI_ARGS (current_function_decl);
+      if (context == adc_return_type
+         || context == adc_variable_type
+         || context == adc_decomp_type)
+       if (tree fn = current_function_decl)
+         if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
+           {
+             outer_targs
+               = DECL_TEMPLATE_INFO (fn) ? DECL_TI_ARGS (fn) : NULL_TREE;
+             if (LAMBDA_FUNCTION_P (fn))
+               {
+                 /* As in satisfy_declaration_constraints.  */
+                 tree regen_args = lambda_regenerating_args (fn);
+                 if (outer_targs)
+                   outer_targs = add_to_template_args (regen_args, 
outer_targs);
+                 else
+                   outer_targs = regen_args;
+               }
+           }
 
       tree full_targs = add_to_template_args (outer_targs, targs);
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
new file mode 100644
index 00000000000..f1058daf317
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
@@ -0,0 +1,14 @@
+// PR c++/103706
+// { dg-do compile { target c++20 } }
+
+template<class T, class U> concept C = __is_same(U, int);
+
+template<class T> void f() {
+  []() -> C<T> auto {
+    C<T> auto x = T(); // { dg-error "constraints" }
+    return T(); // { dg-error "constraints" }
+  }();
+}
+
+template void f<int>(); // { dg-bogus "" }
+template void f<char>(); // { dg-message "required from here" }
-- 
2.35.0

Reply via email to