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