Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/16.2?

-- >8 --
This patch extends the 123700 fix to detect more cases:
a TYPENAME_TYPE with a LAMBDA_EXPR in it, and a DECLTYPE_TYPE
whose operand is a CALL_EXPR whose CALL_EXPR_FN is a LAMBDA_EXPR.

It still doesn't completely fix the problem: when the LAMBDA_EXPR
is more nested as e.g. in 110961:

using Typ = std::conditional_t<detail::ExtentsLike<Lst>, decltype([]<auto... 
Idx>(std::index_sequence<Idx...>){}(std::make_index_sequence<sizeof...(Ts)-1>{})),
 Tup>;

we won't find it since we don't and can't use walk_tree.  But this
patch is pretty simple and fixes (at least) 4 PRs.

        PR c++/125212
        PR c++/105667
        PR c++/121597
        PR c++/121287

gcc/cp/ChangeLog:

        * pt.cc (dependent_opaque_alias_p): Refactor.  Also return true
        when a DECLTYPE_TYPE has a LAMBDA_EXPR as its CALL_EXPR operand,
        and also when a TYPENAME_TYPE contains a LAMBDA_EXPR.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/lambda-targ26.C: New test.
        * g++.dg/cpp2a/lambda-targ27.C: New test.
        * g++.dg/cpp2a/lambda-targ28.C: New test.
        * g++.dg/cpp2a/lambda-targ29.C: New test.
        * g++.dg/cpp2a/lambda-targ30.C: New test.
        * g++.dg/cpp2a/lambda-targ31.C: New test.
        * g++.dg/cpp2a/lambda-targ32.C: New test.
---
 gcc/cp/pt.cc                               | 72 +++++++++++++++-------
 gcc/testsuite/g++.dg/cpp2a/lambda-targ26.C | 32 ++++++++++
 gcc/testsuite/g++.dg/cpp2a/lambda-targ27.C | 22 +++++++
 gcc/testsuite/g++.dg/cpp2a/lambda-targ28.C | 16 +++++
 gcc/testsuite/g++.dg/cpp2a/lambda-targ29.C | 12 ++++
 gcc/testsuite/g++.dg/cpp2a/lambda-targ30.C | 22 +++++++
 gcc/testsuite/g++.dg/cpp2a/lambda-targ31.C | 21 +++++++
 gcc/testsuite/g++.dg/cpp2a/lambda-targ32.C | 21 +++++++
 8 files changed, 197 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ26.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ27.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ28.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ29.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ30.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ31.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ32.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d19864774a3..0c033807aeb 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -6887,27 +6887,57 @@ dependent_opaque_alias_p (const_tree t)
       return false;
     };
 
