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

-- >8 --

A typedef to a template-id with a lambda targ must not be stripped by
strip_typedefs because it can cause the lambda to leak into a deeper
template context, which breaks substituting into the lambda later.
For example in the below testcases zero<inner> gets stripped to
zero<Type<[](auto) {}>>, and we end up substituting through this
lambda targ twice (with args {double} then {int}) even though the lambda
is from a depth-one template context.

This patch extends the existing lambda typedef handling in
dependent_opaque_alias_p (added by r15-3694 for decltype(lambda))
to also recognize such template-id typedefs.  This should recognize
the vast majority of such constructs in practice (though the lambda
could also be a subexpression within a template argument which this
won't recognize).

        PR c++/123700

gcc/cp/ChangeLog:

        * pt.cc (dependent_opaque_alias_p): Return true for a
        template-id typedef with a lambda targ.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/lambda-targ24.C: New test.
        * g++.dg/cpp2a/lambda-targ24a.C: New test.
---
 gcc/cp/pt.cc                                | 14 +++++++++++++-
 gcc/testsuite/g++.dg/cpp2a/lambda-targ24.C  | 12 ++++++++++++
 gcc/testsuite/g++.dg/cpp2a/lambda-targ24a.C | 14 ++++++++++++++
 3 files changed, 39 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ24.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ24a.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ddf492b34354..60afc6b99266 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -6872,6 +6872,14 @@ dependent_alias_template_spec_p (const_tree t, bool 
transparent_typedefs)
 bool
 dependent_opaque_alias_p (const_tree t)
 {
+  auto any_lambda_targ_p = [] (tree args)
+    {
+      for (tree arg : tree_vec_range (args))
+       if (TREE_CODE (arg) == LAMBDA_EXPR)
+         return true;
+      return false;
+    };
+
   return (TYPE_P (t)
          && typedef_variant_p (t)
          && (any_dependent_type_attributes_p (DECL_ATTRIBUTES
@@ -6882,7 +6890,11 @@ dependent_opaque_alias_p (const_tree t)
                 alias would incorrectly yield a distinct lambda type.  */
              || (TREE_CODE (t) == DECLTYPE_TYPE
                  && TREE_CODE (DECLTYPE_TYPE_EXPR (t)) == LAMBDA_EXPR
-                 && !typedef_variant_p (DECL_ORIGINAL_TYPE (TYPE_NAME (t))))));
+                 && !typedef_variant_p (DECL_ORIGINAL_TYPE (TYPE_NAME (t))))
+             || (TYPE_TEMPLATE_INFO (t)
+                 && PRIMARY_TEMPLATE_P (TYPE_TI_TEMPLATE (t))
+                 && any_lambda_targ_p (INNERMOST_TEMPLATE_ARGS
+                                       (TYPE_TI_ARGS (t))))));
 }
 
 /* Return the number of innermost template parameters in TMPL.  */
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ24.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ24.C
new file mode 100644
index 000000000000..6b071ca2ada9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ24.C
@@ -0,0 +1,12 @@
+// PR c++/123700
+// { dg-do compile { target c++20 } }
+
+template<class> constexpr int zero = 0;
+template<auto> struct Type;
+
+int outer(auto) {
+  using inner = Type<[](auto) {}>;
+  return [](auto) { return zero<inner>; }(0);
+}
+
+int main() { outer(0.0); }
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ24a.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ24a.C
new file mode 100644
index 000000000000..83279356d4ec
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ24a.C
@@ -0,0 +1,14 @@
+// PR c++/123700
+// { dg-do compile { target c++20 } }
+// A version of lambda-targ24.C where zero is a class instead of
+// variable template
+
+template<class> struct zero { };
+template<auto> struct Type;
+
+auto outer(auto) {
+  using inner = Type<[](auto) {}>;
+  return [](auto) { return zero<inner>{}; }(0);
+}
+
+int main() { outer(0.0); }
-- 
2.53.0.582.gca1db8a0f7

Reply via email to