-  return (TYPE_P (t)
-         && typedef_variant_p (t)
-         && (any_dependent_type_attributes_p (DECL_ATTRIBUTES
-                                              (TYPE_NAME (t)))
-             /* Treat a dependent decltype(lambda) alias as opaque so that we
-                don't prematurely strip it when used as a template argument.
-                Otherwise substitution into each occurrence of the (stripped)
-                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))))
-             /* Also treat an alias to A<lambda> as opaque so that it doesn't
-                "leak" into a deeper template context which would cause us to
-                over substitute into the lambda.  */
-             /* FIXME These lambda checks don't recognize deeply nested lambda
-                subexpressions, and we can't use walk_tree here because it's
-                slow.  Maybe a tree flag indicating typedef opaqueness?  */
-             || (TYPE_TEMPLATE_INFO (t)
-                 && PRIMARY_TEMPLATE_P (TYPE_TI_TEMPLATE (t))
-                 && any_lambda_targ_p (INNERMOST_TEMPLATE_ARGS
-                                       (TYPE_TI_ARGS (t))))));
+  auto tmpl_with_lambda_targ_p = [&] (const_tree t)
+    {
+      if (TYPE_TEMPLATE_INFO (t)
+         && PRIMARY_TEMPLATE_P (TYPE_TI_TEMPLATE (t))
+         && any_lambda_targ_p (INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (t))))
+       return true;
+      return false;
+    };
+
+  if (!(TYPE_P (t) && typedef_variant_p (t)))
+    return false;
+
+  if (any_dependent_type_attributes_p (DECL_ATTRIBUTES (TYPE_NAME (t))))
+    return true;
+
+  /* Treat a dependent decltype(lambda) alias as opaque so that we
+     don't prematurely strip it when used as a template argument.
+     Otherwise substitution into each occurrence of the (stripped)
+     alias would incorrectly yield a distinct lambda type.  */
+  if (TREE_CODE (t) == DECLTYPE_TYPE)
+    {
+      tree expr = DECLTYPE_TYPE_EXPR (t);
+      if (TREE_CODE (expr) == CALL_EXPR)
+       expr = CALL_EXPR_FN (expr);
+      if (expr
+         && TREE_CODE (expr) == LAMBDA_EXPR
+         && !typedef_variant_p (DECL_ORIGINAL_TYPE (TYPE_NAME (t))))
+       return true;
+    }
+
+  /* Also treat an alias to A<lambda> as opaque so that it doesn't
+     "leak" into a deeper template context which would cause us to
+     over substitute into the lambda.  */
+  /* FIXME These lambda checks don't recognize deeply nested lambda
+     subexpressions, and we can't use walk_tree here because it's
+     slow.  Maybe a tree flag indicating typedef opaqueness?  */
+  if (tmpl_with_lambda_targ_p (t))
+    return true;
+
+  if (TREE_CODE (t) == TYPENAME_TYPE)
+    {
+      tree ctx = TYPE_CONTEXT (t);
+      if (tmpl_with_lambda_targ_p (ctx))
+       return true;
+      tree fullname = TYPENAME_TYPE_FULLNAME (t);
+      if (TREE_CODE (fullname) == TEMPLATE_ID_EXPR
+         && any_lambda_targ_p (TREE_OPERAND (fullname, 1)))
+       return true;
+    }
+
+  return false;
 }
 
 /* Return the number of innermost template parameters in TMPL.  */
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ26.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ26.C
new file mode 100644
index 00000000000..ccea0a83b75
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ26.C
@@ -0,0 +1,32 @@
+// PR c++/125212
+// { dg-do compile { target c++20 } }
+
+template <auto dummyVal>
+struct MyStruct
+{
+    template<class Callable>
+    static constexpr auto Invoke(Callable callable)
+    {
+        return callable.template operator() <decltype(val)> ();
+    }
+
+    static constexpr int val = 0;
+
+    template <auto callable>
+    using Alias = MyStruct<dummyVal>;
+};
+
+template <typename T>
+constexpr auto IceFunction()
+{
+    using Alias1 = T::template Alias<[]<typename>() {}>;
+    constexpr auto lambda = []<typename>() {};
+    using Alias2 = T::template Alias<lambda>;
+    using Alias = Alias1;
+    return Alias::Invoke([]<typename>{ return MyStruct<Alias::val>{}; });
+}
+
+int main()
+{
+    IceFunction<MyStruct<1>>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ27.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ27.C
new file mode 100644
index 00000000000..29a2e874e5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ27.C
@@ -0,0 +1,22 @@
+// PR c++/105667
+// { dg-do compile { target c++20 } }
+
+template<auto f>
+struct h {typedef int type;};
+
+template<class Types>
+struct t{};
+
+template<int Ts>
+struct crash {
+    using Types = typename h<[]() {}>::type;
+    template<int tt>
+    static void f()
+    {
+        t<Types> b;
+    };
+};
+
+int main() {
+    crash<0>::f<1>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ28.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ28.C
new file mode 100644
index 00000000000..9a381e39834
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ28.C
@@ -0,0 +1,16 @@
+// PR c++/105667
+// { dg-do compile { target c++20 } }
+
+template<typename>
+struct get { };
+
+template<int>
+struct thing {
+    using T = decltype([](auto) { });
+
+    static constexpr auto value = [](auto) {
+        return get<T>();
+    }(0);
+};
+
+thing<0> X;
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ29.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ29.C
new file mode 100644
index 00000000000..8a781f1534f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ29.C
@@ -0,0 +1,12 @@
+// PR c++/105667
+// { dg-do compile { target c++20 } }
+
+template <auto A = []<class B>(B){}>
+struct C {
+  using D = void;
+};
+
+template <class...>
+using E = C<>::D;
+
+using F = E<>;
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ30.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ30.C
new file mode 100644
index 00000000000..d89d0cac3f0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ30.C
@@ -0,0 +1,22 @@
+// PR c++/105667
+// { dg-do compile { target c++20 } }
+
+struct class1
+{
+       virtual void a_function() = 0;
+};
+
+template<auto my_lambda = []<typename T>() {}>
+class class2 {};
+
+template<typename Touter>
+struct class3 : public class1 {
+       void a_function()
+       {
+               class2<> x;
+       }
+};
+
+struct class4 : public class3<class4> {
+       class4() {}
+};
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ31.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ31.C
new file mode 100644
index 00000000000..b61bec29be0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ31.C
@@ -0,0 +1,21 @@
+// PR c++/121597
+// { dg-do compile { target c++20 } }
+
+template<int, class> struct Tmpl {};
+template<typename T> struct Wrap {};
+
+template<typename = void>
+void foo()
+{
+  using Type = decltype([]<typename = void>{
+    return Tmpl<0, char>{};
+  }());
+
+  []<typename = void>{
+    using X = decltype([]<auto N, class T>(Tmpl<N, T>&&)
+      {}.template operator()<0>(Type{}));
+    return Wrap<X>{};
+  }();
+};
+
+template void foo<>();
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ32.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ32.C
new file mode 100644
index 00000000000..8a46faeefb2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ32.C
@@ -0,0 +1,21 @@
+// PR c++/121287
+// { dg-do compile { target c++20 } }
+
+template <typename _Tp, _Tp...> struct integer_sequence {};
+template <long... _Idx>
+using index_sequence = integer_sequence<unsigned long, _Idx...>;
+template <typename> struct array {};
+
+template <typename = void>
+auto
+f ()
+{
+  using Res = decltype([]<unsigned long Idx>(index_sequence<Idx>) { 
}(index_sequence<3>{}));
+  return []<long...>(index_sequence<>) { array<Res>{}; }({});
+}
+
+void
+g ()
+{
+  f ();
+}

base-commit: ccfcabc847eaeb6c1e0b0bec5a12c8af649c8de0
-- 
2.54.0

Reply via email to